I have two classes PaymentDetailsDTO
and UserDTO
. I want to serialize only the id field (a Long) of UserDTO
present inside PaymentDetailsDTO
. I am using Jackson annotations
@JsonIdentityInfo
and @JsonIdentityReference(alwaysAsId = true)
.
The problem is when the id inside UserDTO
is null, serialization ends with a null pointer exception (but works when the id is not null).
Not sure if that's how it's supposed to behave (if so, why) or am I missing something.
Instead what I expect is that if the id is null, just write null or don't include the key (depending upon whether the @JsonInclude
annotation allows null).
Following is the code in question.
PaymentDetailsDTO
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PaymentDetailsDTO {
private Long id;
@NotNull
@Builder.Default
private Long appId = 10151L;
// Represents user of payment system with information to find it on client
@JsonProperty("userId")
@JsonIdentityReference(alwaysAsId = true)
private UserDTO userDTO;
// Removed for normalization
@JsonProperty(access = Access.READ_ONLY)
private int reqId;
// @DecimalMin("1.00")
@NotNull
private double amountDue;
...
}
UserDTO
@Data
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
public class UserDTO {
private Long id;
// userId of the user on specific client
@NotNull
private Long clientUserId;
// clientName like "eYRC", "eYIC", "mooc"
@NotBlank
private String clientName;
@NotBlank
private String name;
private String emailId;
...
}
And this is the exception
com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.eyantra.payment.features.payment.data.dto.PaymentDetailsDTO["userId"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:730)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:166)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:4094)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3404)
at com.eyantra.payment.features.payment.data.dto.PaymentDetailsDTOTest.Serialize_IncludeOnlyUserID_ReturnsJson(PaymentDetailsDTOTest.java:27)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
...
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: java.lang.NullPointerException
at com.fasterxml.jackson.databind.ser.std.NumberSerializers$LongSerializer.serialize(NumberSerializers.java:194)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase._serializeWithObjectId(BeanSerializerBase.java:624)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:159)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:722)
... 57 more
Process finished with exit code 255