How can I manually evaluate the expression in a Spring #Value annotation? - spring

My SpringBoot application has a bunch of #Value annotations. When the application is deployed to our Kubernetes cluster, it ends up using a properties file that is interpolated through a couple of different mechanisms. When it finally gets there, if developers make simple mistakes, the container can fail to start up, simply because they didn't set all the properties correctly. It's not easy to discover that this is what happened, until well after the mistake is made.
Note that virtually all of these #Value annotations will use the "${}" syntax, as opposed to "#{}". The primary concern is reading particular properties from a properties file, not Spring bean properties.
So, what I want to write is a little validation script (a small Java class), which does something like this:
Obtain the path to the generated properties file
Load that properties file into a Properties object
Scan the classpath for all classes (with a base package), and all fields in those classes, for #Value annotations
For each found #Value annotation, do some simple validation and evaluate the expression
If the validation or the evaluation fails, print an error message with all relevant details.
This script will run before the "kubectl rollout" happens. If we see these error messages before the rollout, we will save time diagnosing these problems.
I've been able to achieve everything so far except doing something with the loaded properties file and evaluating the expression. I know that Spring uses a bean postprocessor, but I don't know how I can manually call that.
Any idea how to fulfill that missing link?
Update:
I still don't have an answer to this.
I was thinking that perhaps the answer would be found in a BeanPostProcessor in the Spring codebase, so I cloned the spring-framework repo. I found a couple of potential ones, being "AutowiredAnnotationBeanPostProcessor", "BeanFactoryPostProcessor", "CommonAnnotationBeanPostProcessor", and "BeanPostProcessor", but I just don't see anything in any of these that looks like evaluating the expression in the Value annotation. I would have tried setting a breakpoint in the "value()" method of the annotation, but of course you can't set a breakpoint in a method like that.
Update:
To be clear, this expression is not a "Spring EL" expression. Those reference bean properties (or loaded properties) and begin with "#{". I'm working with expressions that just reference properties, which begin with "${". I did try parsing the expression with Spring EL, but it just thinks there's nothing there.

I've managed to figure this out. The key is the "PropertyPlaceholderHelper.replacePlaceholders(String, Properties)" method. Using that, I developed something like this:
PropertyPlaceholderHelper propertyPlaceholderHelper =
new PropertyPlaceholderHelper("${", "}", ":", true);
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(true);
boolean foundAtLeastOneUnfoundProperty = false;
for (BeanDefinition bd : scanner.findCandidateComponents(basePackage)) {
String beanClassName = bd.getBeanClassName();
Class<?> clazz = Class.forName(beanClassName);
for (Field field : clazz.getDeclaredFields()) {
Value valueAnnotation = field.getAnnotation(Value.class);
if (valueAnnotation != null) {
Matcher matcher = propertyRefPattern.matcher(valueAnnotation.value());
if (matcher.matches()) {
String resultingValue = propertyPlaceholderHelper.replacePlaceholders(valueAnnotation.value(), properties);
if (resultingValue.equals(valueAnnotation.value())) {
// This means that the property was not found.
System.out.println("ERROR: Expression \"" + valueAnnotation.value() +
"\" on field \"" + field.getName() + "\" in class \"" + beanClassName +
"\" references a property which is not defined.");
foundAtLeastOneUnfoundProperty = true;
}
}
}
}
}

Related

How to keep non-nullable properties in late initialization

Following issue: In a client/server environment with Spring-Boot and Kotlin the client wants to create objects of type A and therefore posts the data through a RESTful endpoint to the server.
Entity A is realized as a data class in Kotlin like this:
data class A(val mandatoryProperty: String)
Business-wise that property (which is a primary key, too) must never be null. However, it is not known by the client, as it gets generated quite expensively by a Spring #Service Bean on the server.
Now, at the endpoint Spring tries to deserialize the client's payload into an object of type A, however, the mandatoryProperty is unknown at that point in time, which would result in a mapping exception.
Several ways to circumvent that problem, none of which really amazes me.
Don't expect an object of type A at the endpoint, but get a bunch of parameters describing A that are passed on until the entity has actually been created and mandatoryProperty is present . Quite cumbersome actually, since there are a lot more properties than just that single one.
Quite similar to 1, but create a DTO. One of my favorites, however, since data classes can't be extended it would mean to duplicate the properties of type A into the DTO (except for the mandatory property) and copy them over. Furthemore, when A grows, the DTO has to grow, too.
Make mandatoryProperty nullable and work with !! operator throughout the code. Probably the worst solution as it foils the sense of nullable and non-nullable variables.
The client would set a dummy value for the mandatoryProperty which is replaced as soon as the property has been generated. However, A is validated by the endpoint and therefore the dummy value must obey its #Pattern constraint. So each dummy value would be a valid primary key, which gives me a bad feeling.
Any other ways I might have overseen that are more feasible?
I don't think there is a general-purpose answer to this... So I will just give you my 2 cents regarding your variants...
Your first variant has a benefit which no other really has, i.e. that you will not use the given objects for anything else then they were designed to be (i.e. endpoint or backend purposes only), which however probably will lead to cumbersome development.
The second variant is nice, but could lead to some other development errors, e.g. when you thought you used the actual A but you were rather operating on the DTO instead.
Variant 3 and 4 are in that regard similar to 2... You may use it as A even though it has all the properties of a DTO only.
So... if you want to go the safe route, i.e. no one should ever use this object for anything else then its specific purpose you should probably use the first variant. 4 sounds rather like a hack. 2 & 3 are probably ok. 3 because you actually have no mandatoryProperty when you use it as DTO...
Still, as you have your favorite (2) and I have one too, I will concentrate on 2 & 3, starting with 2 using a subclass approach with a sealed class as supertype:
sealed class AbstractA {
// just some properties for demo purposes
lateinit var sharedResettable: String
abstract val sharedReadonly: String
}
data class A(
val mandatoryProperty: Long = 0,
override val sharedReadonly: String
// we deliberately do not override the sharedResettable here... also for demo purposes only
) : AbstractA()
data class ADTO(
// this has no mandatoryProperty
override val sharedReadonly: String
) : AbstractA()
Some demo code, demonstrating the usage:
// just some random setup:
val a = A(123, "from backend").apply { sharedResettable = "i am from backend" }
val dto = ADTO("from dto").apply { sharedResettable = "i am dto" }
listOf(a, dto).forEach { anA ->
// somewhere receiving an A... we do not know what it is exactly... it's just an AbstractA
val param: AbstractA = anA
println("Starting with: $param sharedResettable=${param.sharedResettable}")
// set something on it... we do not mind yet, what it is exactly...
param.sharedResettable = UUID.randomUUID().toString()
// now we want to store it... but wait... did we have an A here? or a newly created DTO?
// lets check: (demo purpose again)
when (param) {
is ADTO -> store(param) // which now returns an A
is A -> update(param) // maybe updated also our A so a current A is returned
}.also { certainlyA ->
println("After saving/updating: $certainlyA sharedResettable=${certainlyA.sharedResettable /* this was deliberately not part of the data class toString() */}")
}
}
// assume the following signature for store & update:
fun <T> update(param : T) : T
fun store(a : AbstractA) : A
Sample output:
Starting with: A(mandatoryProperty=123, sharedReadonly=from backend) sharedResettable=i am from backend
After saving/updating: A(mandatoryProperty=123, sharedReadonly=from backend) sharedResettable=ef7a3dc0-a4ac-47f0-8a73-0ca0ef5069fa
Starting with: ADTO(sharedReadonly=from dto) sharedResettable=i am dto
After saving/updating: A(mandatoryProperty=127, sharedReadonly=from dto) sharedResettable=57b8b3a7-fe03-4b16-9ec7-742f292b5786
I did not yet show you the ugly part, but you already mentioned it yourself... How do you transform your ADTO to A and viceversa? I will leave that up to you. There are several approaches here (manually, using reflection or mapping utilities, etc.).
This variant cleanly seperates all the DTO specific from the non-DTO-specific properties. However it will also lead to redundant code (all the override, etc.). But at least you know on which object type you operate and can setup signatures accordingly.
Something like 3 is probably easier to setup and to maintain (regarding the data class itself ;-)) and if you set the boundaries correctly it may even be clear, when there is a null in there and when not... So showing that example too. Starting with a rather annoying variant first (annoying in the sense that it throws an exception when you try accessing the variable if it wasn't set yet), but at least you spare the !! or null-checks here:
data class B(
val sharedOnly : String,
var sharedResettable : String
) {
// why nullable? Let it hurt ;-)
lateinit var mandatoryProperty: ID // ok... Long is not usable with lateinit... that's why there is this ID instead
}
data class ID(val id : Long)
Demo:
val b = B("backend", "resettable")
// println(newB.mandatoryProperty) // uh oh... this hurts now... UninitializedPropertyAccessException on the way
val newB = store(b)
println(newB.mandatoryProperty) // that's now fine...
But: even though accessing mandatoryProperty will throw an Exception it is not visible in the toString nor does it look nice if you need to check whether it already has been initialized (i.e. by using ::mandatoryProperty::isInitialized).
So I show you another variant (meanwhile my favorite, but... uses null):
data class C(val mandatoryProperty: Long?,
val sharedOnly : String,
var sharedResettable : String) {
// this is our DTO constructor:
constructor(sharedOnly: String, sharedResettable: String) : this(null, sharedOnly, sharedResettable)
fun hasID() = mandatoryProperty != null // or isDTO, etc. what you like/need
}
// note: you could extract the val and the method also in its own interface... then you would use an override on the mandatoryProperty above instead
// here is what such an interface may look like:
interface HasID {
val mandatoryProperty: Long?
fun hasID() = mandatoryProperty != null // or isDTO, etc. what you like/need
}
Usage:
val c = C("dto", "resettable") // C(mandatoryProperty=null, sharedOnly=dto, sharedResettable=resettable)
when {
c.hasID() -> update(c)
else -> store(c)
}.also {newC ->
// from now on you should know that you are actually dealing with an object that has everything in place...
println("$newC") // prints: C(mandatoryProperty=123, sharedOnly=dto, sharedResettable=resettable)
}
The last one has the benefit, that you can use the copy-method again, e.g.:
val myNewObj = c.copy(mandatoryProperty = 123) // well, you probably don't do that yourself...
// but the following might rather be a valid case:
val myNewDTO = c.copy(mandatoryProperty = null)
The last one is my favorite as it needs the fewest code and uses a val instead (so also no accidental override is possible or you operate on a copy instead). You could also just add an accessor for the mandatoryProperty if you do not like using ? or !!, e.g.
fun getMandatoryProperty() = mandatoryProperty ?: throw Exception("You didn't set it!")
Finally if you have some helper methods like hasID(isDTO or whatever) in place it might also be clear from the context what you are exactly doing. The most important is probably to setup a convention that everyone understands, so they know when to apply what or when to expect something specific.

PDPrincipal.implies deprecated, alternate class's implies method requires a Subject

I have the following running code to determine if a user can edit Object Namespace
com.tivoli.mts.PDPrincipal whoIsit = new PDPrincipal(userId,configURL);
com.tivoli.mts.PDPermission whatTheyWant = new PDPermission(objectSpaceName,GMTConstants.tamPermissions);
boolean haveAccess = whoIsit.implies(whatTheyWant);
The problem is that the implies method from com.tivoli.mts.PDPrincipal class has been deprecated.
This has been replaced by
com.tivoli.pd.jazn.PDPrincipal.implies(javax.security.auth.Subject subject)
Question is how do i construct this Subject object. Secondly, can i continue to use the deprecated clas and method?
I was able to work out a solution for this hence sharing it here so that anyone else facing the same issue can use this code.
I found that the new com.tivoli.pd.jazn.PDPermission class has a method implies which takes in a PdAuthorization context and a com.tivoli.pd.jazn.PDPrincipal object which does the same authorization checks that the previous class com.tivoli.mts.PDPrincipal use to do.
Mentioned below is how the same authorization can be done. With this code you need not implement the JAAS code.
First construct the PdAuthorizationContext as shown below. Make sure to define a static PdAuthorizationContext object so that it can be reused untill you close it. Constructing PDAuthorizationContext for every authorization check is resource intensive and not recommended. close the context at the end of your logic
URL configURL = new URL("file:" + String locationToTamConfigFile);
PDAuthorizationContext pdAuthCtx = new PDAuthorizationContext(configURL);
Next Construct the new PDPrincipal and the PdPermission objects as shown below and call the implies method
com.tivoli.pd.jazn.PDPrincipal pdPrincipal = new com.tivoli.pd.jazn.PDPrincipal(pdAuthCtx,userId);
com.tivoli.pd.jazn.PDPermission pdPermission = new com.tivoli.pd.jazn.PDPermission(objectSpaceName,"TbvA");
boolean newimpliesTry = pdPermission.implies(pdAuthCtx,pdPrincipal);

grails:spring:resources.groovy - is there any difference between refrencing beans with and without ref()

Help me with this small confusion as I am new to grails and working on grails with spring
Is there any difference between ref to firstBean in secondBean and thirdBean in resources.groovy
beans = {
firstBean(someclass)
secondBean(someotherclass) {
property = firstBean
}
thirdBean(someotherclass) {
property = ref(firstBean)
}
}
In your example there is hardly any difference. You are getting basically the objects you just have defined there. So this only works, if you can order your code, so this works and if the refs are right within your resources.groovy. The more common case is to use ref with strings, which may "forward reference". E.g.
beans = {
// fails! print b1
// fails! print ref(b1)
print ref("b1")
b1(Expando)
print b1
print ref(b1)
print ref("b1")
}
I'd use ref(<String>) for good measure, to give the underlying spring injection framework the easiest way to handle its dependencies (e.g. so components need only to be created, if and when they are needed).

ref() not getting bean config for nested map value using spring dsl on grails

On Grails 2.3.7, trying to set a nested map value using bean reference in resources.groovy
msgbean(Message){
text = 'hello'
}
bean1(ConfigObj){
prop = [ref('msgbean')]
}
bean2(ConfigObj){
prop = [key: ref('msgbean')]
}
bean3(ConfigObj){
prop = [key:[msg:ref('msgbean')]]
}
bean1 and bean2 get wired correctly,
println '1 ' + bean.prop[0].text
println '2 ' + bean2.prop['key'].text
prints...
1 hello
2 hello
bean3, however, doesn't get its reference to msgbean...
println '3 ' + bean3.prop['key']['msg'].text
Error |
No such property: text
Taking a closer look, bean3.prop['key']['msg'] ends up with not Message, but an instance of RuntimeBeanReference, with beanName=<msgbean>; so I tried invoking getSource() on it, returns null, which can happen according to docs (not ok for me)
Why does ref() not work for nested maps?
Alternate: Inline DSL Config
Something like this would be nice too; is this possible? Gave it a shot, returned a closure which, when executed, returns 'hello'; no surprise there, but not what I want; need the Message instance instead.
bean3(ConfigObj){
prop = [key:[msg:{Message -> {
text = 'hello'
}
]]
}
In order to get RuntimeBeanReferences unwrapped automatically at runtime the Map configured in the spring context needs to be a org.springframework.beans.factory.support.ManagedMap - the spring DSL automatically converts any map that contains a RuntimeBeanReference value into a ManagedMap but it only does this at one level deep, it doesn't look inside maps of maps etc.
A bit messy but you could declare the inner map as a top-level bean in its own right:
bean3Message(org.springframework.beans.factory.config.MapFactoryBean) {
sourceMap = [msg:ref('msgbean')]
}
bean3(ConfigObj){
prop = [key:ref('bean3Message')]
}
Now the maps both contain runtime references at the first level, so will both be "managed" correctly.
Another solution that works for me:
bean3(ConfigObj) {
prop = [key : ref(bean3Message(org.springframework.beans.factory.config.MapFactoryBean) {
sourceMap = [msg:ref('msgbean')]
})]
}
It's messy too, but you don't have to spread the map definition across multiple top-level beans.
I've tried this with list (using org.springframework.beans.factory.config.ListFactoryBean with the attribute sourceList instead of sourceMap).

Where does Grail's errors property come from?

Grails has a bug with regards to databinding in that it throws a cast exception when you're dealing with bad numerical input. JIRA: http://jira.grails.org/browse/GRAILS-6766
To fix this I've written the following code to manually handle the numerical input on the POGO class Foo located in src/groovy
void setPrice(String priceStr)
{
this.priceString = priceStr
// Remove $ and ,
priceStr = priceStr.trim().replaceAll(java.util.regex.Matcher.quoteReplacement('$'),'').replaceAll(',','')
if (!priceStr.isDouble()) {
errors.reject(
'trade.price.invalidformat',
[priceString] as Object[],
'Price:[{0}] is an invalid price.')
errors.rejectValue(
'price',
'trade.price.invalidformat')
} else {
this.price = priceStr.toDouble();
}
}
The following throws a null reference exception on the errors.reject() line.
foo.price = "asdf" // throws null reference on errors.reject()
foo.validate()
However, I can say:
foo.validate()
foo.price = "asdf" // no Null exception
foo.hasErrors() // false
foo.validate()
foo.hasErrors() // true
Where does errors come from when validate() is called?
Is there a way to add the errors property without calling validate() first?
I can't exactly tell you why, but you need to call getErrors() explicitly instead of accessing it as errors like a property. For some reason, Groovy isn't calling the method for it. So change the reject lines in setPrice() to
getErrors().reject(
'trade.price.invalidformat',
[priceString] as Object[],
'Price:[{0}] is an invalid price.')
getErrors().rejectValue(
'price',
'trade.price.invalidformat')
That is the easiest way to make sure the Errors object exists in your method. You can check out the code that adds the validation related methods to your domain class.
The AST transformation handling #Validateable augments the class with, among other things
a field named errors
public methods getErrors, setErrors, clearErrors and hasErrors
The getErrors method lazily sets the errors field if it hasn't yet been set. So it looks like what's happening is that accesses to errors within the same class are treated as field accesses rather than Java Bean property accesses, and bypassing the lazy initialization.
So the fix appears to be to use getErrors() instead of just errors.
The errors are add to your validateable classes (domain classes and classes that have the annotation #Validateable) dinamically.
Allowing the developer to set a String instead of a number doesn't seem a good way to go. Also, your validation will work only for that particular class.
I think that a better approach is to register a custom property editor for numbers. Here's a example with dates, that enable the transform of String (comming from the form) to Date with a format like dd/MM/yyyy. The idea is the same, as you will enforce that your number is parseable (eg. Integer.parseInt() will throw exception).
In your domain class, use the numeric type instead of String, so by code developers will not be allowed to store not number values.

Resources