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.
Related
I have my application.properties:
test.md5.params=something1,something4
In my java class I am getting this particular value :
and need to create same strings as present in the property file, such as
public String calculate(RequestClass request)
{
List<String> params= //I am getting the values from application.prop
**(above part id done)**
My Question is below ::
now in my params list I have [something1,something4]
so I need to concatenate both the String values like below:
String finalString=request.getSomething1()+request.getSomething4();
return finalString;
}
My Question is how to do this dynamically and in my properties file I might receive "n" of something values.
Note : I need to make the code such that my class remains constant, if in future I am adding 10 more values in properties files, my final string should be returning like
String finalString=request.getSomething1()+request.getSomething4()+....all the values.;
Through reflection this is possible, below is one implementation.
public String calculate(RequestClass request) throws InvocationTargetException, IllegalAccessException {
List<String> params = Arrays.asList("something1", "something4");
// Do your logic to get the method Names from params, below is an simple example - paramsUpdated
List<String> paramsUpdated = Arrays.asList("getSomething1", "getSomething4");
// Reflection to get the methods of request class
Method[] methods = request.getClass().getMethods();
StringBuilder sb = new StringBuilder();
for (String param : paramsUpdated) {
for (Method method : methods) {
if (param.equals(method.getName())) {
sb.append(method.invoke(request));
}
}
}
return sb.toString();
}
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.
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....
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;
}
I have Spring MVC URL's define in Interfaces (just to hold the Constants) like:
String URL_X = "/my-url/{id:[0-9]*}";
String URL_Y = "/my-url/{id:[0-9]*}/blah-blah";
I have a method for my tests that replace the variables in an URL:
private static final String REGEX_PARAMETROS_DA_URL = "(\\{[^\\}]*\\})";
protected String replaceParametersOnURL(String urlSpring, String... params) {
String urlAtual = urlSpring;
for (String parametro : params) {
urlAtual = urlAtual.replaceFirst(REGEX_PARAMETROS_DA_URL, parametro);
}
return urlAtual;
}
I was using this regex: (\{[^\}]*\}) to match the variables and replace it.
But now i have some URL's that have {} on it and i can't find a properly regex to replace the variable with my value.
Is there any method on Spring that replaces the PathVariable value or can anyone help me with this regex?
Given this URL for instance:
/pessoajuridica/{cnpj:[0-9]{14}}-{slug:[a-zA-Z0-9-]+}/sancoes/resumo
The matches must be: {cnpj:[0-9]{14}}and {slug:[a-zA-Z0-9-]+}
Thanks #Matthew. I haven't noticed that the spring test itself can do this!
All i need to do is:
mockMvc.perform(get("/pessoajuridica/{cnpj:[0-9]{14}}-{slug:[a-zA-Z0-9-]+}/sancoes/resumo", var1, var2)) ...