Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lombok @NonNull null check enforcement not working with Jackson deserialization

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;
  }

}

like image 953
amulllb Avatar asked Feb 19 '19 19:02

amulllb


2 Answers

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 {
    }
  }

like image 173
amulllb Avatar answered Sep 22 '22 11:09

amulllb


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;
        }
    }
}
like image 41
LppEdd Avatar answered Sep 20 '22 11:09

LppEdd