What does #get:NotNull mean in Kotlin? - validation

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

Related

Validate complex object on GET request

I'm trying to apply input validation on a complex parameter of a get request.
What I have:
data class FilterDTO (
#Valid
#NotNull
val id: Long? = null,
#NotNull
val code: String? = null
)
#Validated
#RestController
#RequestMapping("/foo")
class FooController {
#GetMapping
fun get(
#Valid filter: FilterDTO,
#Valid #NotNull #RequestParam("bar") bar: String?
) {
// ...
}
}
The above endpoint validates correctly the #NotNull on the bar parameter but it seems to ignore the validation on the complex FilterDTO object.
I have tried:
Adding #Valid on FilterDTO's properties (even with Kotlin's #field: and #get:)
Adding #Validated (??) on the FilterDTO whole class
Couldn't make it work.
Is it possible to have a complex get parameter validated?
Thanks
Just found the problem. For anyone getting here, I should be annotating with #field: the validations I want. So simply changing my DTO to this worked:
data class FilterDTO (
#field:NotNull
val id: Long? = null,
#field:NotNull
val code: String? = null
)

#RequestBody and #Valid not validating empty/blank string field in kotlin object

My request is parsed into the Kotlin object that is the request body in the controller. Currently, if the fields are null - a validation exception is thrown which is exactly what i want.
However, I am using #NotBlank and this doesn't seem to validate the way it's meant to against "" or " ". What am I missing?
#NotEmpty also doesn't check against "". They both seem to just check against null, which is only part of what I'm looking for.
Essentially I am looking for the request not to be null, the list field not to be null, the inner BumblebeeEvent in the list not to be null, and each Event to have it's fields validated (e.g. not null, "" or " ").
Here is my controller:
#Controller
class BumblebeeEventController {
#PostMapping("/publish")
fun eventIntake(#RequestBody #Valid payload: BumblebeeEventList) : ResponseEntity<String>{
return ResponseEntity("Published ${eventList.size} event(s) successfully",HttpStatus.OK)
}
}
class Event(#NotBlank val localTime: String){}
class BumblebeeEvent(#NotNull val event: Event)
class BumblebeeEventList(#NotNull val events: List<BumblebeeEvent>){}
Thanks in advance
try with
class Event(#NotBlank val localTime: String){}
class BumblebeeEvent(#NotNull #Valid val event: Event)
class BumblebeeEventList(#NotNull #Valid val events: List<BumblebeeEvent>){}
You must indicate that the validation must go also in the nested object

Jackson ObjectMapper ignores JsonInclude.Include.NON_NULL

I have a project in Spring Boot 1.5.2. For some reason, I haven't been able to make the ObjectMapper ignore null fields during serialization. Here's the setup:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class CustomerInfo{
private Long customerId;
private String fullName;
//some more fields
//getters and setters
}
#Service
public class ObjectMapperTester{
#Autowired
private ObjectMapper objectMapper;
public void test(){
CustomerInfo ci = new CustomerInfo;
ci.setFullName("Foo");
objectMapper.writeValueAsString(ci);
//I get JsonMappingException here
}
}
Up until now, I've always used #JsonInclude(JsonInclude.Include.NON_NULL) annotation with my classes to ignore null fields. That works perfectly well when I return any kind of object in RestController methods, so I don't see any null fields in the response output. But this one resists working. I get an exception when trying to writeValueAsString when the customerId field is null. The ObjectMapper is trying to get customerId value through getter, which in turn does the following:
//In fact compiler transforms the getter to be so, otherwise I just return the customerId.
return this.customerId.longValue();
And that of course throws NullPointerException.
I've tried instructing the mapper manually to ignore null fields during serialization this way:
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
But that doesn't help either. Any other ideas?
UPDATE
I've sort of figured out the problem. In fact, the type of the customerId field used to be the primitive long. Then I changed it to Long without using the IDE refactoring, which left the getter like this:
public long getCustomerId(){
return customerId;
}
And the compiler converted it to
public long getCustomerId(){
return customerId.longValue();
}
After fixing the getter return type to Long, the problem got solved and I indeed don't get the customerId field in the output. But the getCustomerId() method is still invoked. That's why I said sort of. Why does the mapper need to invoke the getter if it's going to ignore it? I've tried removing the class-wide annotation and added it to the fields. But still, the getter method gets invoked.

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

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)

Spring WebClient setting some fields to null when they are not null in the response body

I have domain class
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Data;
#Data
#Document
public class Bar {
#Id
private String id;
private List<String> owners;
private List<String> cFeatures;
private Integer age;
private String color;
}
I am using below code to invoke API to get data in Bar object:
import org.springframework.web.reactive.function.client.WebClient;
Mono<Bar> prop = webClient.get()
.uri("/bars/"+id)
.header("Authorization", "Bearer " + access_token)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Bar.class).log("find by id")
The problem is that I get cFeatures as null even though original JSON response
has:
"cFeatures":["custom feature one", ""]
but owners list gets correct value even though owners also has empty string value in the list (not sure if thats the source of this bug)
so Bar object has:
cFeatures: null
Is this a bug in Webclient or am I missing something ? I spent whole day on this but no fix yet.
The problem was with lombok. Lombok was generating setter method:
setCFeatures
but jackson expects setter:
setcFeatures which it does not find and hence null value for cFeatures.
It can be helpful if you make sure your POJO has the correct annotation style. For example, use jsonscheme2pojo.org and choose "Json" as your source type and "Jackson 2.x" as your annotation style. That should make the problem disappear. I was stuck at first by the same problem because I used a Gson-annotated POJO.

Resources