Kotlin init not picking up value from #Value - spring

I want to initialise a member variable from a value I pick from ENV but it is not available in init block as it gets picked up after object initialisation
private lateinit var needValueHere: String
#Value("\${CLIENT_ID:NA}")
private val CLIENT_ID: String = ""
init {
this.needValueHere = this.CLIENT_ID
}
This is a simplified version of the actual problem.
I have verified the value is available in the member functions.

Your object is constructing by the following way:
Create object (e.g. call constructor)
Via reflection: put dependencies (e.g. fill values under #Autowired, #Value and other annotations).
Your init block is part of constructor, e.g. all Spring-related items aren't initialized here.
How you can fix this:
Extract properties to the type-safe configuration (please see official docs here)
Use notation of class like below.
Create private lateinit var field and don't call it until Spring initialization finishing (this is useful for integration tests, e.g. test methods start only after full warmup). Another option - use kotlin lazy notation. However whole this item couldn't be named as "good code".
class MyService(#Value("\${CLIENT_ID:NA}") private val needValueHere: String) {
/* */
}

Related

Spring calls noargs constructor on java record for #ConfigurationProperties

I'm pulling my hair out here. I want to use a Java record for my #ConfigurationProperties, providing default values to unspecified config properties. Here is a very simple example:
#ConfigurationProperties(prefix = "myconfig")
public record LoggingProperties (
String whatever,
String somethingToDefault
) {
public LoggingProperties(String whatever, String somethingToDefault) {
this.whatever = whatever;
this.somethingToDefault = somethingToDefault;
}
public LoggingProperties(String whatever) {
this(whatever, "whatever was specified, but not somethingToDefault");
}
public LoggingProperties() {
this("neither was specified", "neither was specified");
}
}
It seems, if I declare a noargs constructor, spring always calls that, regardless of what I actually have in my config file (application.yml)
The above will yield an instance, that when logged shows:
LoggingProperties[whatever=neither was specified, somethingToDefault=neither was specified], despite the fact that my config WAS specified.
If I delete the no-args constructor, I get an exception about No default constructor found;
If I add #ConstructorBinding to the allargs constructor I get:
LoggingProperties[whatever=value from file, somethingToDefault=null]. i.e. it just called the annotated constructor, ignoring the one with 1 arg (despite that prop being declared in my yml).
I'm at a loss... Is this even possible?
EDIT: in my application.yml I have:
myconfig:
whatever: "value from file"
Praise the lord for documentation (it pays to read it)
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#features.external-config.typesafe-configuration-properties.constructor-binding
Default values can be specified using #DefaultValue on a constructor parameter or, when using Java 16 or later, a record component. The conversion service will be applied to coerce the String value to the target type of a missing property.
So it seems I can skip the constructor mess, and just annotate the record fields with a #DefaultValue(value = "whatever default"), like so:
#ConfigurationProperties(prefix = "someprefix")
#ConstructorBinding
public record MyRecord (
#DefaultValue(value = "true")
boolean someProperty,
) {}

What 'final' keyword next to the field stands for?

In a legacy code, I'm working with, I found the following thing:
#Autowired
final lateinit var controller: CustomController
what does this final keyword mean here?
In a Kotlin documentation I found a short description about final keyword that is blocking overriding of the methods in open classes but no information about fields. Also - the class within which I found the line is not open
A final property or a method in Kotlin prevents overriding of the field / method. That being said, Kotlin by default considers a property or a method/function to be final unless specified by the keyword open. In your case, the final keyword is redundant.
Here's a small demo test case to illustrate the same.
open class Parent {
open val someValue = 0
final val otherValue = 13 // redundant modifier 'final' warning in Android Studio
}
class Child : Parent() {
override val someValue = 5
// override val otherValue = 19 // compile error
}
There is an interesting problem called Fragile Base Class in OOP and why some languages like Kotlin prefer final by default.
What you have there is a property, not a field.
It looks just like a field, as it would in Java; but in Kotlin, it actually defines a public getter method, a public setter method, and a private backing field*.
So the final modifier applies to the accessor methods, preventing those from being overridden in a subclass.  (As you say, the backing field itself can't be overridden anyway.)
As Siddharth says, final is the default in Kotlin, so you usually wouldn't need to specify it, though there are a few situations in which it would be needed — e.g. if it were already overriding something, or you were using the all-open or kotlin-spring compiler plug-ins.  (The use of #Autowired suggests that this is a Spring module, which probably explains why final is needed here.)  In any case, your IDE would probably indicate where it's not needed, e.g. by showing it greyed-out.
(* Only the getter is necessary; the setter isn't generated for a val, and the backing field isn't generated if you override the accessor(s) and they don't refer to it.)

Using #Value annotation with Spring and SPeL

I am trying to find a way to do the following in my spring boot 1.5 application.
I have a variable who's value is dynamic meaning it comes in from an external system.
String name = "abc"; //gets set externally
I want to try and use the name's value to lookup my property file and see if there is a matching property defined. something like..
#Value("#{myClassName.name.concat('something')}")
String propertyValue;
Now my application.property file has the following property set
assume name has the value "abc"
property file contents:
abc.something:abcValue
Now, when i try to access the value of the variable propertyValue it gets set to the value abc.something and not abcValue.
I probably think I cannot use #Value with #{} to get to that, I was wondering if there was a way to to use #{} inside ${} so that I goes and fetches the property value after calculating the name of the property using #{}.
Let me know if you need more details please.
A bean life-cycle requires properties to be resolved at compile time. So, #Value requires constant parameter.
You can use Environment bean to access your properties programmatically.
import org.springframework.core.env.Environment;
#Service
public class Serivce {
#Autowired
private Environment environment;
public String getProperty(final String keyPart) {
String key = "build.your." + keyPart;
return environment.getProperty(key)
}
}
By the way you can use #('${spring.some.property}') in SpEL to access placeholder.
// This is valid access to property
#Value("#('${spring.some.property}')")
private String property;

Spring return dynamic instance based of String value

Java Spring question:
I have a interface MyInterface with one method
void exec (String str);
I have many implementation of MyInterface, say Oneimpl, anotherimpl yetanotherimpl...and so on and can keep adding new implementations.
how do I obtain an instance of a specific implementation using just the name of the implementing class passed as a STRING value , say "someRandomImpl"
The code should be dynamic and can provide a instance of new implementations without code change.
implements ApplicationContextAware
it will autowired ApplicationContext object
use the object like
context.getBean(beanName)
then you get the bean

#Properties in OSGi

I was writting one service and observed #Property we can define also inside the service as in my below code :
#Component(metatype = true, immediate = true, description = "Demo Service to test")
#Service(value = DemoService.class)
#Properties({
#Property(name = "testprop" , value = "This is Test Property")
})
public class DemoServiceImpl implements DemoService {
#Property(name = "localprop", value = "Local Value")
#Activate
public void activate(ComponentContext ctx)
{
String testprop = (String)ctx.getProperties().get("testprop");
String localprop = (String)ctx.getProperties().get("localprop");
}
}
Both properties display in felix console & accessible inside my service. So what creates the difference to declare them inside component or outside. One i saw we can not use #Properties inside component. But not sure what makes them functionally different from each other & when to use each.
I guess you talk about the felix annotations.
You can use #Property in front of any method or member variable. However, that does not mean that the method would be called or the variable would be set. The only good thing in it is that if you have a specific variable that will hold the value of the property (by assigning it in the activate method), your class can be more self explaining based on the annotations.
In the other hand, you can list properties within the #Properties annotation. I prefer this way as in this case I can define exactly the order of properties how they should appear in the generated metatype xml file (and on the webconsole).
It can also happen, that the configuration property is not assigned to any member variable, it is used only in the activate method. In that case the best place to define it is within the #Properties annotation in front of the class.

Resources