Spring MVC #RequestMapping dynamic value - spring

I am trying to set the "value" attribute of #RequestMapping annotation from a method of an autowired bean using SpEL
#Autowired
private RouteService routeService;
#RequestMapping(value={"#{routeService.loadRoutes()}"})
without any success.
Does anyone know if this is possible?

No, it is not possible.
This is happening because the value of the RequestMapping must be a constant expression.
What you can do is declare some constants and use those as a Strings inside the RequestMapping's value.

Like user OEH said this is not possible. One solution might be to take a path parameter and then route the message based on the value of the parameter.

Related

String.format returns null in Spring Boot after retrieving information from application.properties

I have a Spring Boot application, using Intellij, and am trying to use the #Value annotation in order to get an environment variable from my application.properties.
My application.properties looks like this
server.port=27019
web.entrance.id=63d284ec
Using debugger, I can see that the value of entranceId is successfully retrieved from application.properties, but the same variable is always null in the String.format and my WebUrl has the string 'null' in it and I don't understand why.
#RestController
public class Controller {
#Value(("${entrance.id}"))
private String entranceId;
String WebUrl = String.format("http://localhost:27019/%s", entranceId);
Can someone explain if there is some detail I'm missing why this happens?
Thank you
Your thinking is wrong. Spring will process the #Value after the object has been constructed, whereas your field is being initialized as soon as the class is being constructed (so during constructing).
Basically what Spring does
new Controller()
Detect #Value and with reflection set value
Any construction callbacks (like #PostConstruct).
Your field is being filled at step 1 not after step 2. At which point the #Value hasn't yet been processed.
If you want to set the value you need to do that in an #PostConstruct method or use constructor injection to construct the URL.

Custom annotation like #Value

I need to create a means to add a custom annotation like
#Value("${my.property}")
However, in my case I need to get the value from a database rather then a properties file.
Basically I would like to create a bean on container startup that reads in property name value pairs from a database and can then inject these into fields belonging to other beans.
Approach #1:
One way is to create an Aspect, with a point-cut expression that matches any method having this annotation.
Your aspect will then:
Read the property value in the annotation
Look up the required value an inject it into the class.
AOP Kickstart
Here's a guide to getting started with AOP in Spring
http://www.tutorialspoint.com/spring/aop_with_spring.htm
Joinpoint matching
Here's a reference that describes how to create a join-point that matches on annotations: http://eclipse.org/aspectj/doc/next/adk15notebook/annotations-pointcuts-and-advice.html
Approach #2:
Another way is to use a BeanFactoryPostProcessor - this is essentially how a PropertyPlaceholderConfigurer works.
It will look at your bean definitions, and fetch the underlying class.
It will then check for the annotation in the class, using reflection.
It will update the bean definition to include injecting the property as per the value in the annotation.
. . actually I think approach #2 sounds more like what you want - all of the processing happens on "start-up". . . (In actual fact your modifying the bean recipes even before startup). . whereas if you used AOP, you'd be intercepting method invocations, which might be too late for you?
Namespace Handler
If you wanted you could even create your own Spring namespace handler to turn on your post processor in a terse way. Eg:
<myApp:injectFromDb />
as an alternative to:
<bean class="MyDatabaseLookupProcessorImpl etc, etc. />
Update: Approach #3
As of Spring 3.1 there's also the PropertySourcesPlaceholderConfigurer, that will provide most of the plumbing for you, so you can achieve this with less code.
Alternatively you should be able to configure kind of properties repository bean and then use it in SpEL directly in #Value annotation.
Let's say you'd have bean called propertiesRepository in your context that implements following interface:
interface PropertiesRepository {
String getProperty(String propertyName);
}
then on bean where you want to inject values you can use following expression
#Value("#{propertiesRepository.getProperty('my.property')}")
String myProperty;
You can use #Value annotation by injecting database configuration in application environment itself.
I know this is an old question but I didn't find an exact solution. So documenting it here.
I have already answered the same on different forum.
Please refer to this answer for exact solution to your problem.

Spring #Cachable bean reference in key

I want to use the #Cachable annotation on one of my methods, but I have the problem, that the result depends on an attribute of a spring bean that is not part of the method signature.
So I want something like this:
#Cachable(value="mycache", key="#id, #myspringbean.referenceId")
MyResult myMethod(int id);
I guess these are actually two problems: How to get use a composite key and how to use another spring bean in the expression.
The problem of how to use a composite key can probably be solved like in this SO question: #Cacheable key on multiple method arguments
However, I could not find anythig about how to reference to another spring bean in this expression. Is it possible and if yes, how?
You can have a lot a details on SpEL in the Spring documentation (http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/expressions.html). As you can see, you can use bean references using the #myBean syntax. You have to include a bean resolver in your context to do that.
It's not possible to use the current Spring bean name.
I think I would use the following pattern so that each bean object will have it's own "key-space" see also What can be the default key generator.
As for the problem above one can use:
#Cachable(value="mycache", key = "{#id, #root.targetClass.getDeclaredField('attribute').get(#root.target)}")
MyResult myMethod(int id);
just make sure your attribute is public

How to get property from context property placeholder tag inside custom java component

I have Mule Configuration that defines
<context:property-placeholder location="classpath:/mule-sw.properties"/>
And I also have a custom component class in Java which use #Lookup annotation on one of my field
#Lookup("file-path")
private String path;
Considering my "mule-sw.properties" is like this
file-path=C:/hello.txt
After I start up the Mule App, I always get Deploy Exception
org.mule.api.expression.RequiredValueException: "Required object not found in registry of Type "class java.lang.String" with name "file-path" on object "class component.CustomComponent"
I also tried to change the #Lookup("file-path") with #Lookup("${file-path}") with no success.
Anyone can give me a better solution ?
Any help is kindly appreciated.
Thanks
The #Lookup annotation is designed to retrieve objects from the registry , whereas what you are trying to do is to assign a value to an attribute of your custom component.
There are 2 way to do that:
1) Through property injection, i.e. you declare your component like the following:
<custom-component class="org.myCompany.CustomComponent">
<property name="file-path" value="${file-path}" />
</custom-component>
2) Through Spring EL support and the #Value annotation, i.e. you annotate your attribute in the following way
#Value("${file-path}")
private String path;
I'd recommend the first approach since it is easier to maintain from a flow perspective
#Value("#{'${file-path}'}")
private String path;
Give this a shot. I think you need to wrap it in an EL block #{} for it to be properly recognized.

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