Injecting Spring Spel Expressions into bean properties - spring

How can I inject a String meant to be a spel expression into an app context bean property without having the context interpret the string property as a spel resolvable value.
<bean id="x" p:spelExpression="${#code}/${#value}"/>
I want the the class's setter property to take a string argument and creates a reusable SpelExpression as a private property of the bean, however, the spring application context appears to be recognizing the #variableName as spel expressions and attempting to interpret the expression at initialization time.
I find Spel interpretation to be very useful, but would like to to use spel internally as well, with expression injection into my own beans.
Is it possible to disable the Spel Interpretation of for a bean, or even for a whole context file (maybe with some namespace shenanigans) without having to disable or modify spel expression resolution for the whole application context.

The #{...} are markers for spel interpreter in xml context.
I don't undestand : ${#code}/${#value}. Good is #{code/value}, as I understand things, if code and value are id.
So, if you want a spel expression without interpret it, put string code/value in xml.

Related

Spring Framework: Is there a list of "reserved words" or "Predefined Variables" about SpEL?

For Spring Framework where is the complete list of reserved words or Predefined Variables about SpEL with their respective explanation? It such as for:
environment
systemProperties
systemEnvironment
For example in this valuable tutorial is just shown the 2 latest of the list shown above
Spring Expression Language (SpEL) Predefined Variables
Consider if Spring 6 added more of them, it as an improvement, therefore could be more.
Yes, I did do a research - currently for version 6 - at the official documentation at:
Spring Expression Language (SpEL)
But does not contain the reserved words.
There isn't really a list of reserved words for SpEL like what you are looking for, at least not in generic SpEL parsing and evaluation.
There is default SpEL support in the application context and notably in #Value annotations, as documented in the reference guide: Expressions in Bean Definitions.
Thi is provided via a SpEL StandardEvaluationContext which uses the beanFactory as the root object. Or rather, it uses a BeanExpressionContext view of the bean factory plus a dedicated PropertyAccessor is added to this evaluation context so that every beanName in the bean factory is considered a property of that root object during evaluation.
As a result, if a bean named foo is registered in the factory, #Value("#{ foo }") will be interpreted as "the property foo of the root object", which resolves to the aforementioned bean.
So systemProperties/systemEnvironment and environment are not really predefined SpEL variables, but rather standard beans in an AbstractApplicationContext.

What does the #Value annotation in method do?

I see one method annotated with #Value("${some.property}")
as in
#Value("${some.property}")
public void setSomething(String param) {
... do something with param
}
What is that annotation doing there?
Basically it tells Spring's AutowiredAnnotationBeanPostProcessor to call the setSomething method with the resolved value of some.property as the argument... but only if you have a PropertySourcesPlaceholderConfigurer in your bean definitions; if you haven't configured one the post processor will only inject the string "${some.property}"(without quotes) to your method.
An IllegalArgumentException will be thrown if the value could not be resolved unless you have used a default e.g. "${some.property:default}".
Spring resolves these values using the current Environment and its PropertySources e.g. JVM system properties, a Java properties file, etc.
Also you may use Spring Expression Language (SpEL) to resolve things like #{someBean.someMethod} or #{systemProperties[user.region]}
Sidenote: As the documentation states
Fields are injected right after construction of a bean, before any
config methods are invoked. [...] Bean property setter methods [as in this case] are effectively just a special case of such a general config method.
A common mistake is to try to execute some logic in your constructor using the value injected but at this moment the value has not be resolved nor injected because the constructor must finish in order to inject the value in the config method. In these cases you have to use the #Value or #Autowired annotations in your constructor arguments.
You may also use #PostConstruct or the XML init-method attribute pointing to a method that will be executed after the bean properties have been set. Alternatively you can implement the InitializingBean interface.

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 disable interpolation of property values in property placeholders

I'm using Spring 3 and Spring's property-placeholders in my application context:
<context:property-placeholder location="my.properties"/>
my.properties contains:
key1=value1
key2=some JSP code ${some-model-attr}
The issue is, the values in my.properties are also evaluated against the placeholders, but in my case the values contain JSP EL, which causes "property not found" errors during Spring initialization:
java.lang.IllegalArgumentException: Could not resolve placeholder 'some-model-attr'
So far I have this workaround, but it's ugly:
key1=value1
key2=some JSP code #{'$'}{some-model-attr}
Hence my question:
Is it possible to tell Spring not to interpolate property placeholder values, or, in other words, not to evaluate placeholders recursively?
It looks like it isn't possible to tell Spring not to recursively evaluate placeholders.
The placeholders are evaluated by org.springframework.util.PropertyPlaceholderHelper which (in Spring 3) contains the following line:
// Recursive invocation, parsing placeholders contained in the placeholder key.
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
So the recursive call is hard-coded into the evaluation.
However I think you could change the default prefix and suffix for placeholders so that you use a different syntax for Spring placeholders. <context:property-placeholder> is just a convenient way of constructing the org.springframework.beans.factory.config.PropertyPlaceholderConfigurer class, and that class has methods setPlaceholderPrefix() and setPlaceholderSuffix(). You could use those methods to change the syntax of the Spring placeholders to something like:
$[property]
instead of
${property}
Then I expect Spring won't parse your JSP properties any more because they're in a different syntax:
key2=some JSP code ${some-model-attr}
As a workaround you can use SpEL expression templating. For example:
key2=some JSP code $#{'{some-model-attr}'}
This works because Spring no longer sees the configured property placeholder prefix of ${. However, the SpEL expression evaluates to the String concatenation of:
'some JSP code $' + '{some-model-attr}'
which is the same as
some JSP code ${some-model-attr}

Resources