Spring boot `#Value` is always zero, despite default - spring

I am using
#Service
public class Foo
{
#Value ("${this.does.not.exist: 10}")
private static int bar;
}
Because the value does not exist in the configuration, I was expecting bar to have value 10 but it is 0.
I also tried #Value ("${this.does.not.exist: #{10}}") as per this answer, it's still zero.
Why didn't this work?

I omitted the static keyword in the OP (now edited) and that was the fault.

The following code works for me:
#Service
public class MyService {
#Value("${this.does.not.exist: 10}")
private int val;
With the last version of spring-boot (and it should with any other version basically).
So the issue must be elsewhere.
Please check the following:
Make sure that Foo is indeed managed by spring (it finds it in the component scanning process). Otherwise no-one will inject the value.
Make sure that you're not trying to read the value from constructor or something:
In spring it first creates the object (and at that moment the value of the field is 0 indeed) and only then triggers a bean post processors for injecting values, autowiring, etc.

Related

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.)

What is best way to read properties from application.properties?

So, I have created configuration class with #Component and #ConfigurationProperties(prefix = "properties"), set default values for some of my application properties and changed some of them in application.yaml/properties
Now, I know I can access it using #Value("properties.*") but it can lead to having many variables which will be repetitive in another classes too
#Value("${properties.user-id-length}")
private int userIdLength;
I also can access my configuration class (as it is Spring Bean) through #Autowire it to variable in every single class I need make use of it. The cons for that is that more complex configuration class containing inner classes, which contain inner classes etc. will not look too great in code
#Autowired // Not recommended, but for simplicity
private MyConfigurationClass myConfigurationClass;
// some method
int userIdLength = myConfigurationClass.getUserIdLength();
String serverLocation = myConfigurationClass.getAmazon().getSes().getSenderEmailAddress()
Another way is to create additional helper class like Constant and set needed static fields with #Value but it can be time consuming and I'm not sure it is THAT different from first solution
public static int USER_ID_LENGTH;
#Value("${properties.user-id-length}")
private void setUserIdLength(int length){
Constant.USER_ID_LENGTH = length;
}
So, which aproach is the best? Or are there another ways to do that?
Well, not much of the feedback but in the meantime I figured out that using both #Value and #ConfigurationProperties leads to some problems.
MyProp.class
#Getter
#Setter
#ConfigurationProperties(prefix = "prop")
public class MyProp{
private String default = "Default String"
}
SomeClass.class
#Component
public class SomeClass.class{
#Value("${prop.default}")
public String message;
}
Above example causes Exception BeanCreationException
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someClass': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'prop.default' in value "${prop.default}"
Explanation to this can be found here in #davidxxx's post and occurs unless we set all fields in application.properties. Because of that my first proposal cannot be done in the terms I thought it can be done and explanation was not easy to find, so I hope it will help someone one day.

Is it possible to pass a key as default value in #Value annotation of Spring

I have a situation where we are reading one property from properties file and now we have been asked to point to another endpoint and for some time we have to manage both these endpoints unless this new endpoint is tested and validated throughly.
I wanted to handle this situation by adding this newer property in properties file and in the actual class were we are reading this property with #Value Annotation the old one can be passed as default with its key as value something like
#Value("${backend.endpoint:${older.endpoint}}"). is it possible ?
Yes you can do it, I have tested it, my sample code
code:
#Value("#{ ${spring.myapp.usenewval} ? '${spring.myapp.newval}' : '${spring.myapp.oldval}}'}")
private String message;
Properties
spring:
myapp:
usenewval: false
newval: hello
oldval: world.....
You can always set spring.myapp.usenewval from outside like
java -jar -Dspring.myapp.usenewval=true myapp.jar
You can use it like this. (I've personally never done it, so forgive me if I'm wrong)
#Configuration
public class PropertyConfiguration {
#Value("{'${backend.endpoint:${older.endpoint:}}'}")
private String myValue;
}
This #Value annotation uses backend.endpoint, if it is provided and defaults to older.endpoint, if backend.endpoint is not provided.
If neither is provided, the property must be set null.
There are other ways to handle this as well. Probably, use #Value for both the property and handle in code.
Here is quick fix for you. Kindly refer it.
You can set default value to #Value annotation of spring as following.
#Controller
#RequestMapping(value = "/your path")
public class MyController {
#Value("${key:true}")
private boolean booleanWithDefaultValue;
}
Here, I take Boolean variable and set default value as "true".
Hope this solution works.

Lombok Builder with defaults in Spring Data

I have the following (simplified) class:
#Entity
#Data
#Builder
#NoArgsConstructor // #Builder creates the all-args version but I need this one elsewhere.
#AllArgsConstructor(access = AccessLevel.PRIVATE) // Having #NoArgsConstructor disables the #AllArgsConstructor needed by #Builder unless I have this explicitly applied
public class MyClass {
// ...
#Builder.Default
private String foo = "Some Default Value"
// ...
}
This works fine in the general case, but a problem comes about when this Entity gets built by Spring (specifically Spring Data Repository in response to a REST request to create it). Spring sees the all-args constructor and uses it, setting a null value for foo (in this case it wasn't set in the POST data) and I end up with a null value for foo instead of the expected "Some Default Value". The #Builder.Default.
It does not work to simply create the setter and prevent nulls. I could write out the AllArgsConstructor explicitly, but that (somewhat) defeats the purpose of Lombok to some extent. Not a horrible solution, but not ideal.
Can anyone think of any workarounds for this?
I know you can specify default values with the non-lombok default values. I haven't tried it with this particular case, but its worth a shot.
#Value("#{prop['my.property'] ?: 12345}")
Maybe you should try using the RequiredArgs Constructor which only specifies a constructor that uses "one argument per final / non-null field" and that won't override the var.
https://projectlombok.org/features/constructor
I was able to work around this using a PrePersist annotation in my model class. With the PrePersist I can make sure that null values get their defaults set regardless of when they were set to null, or by whom. Not truly a fix for this, but something I should probably be doing anyway so it's an acceptable workaround.

Why is the Java 8 Optional class final? [duplicate]

I was playing with the following question: Using Java 8's Optional with Stream::flatMap and wanted to add a method to a custom Optional<T> and then check if it worked.
More precise, I wanted to add a stream() to my CustomOptional<T> that returns an empty stream if no value is present, or a stream with a single element if it is present.
However, I came to the conclusion that Optional<T> is declared as final.
Why is this so? There are loads of classes that are not declared as final, and I personally do not see a reason here to declare Optional<T> final.
As a second question, why can not all methods be final, if the worry is that they would be overridden, and leave the class non-final?
According to this page of the Java SE 8 API docs, Optional<T> is a value based class. According to this page of the API docs, value-based classes have to be immutable.
Declaring all the methods in Optional<T> as final will prevent the methods from being overridden, but that will not prevent an extending class from adding fields and methods. Extending the class and adding a field together with a method that changes the value of that field would make that subclass mutable and hence would allow the creation of a mutable Optional<T>. The following is an example of such a subclass that could be created if Optional<T> would not be declared final.
//Example created by #assylias
public class Sub<T> extends Optional<T> {
private T t;
public void set(T t) {
this.t = t;
}
}
Declaring Optional<T> final prevents the creation of subclasses like the one above and hence guarantees Optional<T> to be always immutable.
As others have stated Optional is a value based class and since it is a value based class it should be immutable which needs it to be final.
But we missed the point for this. One of the main reason why value based classes are immutable is to guarantee thread safety. Making it immutable makes it thread safe. Take for eg String or primitive wrappers like Integer or Float. They are declared final for similar reasons.
Probably, the reason is the same as why String is final; that is, so that all users of the Optional class can be assured that the methods on the instance they receive keep to their contract of always returning the same value.
Though we could not extend the Optional class, we could create our own wrapper class.
public final class Opt {
private Opt() {
}
public static final <T> Stream<T> filledOrEmpty(T t) {
return Optional.ofNullable(t).isPresent() ? Stream.of(t) : Stream.empty();
}
}
Hope it might helps you. Glad to see the reaction!

Resources