Using a static variable value in Qualifier annotation - spring

Is it possible to pass a static variable defined in a class as argument to #Qualifier annotation? I tried the below format and a few other variations, but nothing worked.
#Qualifier("T(com.test.Constants).BEAN_NAME")
Spring-el works in #Value annotation. For example, below example is valid:
#Value("#{ systemProperties['user.region'] }")

Try with #Qualifier(com.test.Constants.BEAN_NAME)

Related

How to define #Value as nullable in spring with kotlin?

I don't want autowiring fail when one specific property is missing. In that case i can accept nulls. How can i achieve it?
#Service
class MyClass(
#Value("\${my.nullable.property}") property: String?
)
You can define a default when using #Value and set it to an expression that evaluates to null:
#Value("\${my.nullable.property:#{null}}")
Anything after the : is the default if my.nullable.property cannot be defined. Because putting null there would be treated as a String, we have to use an expression that evaluates to null, which is wrapped by #{}.

ByteBuddy - Getting error while passing array in annotation's value

Consider an example of building a new class instance and adding below annotation.
.annotateMethod(
AnnotationDescription.Builder.ofType(OneToMany.class)
.define("cascade", new CascadeType[]{CascadeType.PERSIST, CascadeType.MERGE})
.define("fetch", FetchType.LAZY)
.define("targetEntity", EntityB.class)
.build())
Everything works fine except assigning the "cascade" value. Getting compile-time error because .define method is not expecting an array of enums.
How can I pass an array as an Annotaion's value assignment?
For example, I want to assign an array of enum as below:
#ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
As Holger points out, use defineEnumerationArray as documented in the javadoc.
The overloads are limited to avoid a conflict with defining a single enum value property compared to defining an enumeration array with a single value.

Kotlin compiler complains about using a SPeL expression in a property definition. WHY?

When I try to use a SPeL expression to inject a value it works from in Java but NOT in Kotlin. The compiler says
Error:(13, 25) Kotlin: An annotation parameter must be a compile-time constant
Code:
#SpringBootApplication
open class DeDup(#Value("#{new java.io.File('${roots}')}") val roots: Set<File>,
#Value("algo") val hashAlgo: String,
#Value("types")val fileTypes: List<String>) {
}
fun main(args: Array<String>) {
SpringApplication.run(DeDup::class.java, *args)
}
Mmm... news flash Kotlin compiler: It IS a constant! The compiler clearly knows it's a SPeL expression and doesn't like it.
My questions:
Why doesn't Kotlin like SPeL? This is a construction injection (or is it) and doesn't violate immutability.
Is this a compiler bug? The message is irrefutably wrong.
${roots} inside a String in Kotlin is a string template, therefore that String is not a constant.
If you want the String to contain those actual characters and not be interpreted as a template, you'll have to escape the $:
#Value("#{new java.io.File('\${roots}')}")

Spring Cacheable how to pass method invocation result to key?

Consider following snippet, I am trying to call a method of propertiesContainer which would be used as a key.
#Cacheable(value = EhCacheManagerApi.CACHE_X_TOKEN, key = ("#{propertiesContainer.getId()}"))
public String getToken(PropertiesContainer propertiesContainer)
I cannot seem to figure out the correct spel expression for key, current format gives me:
org.springframework.expression.spel.SpelParseException: EL1043E:(pos 1): Unexpected token. Expected 'identifier' but was 'lcurly({)'
Before I tried key = ("#propertiesContainer.id") and key = ("#propertiesContainer.getId()")
propertiesContainer is an interface which has method getId returning String.
So presumably this is not the same as bean method invocation with SpEL?
Could you please try this
#Cacheable(value = EhCacheManagerApi.CACHE_X_TOKEN, key = "#{T(java.lang.String).format('%d-%d', #propertiesContainer.id)}")
Did you try the pure expression without the parenthesis:
#Cacheable(value = EhCacheManagerApi.CACHE_X_TOKEN, key="propertiesContainer.id")
This works for me in Spring 4.3.3 where PropertiesContainer is an interface with a getId() method.
Also, you might need to use #p0.id instead of the method parameter name if you don't have debug info in your compiled code. See the accepted answer here but that would give you a different error I suspect.

JSTL Expression Language accessing object properties

I was following a tutorial today that had me scratching my head for an hour. Consider:
public class MyClass {
public int getTotal() {
amount = 100;
return amount;
}
}
and an excerpt from a JSP:
<p>Total: ${objectOfTypeMyClass.total}</p> //object instantiated elsewhere
Nowhere in the code was an instance variable named "total" ever declared or used. The only reference to the word "total" in the whole project (other than in the JSP) was the method getTotal().
So after some desperate last-ditch experimentation, it appears that Expression Language evaluates ${someObject.var} as "call the getVar() method of the someObject object.
I worked with this long tutorial for over a week thinking that ${someObject.var} was saying "directly fetch the saved instance variable "var" from someObject.
Did I have it wrong the whole time and is my observation correct that in order to reference any instance variable using EL, you have to provide a corresponding getter method named getVarname() where "Varname" is the name of the instance variable?
Also, EL seems to be case-insensitive in this regard. In my example above, "total" in ${objectOfTypeMyClass.total} is all lowercase where the method getTotal() has a capital "T".
And while we're at it, why don't we need to instantiate the variable "total"? I guess EL isn't actually referencing an instance variable...just a getter method?
What gives?
Did I have it wrong the whole time and is my observation correct that in order to reference any instance variable using EL, you have to provide a corresponding getter method named getVarname() where "Varname" is the name of the instance variable?
That's correct. EL adheres the JavaBeans specification as described in the EL specification.
Also, EL seems to be case-insensitive in this regard. In my example above, "total" in ${objectOfTypeMyClass.total} is all lowercase where the method getTotal() has a capital "T".
No, it's certainly not case insensitive. It's specified behaviour. ${bean.Total} would not have worked.
And while we're at it, why don't we need to instantiate the variable "total"? I guess EL isn't actually referencing an instance variable...just a getter method?
It's because it's supposed to adhere the Javabean specification.
All with all, read the both specifications and everything will be clear :)
See also:
What are the advantages of Javabeans?
The . in objectOfTypeMyClass.total is the JSTL EL Dot Operator. It can do a few different things. Including:
map.key accessed a value from map stored under key. or
object.property accesses property from object using "JavaBeans" conventions.
This should work:
public class MyClass {
private int total = 100;
public int getTotal() {
return total;
}
...
}

Resources