I have a url say /prefix/part1/part2/.../partN/suffix and in a controller i want to map anything between /prefix/ and /suffix to one variable.
Approaches tried
#RequestMapping(value = "/prefix/{store:[\s\S]*}/suffix",
method = RequestMethod.GET)
Also, tried regex : (.*), The interesting part is i don't know what N is. So, cant explicitly specify number of slashes possible.
I have an open JIRA issue requesting this ability, but the Spring core team apparently doesn't think that it's useful and is not interested in supporting it. You might make a note there.
In the meantime, the only option is to get the entire string from the request and parse it yourself.
Related
Background
We are currently implementing an application using hexagonal architecture. Our REST API DTOs are mapped to our entities via MapStruct. This works fine. (Though, it would be much nicer if MapStruct would have support for hierarchical structures.)
Problem
However, we are facing a problem which is best described by the following example:
Consider you have an entity Person that stores the date of birth. Now, this
entity has a method which might be called int calculateAge().
The REST API's PersonDto will get an attribute int age.
Now, we want MapStruct to generate this mapping for us. Our approach was to try to configure #Mapping(target = "age", ...) to use the int calculateAge() method as source, but we did not succeed.
Believing this might be a straightforward application of MapStruct, we were quite disappointed to not come up with a clean solution after searching on this topic for hours.
Solutions
We found two solution approaches that work, but are (in our opinion) not really maintainable:
Use #Mapping(expression = "java(...)")
Use #AfterMapping to post process the constructed DTO and implement the required mappings in the annotated method
Question
Is there a cleaner way to achieve our goal, something which might look like this #Mapping(sourceMethod = "calculateAge", target = "age)?
Is there a cleaner way to achieve our goal, something which might look like this...
No, there isn't as of the MapStruct latest stable version (1.4.1.Final) of time of writing this answer. You have basically two choices which heavily depends what exactly and how you want to map the fields. I describe shortly in what case each solution is suitable for:
The first solution using expression introduces the problem the methods are hardcoded in the annotation. I prefer this solution only in the case of simple format conversions or calculations without calling a custom method (only from the existing Java API). Anyway, even with your proposed solution it would be still hardcoded. The syntax is the only thing that changes. There is effectively no difference in terms of maintainability:
#Mapping(target = "age", expression = "java(...)") // current API
#Mapping(sourceMethod = "calculateAge", target = "age") // hypothetical
Feel free to request for such feature. This solution in any case also requires imports within the mapper (#Mapper(imports = Another.class)) as well as the "hypothetical" one.
The annotation #AfterMapping is useful in case of more complex transformations and calculations. It's not as clean as a single annotation call and in fact you still write the mapping manually, however, it brings more control over the called methods which the IDE highlights before the compilation (at least you don't need an additional IDE-specific plugin). I'd go for this solution in case I need to call my custom methods and logics.
From what I've seen, Mapstruct relies on standard getters and setters. If you want to use a specific method then Mapstruct does work with #qualifiers, but I don't think the method can be in the entity. From my experience the best solution is to use #AfterMapping, as you mentioned.
I have an action I want to apply to multiple routes in my Play application. These routes perform actions on a product, and a product can have various versions. I want my API to work such that the user can specify a version explicitly (via a query parameter), and if they do not specify one we will look up the latest version from the DB for them and operate on that one. So this action needs to be able to look up the latest version of a product, but we need to know which product is being asked for. In the route's controller, this is obvious. Play calls the route controller with route parameters as arguments:
#RequireProductVersion()
public CompletionStage<Result> getProduct(String productId) {
...
}
But in our action, we only have this Play internal Context object to work with. My action looks something like this:
public class RequireProductVersion extends Action<RequireProductVersion> {
#Override
public CompletionStage<Result> call(Http.Context ctx) {
final String version = ctx.request().getQueryString("version");
// if an explicit "version" parameter was specified, verify it and use it
if (version != null) {
...
} else {
// look up the latest version for this product
final String productId = ctx.request.????getParameter("productId");
return lookupLatestProductVersion(productId).thenCompose( ... );
}
}
}
Although I have some additional validity checking in that action. Sometimes I return an error from there immediately. So we could replace this action composition solution by adding the query string parameter "version" to all the routes and adding a half dozen lines of code in each of my route controllers:
#RequireProductVersion()
public CompletionStage<Result> getProduct(String productId, #Nullable String productVersion) {
final int productVersion;
try {
productVersion = Utils.getProductVersion(productId, productVersion);
} catch (ProductVersionException e) {
return CompletableFuture.completedFuture(e.getAppropriateResult());
}
...
}
But this use case is exactly what action composition should be for, I think. It just seems that the route parameters are missing. The Context object exposed in the Action call() method has a lot of stuff in it, actually. Headers are there, query parameters are there, and even the exact path being hit is there! Even if that were not so, by the point the framework has parsed the route and determined the values of the route parameters. This must be true because if it was not, then how would it know which action to call? However, it appears that these parsed parameters are completely unavailable to us. We could parse them again ourselves from the path. But why should we have to do that? We would be parsing the path twice. Why doesn't the framework expose these values?
There's an interesting article I found that, to solve a similar problem, suggests a hack that will put a url parameter into the query string parameters map.
https://alots.wordpress.com/2014/05/01/accessing-url-parameters-as-get-parameters-in-play/
However it appears to me that this method is also basically double parsing the path anyway, although I might be misinterpreting it as I'm not very familiar with Scala. If so, I might as well just hack in logic to reparse the path in my Action.
Okay so this problem is solvable in Scala. It does not appear there is currently any way to solve it in Java due to how Play Java uses annotations for action composition (and for body parsers, which is another place I ran into this exact same problem). You would have to parse the path again yourself. However, it looks like it is quite easy to accomplish in Scala. I haven’t tested either of these and I’m not very familiar with Scala, but it looks like for Play in Scala, action composition works differently.
this gist has an example of how Play Scala action composition should support this:
https://gist.github.com/wolfendale/75e8b5e9a7ace95aa7e6d123e6c6dacd
jroper’s posts in this issue thread also demonstrate what appears to me to be the same solution:
https://github.com/playframework/playframework/issues/3378#issuecomment-54925034
If those work, the technique demonstrated in the article I linked in the original post is not at all necessary to solve this problem if you are using Scala. However, because it only requires writing some code in Scala (whereas for the technique demonstrated by wolfendale and jroper, you need to write your controller in Scala as well), it could be a useful way to solve this problem and still write most of your application in Java. I don’t know for sure. I haven’t tested it and I’m not interested in that kind of hack.
You can't, at least, not out of the box. Play doesn't provide ways to get the request params in action composition.
Basically : You have to parse yourself.
There're few ways one can manipulate the message in Spring Integration. One way is calling a bean's method inside <int:enricher> that will return an object and assign it to the given name, e.g:
<!-- calls getKey method of IdGenerator bean which returns String with some value -->
<int:enricher input-channel="a.channel" output-channel="b.channel" id="preTranslator">
<int:header name="Key" expression="#IdGenerator.getId(payload)"/>
</int:enricher>
Same can be utilized in filtering:
int:filter discard-channel="d.channel" input-channel="b.channel" output-channel="c.channel"
expression="#Cache.hasKey(headers.Key) == false"/>
On the other hand I can call the <int:service-activator> on a class implementing MessageProcessor interface. It would take the original message and return a copy with a new header field. That requires my class's method to always build a new message with MessageBuilder though.
Currently I use the first way for simple field enrichment and service-activator for requesting data from DB/external services. What's the right way of picking the correct approach?
First of all, the <filter> doesn't change message at all. The given name should be read as header, looking to your case.
The <service-activator> always return a new message. Yes, you can populate new headers there as well and right you have to use MessageBuilder.
It is fully unclear what is your problem. If you can achieve the solution with expressions in the config, so be that. But if you do something with the message in the code and would like to add/edit/remove headers you use MessageBuilder.
That's really fine. I think you should just read more documentations and right more code in your application.
Eventually you will find the most convenient style for yourself. Fro example I end up once with expressions and Groovy scripts. No Java code at all. But right now I prefer Spring Integration Java DSL, because it is much faster, cleaner, fluent and lets get rid of any other configs like XML or Groovy. Everything is Java now and that MessageBuilder is still on the horse!
We are facing issue related with making a path parameter optional.
original URL /expire/{token}
What we are trying to do is have the same service work for the URL's below.
1. /expire/{token}
2. /expire
Ex:- #Path("/expire/{token}")
We have already applied other solutions from SO,but no luck so far.
What about adding another method annotated with only:
#Path("/expire")
And let this method pass a null value into the original method.
Logically, it doesn't seem to make sense to have it optional. Your URI should handle the type of request it's supposed to do. But, I came across a post to make the #PathParam to be optional with a small hack using regular expressions.
http://www.nakov.com/blog/2009/07/15/jax-rs-path-pathparam-and-optional-parameters/
I would go with having separate endpoint method in Controller where it can pass the call to your services with optional parameter.
We can use regular expressions,
"#Path("/add/{a:([0-9.]*)}/{b:([0-9.]*)}{p:/?}{c:([0-9.]*)}")"
here path can be
add/2/3
add/2/3/4
my case I am using regular expressions for allowing only numbers
Is there a common way to secure a pathvariable?
#RequestMapping("/image/{id}")
public String getArticleImageUrl(#PathVariable String id) {
....
I mean remove unusual content e.g. javascript or other security issue related things to prevent "hacking" or abusive use?
What is secure depends on what you want to use the input for. Bottom line: You should take the same care with these kinds of parameters as any other parameter you would accept from the outside into the system, e.g.:
Take appropriate action to prevent SQL injection (i.e. PreparedStatements)
Take care when rendering stuff on your web site that was received as user input (i.e. make sure to HTML encode stuff - most frameworks would take care of this for you).
etc.
"Washing" the input from unwanted characters is possible but, as always: tricky and depending on what the data will be used for.
Nvm.
I used a regex to check if this String is alphanumeric. ( ^[\\pL\\pN]+$ )
Should be enough.