'lateinit' modifier is not allowed on properties of primitive types - Kotlin - spring

I'm getting an error while trying to assign a environment variable value to a lateinit variable.
The error is "'lateinit' modifier is not allowed on properties of primitive types".
My application.properties (reading the environment variable)
my.property.from.properties.file=true
MyService class:
#Component
class MyService #Autowired constructor(
private val someService: SomeService) {
#Value("\${my.property.from.properties.file}")
private lateinit var myBooleanEnabled: Boolean
Assigning a value to it does not solve the problem. For example, with
private lateinit var myBooleanEnabled: Boolean = true
I get 2 errors:
'lateinit' modifier is not allowed on properties of primitive types
'lateinit' modifier is not allowed on properties with initializer
For what I read, I need a Delegated (https://kotlinlang.org/docs/reference/delegated-properties.html) but I could not grasp it fully. Also, I don't want to have to write another method to set the property if there is a "cleaner" solution.
Any ideas?

The simplest thing is to define myBooleanEnabled as nullable and remove lateinit
private var myBooleanEnabled: Boolean? = null
In this case, it will not be interpreted as a primitive boolean in bytecode.
However, in your case, I'd suggest a constructor injection.

You can use constructor injection as shown below. If you're using Spring 4.3+ you don't need the #Autowired annotation. Spring documentation has some guidelines on this:
https://docs.spring.io/spring/docs/current/spring-framework-reference/languages.html#injecting-dependencies
#Component
class MyService(
private val someService: SomeService,
#Value("\${my.property.from.properties.file}")
private val myBooleanEnabled: Boolean)

Related

Spring property binding with multiple separation

I have an application.property like this:
somevalue.api.test=something
somevalue.anotherproperty=stuff
I have made a configuration bean like this:
#Configuration
#ConfigurationProperties("somevalue")
public class SomeProperties {
#NotNull
private String apiTest;
#NotNull
private String anotherproperty;
}
Is it possible to refer to api.test like apiTest?
Mainly my issue is that I want to use the somevalue starting point for both property. I know if I don't separate with a dot the apiTest and I use it in this way somevalue.api-test I can refer to that with apiTest in my bean, but in my case it's not possible the renaming. So with dot separation can I achieve the same result or I should create two separate config bean, one refering to somevalue.api and the another only to somevalue?
If you can't rename the property then no, you can't reference it using String apiTest. You need an additional class as follows:
#Configuration
#ConfigurationProperties("somevalue")
public class GcssProperties {
#NotNull
private GcssApiProperties api;
#NotNull
private String anotherproperty;
}
public class GcssApiProperties {
#NotNull
private String test;
}
This should work.

validate ConfigurationProperties mapping

Is there a way to validate application.properties (or yml) if the properties match Java bean that it is mapped to via #ConfigurationProperties - so that if there is a typo in an attribute, exception will be thrown?
I tried using #Validated but it works only if every property has #NotNull annotation - but this is not exactly what I want to achieve... there may be some nullable properties in the config and I still want to "validate" them
I just spent 2 hours debugging an issue and I found out, the problem is that I misspelled an attribute name
e.g. application.yml
property1: 1
properrrrrty2: 2
#Configuration
#ConfigurationProperties
public class AppConfig {
private String property1;
private String property2; // <--- this property does not match due to typo in application.yml
}
A)
If you want to be sure that always a property exists then use #Validated with #NotNull for that property. #NotNull will complain if it does not find that property. You can still have the property there with an empty value if that is what you mean with nullable properties and NotNull will not complain.
You can't say I want it to be able to be nullable but also the validator should complain when that property is null.
So to sum things up.
#NotEmpty property must exist and also not have an empty value
#NotNull property must just exist. It does not care if it exists with an empty value.
That's why I insist you go with NotNull for your requirements.
B)
Also I can think of another way to handle that.
#Component
public class AppConfig {
#Value("${property1}")
private String property1;
#Value("${property2}")
private String property2;
}
Using injection with #Value, spring will fail to initialize the singleton AppConfig during application startup if some property with exactly the same name does not exist on properties file, therefore you will be informed that no property with that name exists and the application will not start up.
You can specify ignoreUnknownFields = false to ensure that no unknown properties are defined under the corresponding prefix. (docs):
Flag to indicate that when binding to this object unknown fields should be ignored. An unknown field could be a sign of a mistake in the Properties.
Borrowing from your example:
#Configuration
#ConfigurationProperties(prefix = "myapp", ignoreUnknownFields = false)
public class AppConfig {
private String property1;
private String property2;
}
This means myapp.property1 and myapp.property2 are allowed but not required to be set, so they remain nullable.
Any other set property with the myapp prefix (such as myapp.properrrrrty2=2) will cause a startup failure and the offending property name will be logged in the exception.

What does #get:NotNull mean in Kotlin?

I read a code generated by khipster and in one dataclass I found such fragment:
import javax.validation.constraints.NotNull
data class MyDTO(
var id: Long? = null,
#get: NotNull
var name: String? = null,
What does #get:NotNull annotation mean? As far as I understand #get means that I want to annotate the getter of name property and NotNull is a validation annotation which mean that the thing can't be set to null. But how the two work together? It doesn't make any sense to annotate getter with annotation which means this can't be set to null, because getter can't be set. It would make more sens to use NotNull annotation on setter.
#NotNull on a method means it can't return null. So in particular annotating a setter with it makes no sense; annotating the setter's parameter does.
If you use the decompile feature of IntelliJ ( please check this answer )
Kotlin Code:
#get: NotNull
var uid: String? = null
Decompiled Code:
import javax.validation.constraints.NotNull;
import org.jetbrains.annotations.Nullable;
#Nullable
private String uid;
#NotNull
#Nullable
public final String getUid() {
return this.uid;
}
public final void setUid(#Nullable String var1) {
this.uid = var1;
}
What does #get:NotNull annotation mean?
A quick answer: Please put #NotNull annotation on the top of the getter function
!! Please be aware that there is also #Nullable annotation added to the getter function because of the "?" at the end of the variable definition
As you notice from import it is added by IntelliJ
As detailed answer: I could redirect you to "Use-Site Target Declarations"
Bealdung
Blog post
Finally, I would like to express my experience on that, I had both #Nullable and #NotNull annotation on uid field (you could see on decompiled code), I could set that field to null

#Value to retrieve #Query value

Requirement
I've been asked to retrieve the value of a query annotation from a custom property stored in the application.properties file.
Prievious attempt
I tried to use #Value without success
#Repository
public interface FooRepository
extends JpaRepository<Foo, Long> {
#Value("${db.queries.distance}")
String distanceQuery; // this raises an error
#Query(nativeQuery = true, value =distanceQuery)
...
Eclipse marks "distanceQuery" and states
The blank final field distanceQuery may not have been initialized
And force me to initialize the variable as follows
public static final Double distanceQuery = null;
Unfortunately it's not what I want
Question
Is there a workaround to fix this issue?
Thank you in advance!
Instead of defining in a properties file, you can define query in a constants java file and can get value as below
#Query(nativeQuery = true, value =Constants.DISTANCE_QUERY)

Load Spring configuration in Hibernate entity

I want to configure Hibernate to set maximum length for a VARCHAR field. This maximum length is defined in a configuration file, and this configuration file is loaded by a class ValidationConfiguration.
This is my entity:
#Entity
public class MyEntity{
#Autowired /*I know this is bad practice,
I just want to let readers know that this object is instantiated.*/
private ValidationConfiguration config;
#Column(length = config.getMaxLength()) /*This gives a "java: element value
must be a constant expression"*/
String description;
//Get and set
}
Is this possible? If not, are there any workarounds?
From your code, it is clearly visible, that You are just defining the ValidationConfiguration by private ValidationConfiguration config;
But You are not Instantiating the Object.
So, Instantiate the object like new ValidationConfiguration() and since you haven't shared the code of ValidationConfiguration , i am predicting that your method is getMaxLength() not static. If the problem persists, do share the ValidationConfiguration code.
If that is a bean, then you can autowire it simply and don't create new instantiation.

Resources