Comparing URLs with parameters in Java - java

These two urls should be the same:
http://localhost?asdf=1&qwer=2
http://localhost?qwer=2&asdf=1
But using 'equals()' from the URL class, I get that they're different. How can I compare them?
EDIT: Some background on this question
I'm creating a Selenium test for some url mapping. I have old url, url it should get mapped to and the actual url. I need to compare the should-be url to the actual url. List of urls is created by client. Urls with the same parameters and values are considered valid if the list of parameters is the same, and they all have the right values (order of those parameters is irrelevant)

So if I get it right, you want to compare two URL's, regardless of the order of the query part.
There does not seem to be a method for this in the URL class, so you'll have to write your own.
Also, URL is final, you cannot override URL.equals(Object).
Your method could start with calling sameFile().
If that evaluates to true, you then call getQuery(), and split it into it's components - probably with String.split("\&"). From there on, you evaluate if the parameters are the same.
Also, don't forget to check if the "#fragment" is equal, if that is important to your application.

I don't think you're going to like it, but you could do something like
URL url = new URL("http://localhost?asdf=1&qwer=2");
URL url2 = new URL("http://localhost?qwer=2&asdf=1");
System.out.println(isEqual(url, url2));
public static boolean isEqual(URL url1, URL url2) {
boolean isEqual = url1.getAuthority().equals(url2.getAuthority()) &&
url1.getPort() == url2.getPort() &&
url1.getHost().equals(url2.getHost()) &&
url1.getProtocol().equals(url2.getProtocol());
if (isEqual) {
String query1 = url1.getQuery();
String query2 = url2.getQuery();
if (query1 != null && query2 != null) {
if (query1.length() == query2.length()) {
List<String> list1 = getParameters(query1);
List<String> list2 = getParameters(query2);
for (int index = 0; index < list1.size(); index++) {
String value1 = list1.get(index);
String value2 = list2.get(index);
if (!value1.equals(value2)) {
isEqual = false;
break;
}
}
} else {
isEqual = false;
}
} else {
isEqual = false;
}
}
return isEqual;
}
protected static List<String> getParameters(String value) {
List<String> parameters = new ArrayList<String>(25);
String[] values = value.split("&");
for (String par : values) {
if (!par.contains("=")) {
par += "=null";
}
parameters.add(par);
}
Collections.sort(parameters);
return parameters;
}

URL/URI equals method is broken. At least it doesn't provide results as you would expect.
There are a lot of weird things with it. You might be interested to read
Mr. Gosling – why did you make URL equals suck?!?
or maybe
How to compare two URLs in java?
So, don't expect it would be easy.
You can create your custom comparator for your particular case but in general you might have to parse the url string.
Hope this helps

You can accomplish this with functionality available in the String class.
This approach splits the URLs into two parts, the one before the "?" and the one after (it's fine if no "?" or parameters are present). If the URLs before the "?" are equivalent, the two are "equal" for our purposes.
public boolean urlsMatchWithoutQueryParameters(String firstUrl, secondUrl) {
// Get the portion of the URLs before the "?", and before all parameters.
String firstUrlWithoutParameters = firstUrl.split("\\?", 2)[0];
String secondUrlWithoutParameters = secondUrl.split("\\?", 2)[0];
return firstUrlWithoutParameters.equals(secondUrlWithoutParameters);
}
The code is a little crowded, so you could do something pull out the String logic into a helper like so:
public boolean urlsMatchWithoutQueryParameters(String firstUrl, secondUrl) {
return getUrlWithoutParameters(firstUrl).equals(getUrlWithoutParameters(secondUrl));
}
public String getUrlWithoutParameters(String url) {
// Get the portion of the URL before the "?", and before all parameters.
return url.split("\\?", 2)[0];
}
Note: This ignores URL anchors (e.g., #photos in the url www.example.com/profiles/user123#friends).
To for anchors, simply replace "\\?" with "#" in split("\\?", 2).

I like this question so I wrote this little demo. (Sorry, I used the StringUtils class for the substrings)
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.StringUtils;
public class URLDemo
{
/**
* #param args
* #throws MalformedURLException
*/
public static void main(String[] args)
throws MalformedURLException
{
String url1 = "http://localhost?asdf=1&qwer=2";
String url2 = "http://localhost?qwer=2&asdf=1";
URL url11 = new URL(StringUtils.substringBefore(url1, "?"));
URL url22 = new URL(StringUtils.substringBefore(url2, "?"));
if (url11.equals(url22))
{
// url are equal but still need to check the parameters
List<String> params1 = Arrays.asList(StringUtils.split(StringUtils.substringAfter(url1, "?"), "&"));
List<String> params2 = Arrays.asList(StringUtils.split(StringUtils.substringAfter(url2, "?"), "&"));
// need to check both ways
if (params1.containsAll(params2) && params2.containsAll(params1))
{
System.out.println("URLs are the same");
}
else
{
System.out.println("URLs are different");
}
}
}
}

Well these two url are infact different
http://localhost?asdf=1&qwer=2
http://localhost?qwer=2&asdf=1
//////// EDITED PART //////////
Try this....
- Use openStream() on both the url.
- Save both of them as 2 String Objects, or StringBuilder instead.
- Now compare both of them using equals().
- This will solve the problem, i think so....

Related

Resolve environment variables of property file Java ResourceBundle

Our application is using java8 and spring. We are working to moving to kubernetes. For that reason, I want to use environment variables in the properties file like as follow and declare the -
conf.dir.path = ${APPLICATION_CONF_PATH}
database.name = ${APPLICATION_DB_SCHEMA}
save.file.path = ${COMMON_SAVE_PATH}${APPLICATION_SAVE_PATH}
# And many more keys
But right now the values are not resolved/expanded by environment variable.
Application initialization of property is as below -
public enum ApplicationResource {
CONF_DIR_PATH("conf.dir.path"),
DB_NAME("database.name")
FILE_SAVE_PATH("save.file.path"),
// And many more keys
private final String value;
ApplicationResource(String value) {
this.value = value;
}
private static final String BUNDLE_NAME = "ApplicationResource";
private static Properties props;
static {
try {
Properties defaults = new Properties();
initEnvironment(defaults, BUNDLE_NAME);
props = new Properties(defaults);
} catch (Throwable t) {
t.printStackTrace();
}
}
private static void initEnvironment(Properties props, String bundleName) throws Throwable {
ResourceBundle rb = ResourceBundle.getBundle(bundleName);
Enumeration<?> enu = rb.getKeys();
String key = null;
String value = null;
while (enu.hasMoreElements()) {
key = (String) enu.nextElement();
value = rb.getString(key);
props.setProperty(key, value);
}
}
public String getString() {
return props.getProperty(value);
}
public int getInt() throws NumberFormatException {
String str = getString();
if (str == null || str.length() == 0) {
return 0;
} else {
return Integer.parseInt(str);
}
}
}
getString is used extensively. Right now when getString is called, it returns the literal string from the properties file. Is there any way to properly resolve environment variables without impacting the codebase?
Edit: By [without impacting the codebase], I meant only changing/editing code in the above enum/class file and the change being transparent in other areas.
The simplest variant based on the Regex engine would be:
private static final Pattern VARIABLE = Pattern.compile("\\$\\{(.*?)\\}");
public String getString() {
return VARIABLE.matcher(props.getProperty(value))
.replaceAll(mr -> Matcher.quoteReplacement(System.getenv(mr.group(1))));
}
This replaces all occurrences of ${VAR} with the result of looking up System.getenv("VAR"). If the string contains no variable references, the original string is returned. It does, however, not handle absent variables. If you want to handle them (in a different way than failing with a runtime exception), you have to add the policy to the function.
E.g. the following code keeps variable references in their original form if the variable has not been found:
public String getString() {
return VARIABLE.matcher(props.getProperty(value))
.replaceAll(mr -> {
String envVal = System.getenv(mr.group(1));
return Matcher.quoteReplacement(envVal != null? envVal: mr.group());
});
}
replaceAll(Function<MatchResult, String>) requires Java 9 or newer. For previous versions, you’d have to implement such a replacement loop yourself. E.g.
public String getString() {
String string = props.getProperty(value);
Matcher m = VARIABLE.matcher(string);
if(!m.find()) return string;
StringBuilder sb = new StringBuilder();
int last = 0;
do {
String replacement = System.getenv(m.group(1));
if(replacement != null) {
sb.append(string, last, m.start()).append(replacement);
last = m.end();
}
} while(m.find());
return sb.append(string, last, string.length()).toString();
}
This variant does not use appendReplacement/appendTail which is normally used to build such loops, for two reasons.
First, it provides more control over how the replacement is inserted, i.e. by inserting it literally via append(replacement) we don’t need Matcher.quoteReplacement(…).
Second, we can use StringBuilder instead of StringBuffer which might also be more efficient. The Java 9 solution uses StringBuilder under the hood, as support for it has been added to appendReplacement/appendTail in this version too. But for previous versions, StringBuilder can only be used when implementing the logic manually.
Note that unlike the replaceAll variant, the case of absent variables can be handled simpler and more efficient with a manual replacement loop, as we can simply skip them.
You said you don’t want to change the initialization code, but I still recommend bringing it into a more idiomatic form, i.e.
private static void initEnvironment(Properties props, String bundleName) {
ResourceBundle rb = ResourceBundle.getBundle(bundleName);
for(Enumeration<String> enu = rb.getKeys(); enu.hasMoreElements(); ) {
String key = enu.nextElement();
String value = rb.getString(key);
props.setProperty(key, value);
}
}
In the end, it’s still doing the same. But iteration loops should be using for, to keep initialization expression, loop condition and fetching the next element as close as possible. Further, there is no reason to use Enumeration<?> with a type cast when you can use Enumeration<String> in the first place. And don’t declare variables outside the necessary scope. And there’s no reason to pre-initialize them with null.
Spring support environment variable or system variable or application.property file
if you able to use kubernates configmap its better choice.
How to set environment variable dynamically in spring test

How to convert a String which looks like an Array into an actual Object Array?

Since
public static String requestMethodExecution(String objectName, String className, String methodName, Object...
params) {
return String.format("%s,%s,%s,%s", objectName, className, methodName, Arrays.toString(params));
}
returns a String, and if you would, for example, call the method like this:
requestMethodExecution("foo","bar","fooBar",2.0,3.0,"Hello");
You'd get a String like this: foo,bar,fooBar,[2.0,3.0,Hello]
I would love to iterate over that Array, but I can't since it is a String.
Reason behind this is this method: (I just started with reflection, so I do not know how else to do it)
public static Class[] getParameterType(String ...params) throws ClassNotFoundException {
Class[] paramTypes = new Class[params.length];
for(int i=0; i<params.length;i++){
Class paramClass = Class.forName(params[i]);
if (paramClass == Double.class) {
paramTypes[i] = (double.class);
} else if (paramClass == Integer.class) {
paramTypes[i] = (int.class);
} else {
paramTypes[i] = paramClass;
}
}
return paramTypes;
}
So far I have only come up with a very dirty way:
public static String[] getParams(String message){
int indexOfParamStart = message.indexOf("[");
int indexOfParamEnd = message.indexOf("]")+1;
String[] splitMessage = message.substring(indexOfParamStart, indexOfParamEnd).replaceAll("\\[", "")
.replaceAll("]", "").replaceAll(" ","").split(",");
return splitMessage;
}
Edit: Thanks for looking into this! Since some of you are asking what I am trying to achieve, here is a bit more explanation:
I want to implement a simple request/reply protocol which allows remote method invocation (and I do not want to use java RMI...)
So I listen for requests whose structure can be seen at the requestMethodExecution example.
There I have all the relevant information to call the Method upon my class, so to invoke the method I need it's arguments (and their value) and I do not know how to access them from the given String.
The others are easy with Class c = Class.forName(className); etc..
Edit#2:
My question is not about a simple regex, so why close it? The title already states a different subject, I am getting a bit salty here...
See this this question for using RegEx to extract the array body from the outer string (by the square brackets), and then you can simply use String.split(",") to split the array body into array items.

Verifying the values of URL in Junit?

I do have to write a unit test case for a method which returns a URL,
I've to verify all the values of the parameters in the URL, is there any API or better way to work around this..
Any suggestions would be appreciated.
Java Method:
class Sample{
public String returnURL(){
return "http://localhost:9080/sample?a=12-a&b=param2&c=param3&d=param_4&e=param5"
}
}
Junit:
#Test
public void returnURLTest(){
String url = new Sample().returnURL()
// Parse the url
assert url['a'] == "param1"
assert url['b'] == "param2"
}
Thanks
If you use AssertJ, you can create the URI (or URL) object and use the assertions on it, as shown in those examples: https://github.com/joel-costigliola/assertj-examples/blob/master/assertions-examples/src/test/java/org/assertj/examples/UriAssertionsExamples.java
assertThat(new URI("http://www.helloworld.org/index.html?happy=very")).hasParameter("happy", "very");
You'll just have to parse the URL and compare the individual pieces you pull out.
Something like:
int indexOfNextParameter = url.indexOf("=");
List<String> parameters = new ArrayList<>();
while(youAreParsingTheURL){
int indexOfParameter = url.indexOf("=", indexOfNextParameter);
String parameter = url.substring("=", indexOfParameter);
parameters.add(parameter);
}
Then just go through that parameters List and validate each item.

Untangling Inherited Methods

Okay, so this is my first time implementing classes, and everything's going wrong. I'm implimenting a different class, PhraseGenerator, and the method inherited which I wish to define here is getPhrase(). It needs to return theArcha. Instead of working within it, I chose to wrap its braces around my work afterwards, and now, no matter where I put it, a different error arises. Before dealing with any of these, I want to make sure I'm putting it in the right place. To my understanding, it would go within public....FromFile implements PhraseGenerator. Any thoughts on where it should go?
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PhraseGeneratorFromFile implements PhraseGenerator {
private ParserHelperImpl parserHelper;
public String getPhrase() {
public PhraseGeneratorFromFile(String filename) {
// read file
StringBuilder fileContent = new StringBuilder();
BufferedReader br = new BufferedReader(new FileReader(filename));
try {
String line = br.readLine();
while (line != null) {
fileContent.append(line);
fileContent.append('\n');
line = br.readLine();
}
String everything = fileContent.toString();
} finally {
br.close();
}
parserHelper = new ParserHelperImpl();
List<String> phraseCollection = parserHelper.getPhrases(fileContent,"phrases:");
String archetype = parserHelper.getRandomElement(phraseCollection);
boolean flagga = true;
while(flagga = true){
Pattern ptrn = Pattern.compile("#[^#]+#");
Matcher m = ptrn.matcher(archetype);
String fromMatcher = m.group(0);
String col = ":";
String token = fromMatcher+col;
List<String> pCol = parserHelper.getPhrases(fileContent, token);
String repl = parserHelper.getRandomElement(pCol);
String hash = "#";
String tk2 = hash + token + hash;
archetype = parserHelper.replace(archetype, tk2, repl);
flagga = m.find();
}
String theArcha = archetype;
return theArcha;
}
}
}
A good practice while posting a question here is :
(1). Explain in brief what you expect off your code to do.
(2). If you are experiencing certain errors, copy them here so that it can be understood what is going wrong in your code.
I seriously did not understood what you were trying to achieve but I see a missing closing bracket in
public String getPhrase()
It should be :
public String getPhrase()
{
//logic here
}
Hope this helps
Yes, it is in the right place but you are missing the closing }, which should come directly after the {. You can't put a method inside another method like that.
Because you want to return theArcha, you should instead make it what we call "an instance variable" - you may not have heard of this? If not, look it up.
Your interface is probably like this
interface PhraseGenerator {
String getPhrase();
}
Then the implementing class you wrote will take the form
class PhraseGeneratorImpl implements PhraseGenerator {
private ParserHelperImpl parserHelper;
#Override //Used for an overridden or implemented method
public String getPhrase() {
//Put all the code you want to implement here..
//If you want to make use of a helper Class the clean way is to use an instance of it(You tried it with Helper)
//If you want to make use of a utility method within the same class,
//say reading something from the file system define a private method below this method
String filePhrase = phraseGeneratorFromFile();
//Now use the filePhrase do do other stuff
}
//
private String phraseGeneratorFromFile(){
//Do all the stuff and return phrase/string so declare return type. you havent done it in the code above
}
}

Avoiding multiple If statements in Java

I've coded a method something like this. But I guess this should undergo refactoring.
Can any one suggest the best approach to avoid using this multiple if statements?
private String getMimeType(String fileName){
if(fileName == null) {
return "";
}
if(fileName.endsWith(".pdf")) {
return "application/pdf";
}
if(fileName.endsWith(".doc")) {
return "application/msword";
}
if(fileName.endsWith(".xls")) {
return "application/vnd.ms-excel";
}
if(fileName.endsWith(".xlw")) {
return "application/vnd.ms-excel";
}
if(fileName.endsWith(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if(fileName.endsWith(".mdb")) {
return "application/x-msaccess";
}
if(fileName.endsWith(".rtf")) {
return "application/rtf";
}
if(fileName.endsWith(".txt")) {
return "txt/plain";
}
if(fileName.endsWith(".htm") || fileName.endsWith(".html")) {
return "txt/html";
}
return "txt/plain";
}
I cannot use switch-case here as my 'condition' is a java.lang.String.
You can use a Map to hold your solutions:
Map<String,String> extensionToMimeType = new HashMap<String,String>();
extensionToMimeType.put("pdf", "application/pdf");
extensionToMimeType.put("doc", "application/msword");
// and the rest
int lastDot = fileName.lastIndexOf(".");
String mimeType;
if (lastDot == -1) {
mimeType = NO_EXTENSION_MIME_TYPE;
} else {
String extension = fileName.substring(lastDot+1);
mimeType = extensionToMimeType.getOrDefault(extension,
UNKNOWN_EXTENSION_MIME_TYPE);
}
For this code to work you'll need to have defined NO_EXTENSION_MIME_TYPE and UNKNOWN_EXTENSION_MIME_TYPE as in your class, somewhat like this:
private static final String NO_EXTENSION_MIME_TYPE = "application/octet-stream";
private static final String UNKNOWN_EXTENSION_MIME_TYPE = "text/plain";
Using a HashMap perhaps?
This way you could do myMap.get(mystr);
Command pattern is the way to go. Here is one example using java 8:
1. Define the interface:
public interface ExtensionHandler {
boolean isMatched(String fileName);
String handle(String fileName);
}
2. Implement the interface with each of the extension:
public class PdfHandler implements ExtensionHandler {
#Override
public boolean isMatched(String fileName) {
return fileName.endsWith(".pdf");
}
#Override
public String handle(String fileName) {
return "application/pdf";
}
}
and
public class TxtHandler implements ExtensionHandler {
#Override public boolean isMatched(String fileName) {
return fileName.endsWith(".txt");
}
#Override public String handle(String fileName) {
return "txt/plain";
}
}
and so on .....
3. Define the Client:
public class MimeTypeGetter {
private List<ExtensionHandler> extensionHandlers;
private ExtensionHandler plainTextHandler;
public MimeTypeGetter() {
extensionHandlers = new ArrayList<>();
extensionHandlers.add(new PdfHandler());
extensionHandlers.add(new DocHandler());
extensionHandlers.add(new XlsHandler());
// and so on
plainTextHandler = new PlainTextHandler();
extensionHandlers.add(plainTextHandler);
}
public String getMimeType(String fileExtension) {
return extensionHandlers.stream()
.filter(handler -> handler.isMatched(fileExtension))
.findFirst()
.orElse(plainTextHandler)
.handle(fileExtension);
}
}
4. And this is the sample result:
public static void main(String[] args) {
MimeTypeGetter mimeTypeGetter = new MimeTypeGetter();
System.out.println(mimeTypeGetter.getMimeType("test.pdf")); // application/pdf
System.out.println(mimeTypeGetter.getMimeType("hello.txt")); // txt/plain
System.out.println(mimeTypeGetter.getMimeType("my presentation.ppt")); // "application/vnd.ms-powerpoint"
}
Personally I don't have problems with the if statements. The code is readable, it took just milliseconds to understand what you're doing. It's a private method anyway and if the list of mime types is static then there's no urgent need to move the mapping to a properties file and use a lookup table (map). Map would reduce lines of code, but to understand the code, then you're forced to read the code and the implementation of the mapping - either a static initializer or an external file.
You could change the code a bit and use an enum:
private enum FileExtension { NONE, DEFAULT, PDF, DOC, XLS /* ... */ }
private String getMimeType(String fileName){
String mimeType = null;
FileExtension fileNameExtension = getFileNameExtension(fileName);
switch(fileNameExtension) {
case NONE:
return "";
case PDF:
return "application/pdf";
// ...
case DEFAULT:
return "txt/plain";
}
throw new RuntimeException("Unhandled FileExtension detected");
}
The getFileNameExtension(String fileName) method will just return the fitting enum value for the fileName, FileExtension.NONE if fileName is empty (or null?) and FileExtension.DEFAULT if the file extension is not mapped to a mime type.
what about using a MIME detection library instead?
mime-util
mime4j
JMimeMagic library - Free. Uses file extension and magic headers to determine MIME type.
mime-util - Free. Uses file extension and magic headers to determine MIME type.
DROID (Digital Record Object Identification) - Free. Uses batch automation to detect MIME types.
Aperture Framework - Free. A framework for crawling external sources to identify MIME types.
(feel free to add more, there so many libraries..)
I consider your approach to be the best overall. This comes after having tested with a number of different approaches myself.
I see a number of huge benefits in your current approach, namely:
Easily readable and understandable by anyone (in my experience, medium-level programmers often underestimate this and usually prefer going with fancy-patterns which, in the end are not readable at all for the vast majority of programmers who do not know that specific pattern)
All the information is in one single place. As Andreas_D pointed out, hunting around files or classes is not a good option for someone that needs to fix a bug while you are on holiday!
Easily maintainable: I could "F3" (if you are Eclipse-ing) on the method and add a new content type in seconds without any worries of introducing bugs!
I can suggest a few things anyway:
This method is very general purpose:
Why should it be private?! This is a
public method of some utility/helper class!
Moreover it should be a static method!! You don't need anything
from the Object itself to perform
your job!
You could use indenting to make
things prettier and compact. I know
that indenting is some kind of
religion for the most of us, but I
think it should not be a strict rule;
it should be properly used to make
our code more readable and compact.
If this would be a config file you
would probably have something like:
pdf=application/pdf
doc=application/msword
You could have a very similar result with:
public static String getMimeType(String fileName){
if(fileName == null) return "";
if(fileName.endsWith(".pdf")) return "application/pdf";
if(fileName.endsWith(".doc")) return "application/msword";
if(fileName.endsWith(".xls")) return "application/vnd.ms-excel";
return "txt/plain";
}
This is also what a lot of the Map based implementations look like.
There is no way to evade that in general. In your case - if there is a set of allowed extensions - you could create an Enum, convert the extension to the Enum type via valueOf(), and then you can switch over your enum.
Easiest and shortest way for this particular problem would be using the builtin Java SE or EE methods.
Either in "plain vanilla" client application (which derives this information from the underlying platform):
String mimeType = URLConnection.guessContentTypeFromName(filename);
Or in a JSP/Servlet web application (which derives this information from the web.xml files):
String mimeType = getServletContext().getMimeType(filename);
I would do this by putting the associations in a map, and then using the map for lookup:
Map<String, String> map = new HashMap<String, String>();
map.put(".pdf", "application/pdf");
map.put(".doc", "application/msword");
// ... etc.
// For lookup:
private String getMimeType(String fileName) {
if (fileName == null || fileName.length() < 4) {
return null;
}
return map.get(fileName.substring(fileName.length() - 4));
}
Note that using the switch statements on strings is one of the proposed new features for the next version of Java; see this page for more details and an example of how that would look in Java 7:
switch (fileName.substring(fileName.length() - 4)) {
case ".pdf": return "application/pdf";
case ".doc": return "application/msword";
// ...
default: return null;
(edit: My solution assumes the file extension is always 3 letters; you'd have to change it slightly if it can be longer or shorter).
You can always use a Groovy class here as it allows for switch-case on Strings :)
Create an enum called MimeType with 2 String variables: extension and type. Create an appropriate constructor and pass in the ".xxx" and the "application/xxx" values. Create a method to do the lookup. You can use enums in switch.
Just to mention it: A direct equivalent to your code would not be using a map for direct lookup (since that would require each extension to have exactly 3 characters) but a for loop:
...
Map<String, String> extmap = GetExtensionMap();
for (Map.Entry<String,String> entry: extmap.entrySet())
if (fileName.endsWith(entry.getKey))
return entry.getValue();
...
This solution works with extensions of any length but is less performant than the hash lookup of course (and slightly less performant than the original solution)
The Algorithmic-Design-Guy solution
A more performant way would be to implement a tree structure starting with the last character of the extension and storing the appropriate MIME types at the respective nodes.
You could then walk down the tree starting with the last character of the file name. But this is probably an overkill ...
How about mapping the extensions to MIME types, then using a loop? Something like:
Map<String,String> suffixMappings = new HashMap<String,String>();
suffixMappings.put(".pdf", "application/pdf");
...
private String getMimeType(String fileName){
if (fileName == null) {
return "";
}
String suffix = fileName.substring(fileName.lastIndexOf('.'));
// If fileName might not have extension, check for that above!
String mimeType = suffixMappings.get(suffix);
return mimeType == null ? "text/plain" : mimeType;
}

Categories