I have a simple case where I want to enforce null check on values found in JSON string when converting the JSON string to POJO using Jackson (2.8) and Lombok (latest version) in Java8. But it looks like @NonNull
doesn't throw exception when the pojo is created using ObjectMapper.convertValue
, but it works fine when pojo is created normally using builder pattern"?
here is my case:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Lombok;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class LearnJackson {
public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static void main(final String[] args) throws IOException {
learnToConvertJsonToSimplePojo();
}
public static void learnToConvertJsonToSimplePojo() throws IOException {
String jsonString = "{}";
JsonNode node = OBJECT_MAPPER.readValue(jsonString, JsonNode.class);
// this is supposed to throw NullPointerException
MySimplePojo o = OBJECT_MAPPER.convertValue(node, MySimplePojo.class);
log.info("o.getVar1: {}, o.getVar2: {}", o.getVar1(), o.getVar2()); // prints null
// MySimplePojo.builder().build(); // this throws NullPointerException correctly
}
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public static class MySimplePojo {
@NonNull
private String var1;
@NonNull
private List<String> var2;
}
}
Found it. fixed by using JsonDeserialize
annotation
@NoArgsConstructor
@AllArgsConstructor
@Builder(builderClassName = "Builder", toBuilder = true)
@Data
@JsonDeserialize(builder = MySimplePojo.Builder.class)
public static class MySimplePojo {
@NonNull
private String var1;
@NonNull
private List<String> var2;
@JsonPOJOBuilder(withPrefix = "")
public static class Builder {
}
}
I see you found an apparent solution. Btw, you could have solved this by setting the setter
visibility on ObjectMapper
. See a complete example. As Lombok generates bytecode, the null-checking is inside the setter, so you can tell Jackson to use them.
public class Main {
public static void main(final String[] args) throws IOException {
final String v = "{\"name\":\"YourName\",\"surname\":\"YourSurname\"}";
final ObjectMapper mapper = new ObjectMapper();
mapper.setVisibilityChecker(
mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withGetterVisibility(Visibility.PUBLIC_ONLY)
.withSetterVisibility(Visibility.PUBLIC_ONLY)
);
final JsonNode jsonNode = mapper.readValue(v, JsonNode.class);
System.out.println(jsonNode);
final User user = mapper.convertValue(jsonNode, User.class);
System.out.println(user);
}
private static class User {
private String name;
private String surname;
public String getName() {
return name;
}
public void setName(final String name) {
if (name == null) {
throw new NullPointerException();
}
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(final String surname) {
if (surname == null) {
throw new NullPointerException();
}
this.surname = surname;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With