I am sending a POST request with the Sample JSON request body:
"name" : "jeff",
"country" : "US",
"content" : {
"subject" : "Test-Subject",
"body" : "Test-body"
}
The class that is this JSON is deserialized into:
#Introspected
#Builder
#Data
public class Template<T extends Content> {
String name;
String country;
T content;
}
Content looks like this:
#Introspected
#Superbuilder
#Getter
#EqualsAndHashCode
#NoArgsConstructor
#AllArgsConstructor(onConstructor_ = #JsonCreator)
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, property="content")
#JsonSubTypes(#JsonSubTypes.Type(value = EmailContent.class, name="EmailContent"))
public abstract class Content {
private String body;
}
This is what I want T content to deserialize into:
#Introspected
#Superbuilder
#Getter
#EqualsAndHashCode(callSuper = true)
#NoArgsConstructor
#AllArgsConstructor(onConstructor_ = #JsonCreator)
public class EmailContent extends Content {
private String subject;
}
I have everything working in Template EXCEPT the generic content type which is giving me trouble no matter what JsonTypeInfo I use. I am trying to deserialize it into an EmailTemplate class. I have other classes extending from content so I am not looking to use #JsonDeserialize.
Solved...it was due to using graalVM which supports partial reflection. I fixed this by adding the #ReflectiveAccess annotation alongside lombok's #Jacksonized annotation for deserializing builder types.
In Spring boot application with Lombok, I have pojo class AccountDTO
#Data
#Builder
#Accessors(fluent = true)
public class AccountDTO implements Serializable {
private String identification;
}
My project compiles fine. However, it throws an exception in its execution
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No
serializer found for class AccountDTO and no properties discovered to create
BeanSerializer
if I removed the annotation #Accessors(fluent = true), then it will work fine without any problems.
How can i make Lombok #Accessors(fluent = true) and Jackson work together ?
I stumbled on this question recently while encountering the same problem and the solution for me was to add and explicit #JsonProperty annotation on the getter generated by Lombok using:
#Getter(onMethod = #__(#JsonProperty)).
In your case, the class would look like this:
#Data
#Builder
#Accessors(fluent = true)
#Getter(onMethod = #__(#JsonProperty))
public class AccountDTO implements Serializable {
private String identification;
}
I have two classes OAuth2Token and CachedOAuth2Token that extends a class called AbstractOAuth2Token.
AbstractOAuth2Token.java
#SuperBuilder
#Jacksonized
#JsonSubTypes({
#JsonSubTypes.Type(value = OAuth2Token.class),
})
#Getter
#Setter
#ToString
public abstract class AbstractOAuth2Token {
#JsonProperty("access_token")
private String accessToken;
#JsonProperty("token_type")
private String tokenType;
}
OAuth2Token.java
#Getter
#Setter
#SuperBuilder
#ToString(callSuper = true)
#JsonTypeName("OAuth2Token")
#Jacksonized
public class OAuth2Token extends AbstractOAuth2Token {
#JsonProperty("expires_in")
private int expiresIn;
}
CachedOAuth2Token.java
#Getter
#Setter
#SuperBuilder
#ToString(callSuper = true)
public class CachedOAuth2Token extends AbstractOAuth2Token {
private LocalDateTime expirationDate;
}
Unfortunately my Maven project doesn't build because AbstractOAuth2Token.java: Builders on abstract classes cannot be #Jacksonized (the builder would never be used).
Even if the code works as expected if the AbstractOAuth2Token isn't abstract, then I'm able to create an instance of it using the builder which indeed isn't what I want. Its constructor is protected, so no problem there.
The idea is that I want AbstractOAuth2Token to be abstract without losing any fuctionality in the children. I'm a fan of Lombok, so I want to be able to use the autogenerated builders but together with Jackson.
It's a Wildfly 11 project with Lombok 1.18.16
How can I solve this issue?
Don't add #Jacksonized to your abstract base class. Non-#Jacksonized #SuperBuilders are compatible with #Jacksonized #SuperBuilders. As Jackson will never use AbstractOAuth2Token's builder directly, there is no need to configure it for Jackson explicitly.
I have the following class:
public class Person {
#JsonProperty(access = Access.READ_ONLY)
private String id;
#JsonProperty(access = Access.READ_WRITE)
private String name;
// constructors and getters/setters are omitted
}
When I use it like this:
#RestController
public class PersonEndpoint {
#PostMapping("/")
public Person savePerson(#RequestBody Person person) {
System.out.println(person);
return person;
}
}
Jackson fails when deserializing the object:
WARN MappingJackson2HttpMessageConverter : Failed to evaluate Jackson deserialization for type [[simple type, class com.mycompany.myapp.model.Person]]: com.fasterxml.jackson.databind.JsonMappingException: Could not find creator property with name 'name' (in class com.mycompany.myapp.model.Person)
There is no such problem when changing Jackson's version to 2.6.7.
Is this a bug or am I doing something wrong?
I'm rewriting some messy code that manages a database, and saw that the original programmer created a class mapped to the database like so:
(I've removed unnecessary code that has no purpose in this question)
#Entity
#Data
#EqualsAndHashCode(callSuper = false, of = { "accessionCode", "header", "date" })
#SuppressWarnings("PMD.UnusedPrivateField")
public class PDBEntry implements Serializable {
#Id
#NaturalId
#NotEmpty
#Length(max = 4)
private String accessionCode;
#NaturalId
#NotEmpty
private Date date;
#NaturalId
// We allow for the header to be 'null'
private String header;
private Boolean isValidDssp;
#Temporal(TemporalType.TIMESTAMP)
private Date lastUpdated = new Date(System.currentTimeMillis());
protected PDBEntry(){}
public PDBEntry(String accessionCode, String header, Date date){
this.accessionCode = accessionCode;
this.header = header;
this.date = date;
}
}
I am still a beginner at Hibernate and using Lombok, but wouldn't this do the same thing and wouldn't Lombok automatically create the needed constructor for you?
#Entity
#Data
#SuppressWarnings("PMD.UnusedPrivateField")
public class PDBEntry implements Serializable {
#Id
#NaturalId
#NotEmpty
#NonNull
#Length(max = 4)
private String accessionCode;
#NaturalId
#NotEmpty
#NonNull
private Date date;
#NaturalId
// We allow for the header to be 'null'
private String header;
private Boolean isValidDssp;
#Temporal(TemporalType.TIMESTAMP)
private Date lastUpdated = new Date(System.currentTimeMillis());
}
Also, the original programmer of this code says he allows for the header to be 'null', yet he explicitly created a constructor that needs a value for header. Am I missing something or is this a bit contradictory?
Have a look at #NoArgsConstructor, #RequiredArgsConstructor, #AllArgsConstructor.
The constructor behavior of #Data is like #RequiredArgsConstructor:
#RequiredArgsConstructor generates a
constructor with 1 parameter for each
field that requires special handling.
All final fields get a parameter, as
well as any fields that are marked as
#NonNull that aren't initialized where
they are declared.
Given that none of your fields are either final or #NonNull, this will result in a no-argument constructor. However, this is not the most expressive way to achieve this behavior.
What you'll probably want in this case is a #NoArgsConstructor (optionally combined with a #AllArgsConstructor), to clearly communicate the intended behavior, as is also indicated in the documentation:
Certain java constructs, such as
hibernate and the Service Provider
Interface require a no-args
constructor. This annotation is useful
primarily in combination with either
#Data or one of the other constructor
generating annotations.
That bit is contradictory you're right. I've not used Lombok before but with hibernate if you want to be able to create a bean and persist you need the default constructor as given above as far I was aware. It uses Constructor.newInstance() to instantiate new objects.
Here is some hibernate documentation which goes into more detail.
Hibernate Documentation
If you are using #Data with a #NonNull field and still want a noargs-constructor, you might wanna try to add all 3 annotation together
#NoArgsConstructor
#RequiredArgsConstructor
#AllArgsConstructor
Apparently an old intelliJ bug which I did replicate in Eclipse Kepler and lombok v0.11.4
#NoArgsConstructor,
#RequiredArgsConstructor,
#AllArgsConstructor
Generate constructors that take no arguments, one argument per final / non-null field, or one argument for every field. Read this lombok-project
#Data
#RequiredArgsConstructor /*Duplicate method Someclass() in type Someclass*/
#NoArgsConstructor(access=AccessLevel.PRIVATE, force=true) /*Duplicate method Someclass() in type Someclass*/
#Entity
public class Someclass {
#Id
private String id;
private String name;
private Type type;
public static enum Type { X , Y, Z}
}
Fixed it by making member variables final
#Data
#RequiredArgsConstructor
#NoArgsConstructor(access=AccessLevel.PRIVATE, force=true)
#Entity
public class Someclass {
#Id
private final String id;
private final String name;
private final Type type;
public static enum Type { X , Y, Z}
}