Using #Value annotation with static final variable in Spring Framework - spring

I want to make the Request Mappings in my Spring application dynamic. So that my url can not be understandable. And I can show anything meaningless to the user and still mapping purpose will be resolved.
For that I am storing the dynamic part of the URL in properties file. And want to use that in the #RequestMapping annotation. And the same thing will be done on the client side in JSP. I will read the value from the property file and then create the href.
I am using #Value annotation to read the property file values.
There is one class that holds all such values in final static variables.
public class UrlMappingAbstraction {
public static final #Value("#{urlAbstractionProperties['url.message']?:'message'}") String MESSAGE = "";
}
And I am extending this class in my controller and using the static final field in the #RequestMapping annotation like below.
#RequestMapping(value="/"+MESSAGE+"/{id}", method=RequestMethod.GET)
And in jsp also I am reading the value from property file using <spring:message/> and generating the url in href.
The problem is jsp able to create the correct url based on the property file value but in the #RequestMapping annotation my value is not getting replaced.
Can anybody tell me the exact problem? I know that we can not change the value of static final variable after its initialized. Then what's the use of #Value annotation.
If this can be done another way then you can also show me it.
Thanks in advance.

Annotations are static by their nature, therefore you cannot do it this way.
#Value cannot be used on static fields, but it doesn't matter here - the real problem is that there is no way to use values other than compile time constants as attributes of annotations.
You can use one of the following alternatives:
Add a URL rewrite filter (such as this or this) and configure it to perform the necessary conversion.
This approach looks more elegant due to clear separation of responsibilities - controllers are responsible for doing their jobs, rewrite filter is responsible for obfuscation of URLs.
Intercept creation of controller mappings by overriding RequestMappingHandlerMapping. getMappingForMethod() and change their URL patterns at this step (not tested)

I will augment #axtavt's suggestions by saying you should just do it in reverse. Do you really need to make the message URL runtime configurable?
If you don't than just make a static variable just like you have it but with out the #Value:
public final class UrlMapping {
public static final String MESSAGE = "message";
}
Then in your JSP refer to UrlMapping.MESSAGE instead of the properties file.
Although its not as flexible its far simpler and IMHO its a bad idea to make endpoint URLs too configurable because inevitably you will hardcode something either in Javascript or in a template. Also changing URLs are bad for SEO.

You can follow this approach
#Value("${name}")
private String name;
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
src - https://www.baeldung.com/spring-inject-static-field

Related

Can we pass dynamic value to #RequestMapping annotation of spring mvc?

I am trying to map URL's in a dynamic way as follows,
consider that I am trying to access with different URL's
http://localhost:8080/MyApp/XYZ/Login.htm
http://localhost:8080/MyApp/PQR/Login.htm
http://localhost:8080/MyApp/ABC/Login.htm
From the above URL's I want to show different Login.htm page to the different user.
Here in above URL's there is only change in request of XYZ, PQR and ABC and rest of all is same, So this will be handled at class level #RequestMapping annotation of the controller class as per my knowledge .
If I manage to pass value dynamically to #RequestMapping annotation so I think I can achieve what I want to .
Please, can anyone suggest me how can I get dynamically value in the #RequestMapping annotation? Or any other suggestion to get Different Login page when URL changes.
You can use path variable matching
#RequestMapping(value = "/MyApp/{id}/Login.htm", method = GET)
#ResponseBody
public String getFoosBySimplePathWithPathVariable(
#PathVariable("id") String id) {
return id;
}
See documentation:
RequestMapping
PathVariable
you used if else condition, URL's in a dynamic way as follows, if condition we request mapping we give any string direct correct jsp page otherwise go to else part point out 404 error.
i want correct code....

How can I map URL containing colon to my Spring controller?

I want to map a URL (for example, http://example.com/v1/books:search) containing colons to my Spring MVC controller, but I can't make it work.
#RequestMapping("/v1/books")
public class BooksController {
#GetMapping(":search")
public Page<Book> search(#RequestParam String author) {
// Return books written by the author.
}
When I test this API, Spring returns 404 NOT_FOUND to me. It seems that Spring doesn't support colons in URL mapping.
Is there any method to make it work? Thanks.
I hit this attempting to do similar so I thought I'd share my findings.
With using most defaults and your code, the search method will be mapped to /v1/books/:search which is obviously not quite what you want. There are two places that I've found so far that get in the way of changing this. The first is the AntPathMatcher's combine method. This method will attempt to put a path separator (/) between segments. The second place is within the RequestMappingInfo's path parsing code. The former can be replaced easily. The latter not so much.
As the methods that tend to be problematic involve combining multiple #RequestMapping annotations, what I've found to work is to simply side-step combinations. On my controller class, I have a #Controller annotation and any defaults for #RequestMapping, but not a path attribute. On each method, the full path is then added. This isn't great, but it does get collection-level special "methods" to function properly. In your example, this would look like:
#Controller
#RequestMapping
public class BooksController {
#GetMapping("/v1/books:search")
public Page<Book> search(#RequestParam String author) {
// Return books written by the author.
}
Long story short: Do not do this - use / as a separator for the method.
A bit more detail: Have a look at Spring Framework issue #24771 that suggests that the team actually moves away from various ways to handle non-standard URL mappings in favor of simpler logic of URL processing, after entangling in a series of various issues with similar concepts. This "custom method" thing is unlikely to get a first class support in Spring, as a result.
Therefore, despite what Google does, just do this as a normal person and use /v1/books/search path:
#RequestMapping("v1/books")
public class BooksController {
#GetMapping("search")
public Page<Book> search(#RequestParam String author) {
// Return books written by the author.
}
}

Is there a way to link JAX-RS resource to another resource like in Spring HATEOAS?

In Spring we've got #ExposesResourceFor annotation which can link our resource with other resources. Thanks to this our Value objects (representations) can know nothing of the actual resources.
Is there a way to do it in JAX-RS? I'm using Dropwizard with Jersey and Jackson and all I see is #InjectLinks annotation which I can use in a value object like this:
public class UserGroup {
#JsonProperty
public String name;
#InjectLinks(GroupsResource.class)
public URI myResource;
public UserGroup(String name){
this.name = name;
}
}
But unfortunatelly my Value Objects should know nothing about Resources, so I'm asking can I do such linking on the level of resources - link in spring-hateoas in controllers, as mentioned above.
With #InjectLinks, you don't have to declare the links in your model class. You can create a "wrapper" representation class, as shown in declarative-linking from the Jersey examples (though this solution is not really on the resource class level as you wish).
Another possible solution (rather than declarative linking) is to use the JAX-RS 2.0 Link class, and do the linking programmatically (with no ties to the Jersey implementation/annotations). You can either add the links to your response headers, as see here, or add Links to you model classes, as seen here (or use the wrapper class for this also, so as to not to invade your model classes)
Some Resources
Declarative Hyperlinking
Using Link for headers

Update field annotated with #Value in runtime

Let's imagine we have such a component in Spring:
#Component
public class MyComponent {
#Value("${someProperty}")
private String text;
}
If we define the property placeholder:
<context:property-placeholder location="classpath:myProps.properties"/>
And myPropos.properties contains the value for someProperty the value will be injected to the text field when the context is initialized. That's quite simple and easy.
But let's say that I have a service that enables user to change the value of the someProperty:
public void changeProp(String name, String newValue);
Is there a chance I can re-inject the newValue to text field. I mean it should be quite straight forward.. Basically it's nothing different than the after-initialization injection. I can not imagine that Spring does not have support for this? Can I fire some event or something?
I could do this on my own basically, but I wander is it maybe something there already? If not does anyone know what Spring class is in fact handling the injections at the first place? I could probably reuse the code there do perform this on my own if a solution does not exists.
I expect spring does not have a support for this, because the normal injection is done while creating the bean, but not will it is put in service.
Anyway: in this blog entry "Reloadable Application Properties with Spring 3.1, Java 7 and Google Guava", you can find the idea for an solution.
The key idea is to use a post processor to build a list of all fields with property fields. And if the properties are changed on can use this list to update the fields.

Handling of pre-slash in #RequestMapping

Imagine that I have a Spring MVC controller something like this:
#Controller
#RequestMapping("/base-url")
public class MyController{
//..snip
#RequestMapping(method=RequestMethod.GET, value="/edit/{id}")
public String edit(Model model, HttpServletRequest request, Authentication authentication){
//..snip
}
}
My question is regarding the inner value parameter to the #RequestMapping annotation at the function level. Is the pre-slash on /edit/{id} required, or does edit/{id} do the job just as well? I would have imagined that the pre-slash would set the request to be absolute, regardless of the class level mapping, but it seems to be ignored.
Is one or the other considered better practice?
In the Spring documentation, they seem to always use the pre-slash. Are there any practical benefits to doing that?
Thanks,
idb.
According to the spring documentation, having a class level #RequestMapping annotation implies that all method level #RequestMappings will be relative to that of the class'.
It might be nice however, to have the ability to override the relative mappings in some rare cases.
I personally prefer to add pre-slash in value of #RequestMapping. In code level you can see: If the value does not start with an / then Spring (DefaultAnnotationHandlerMapping) will add it. Details answer you can visit: Use or not leading slash in value for #RequestMapping. Need official docs or point to Spring source?

Resources