0

I have JSON:

{"name": "testname"}

And java class with thousands of properties:

public class Ui {
    public String name;
    public String title;
}

During deserialization process Jackson or Gson should return null or throw exception because title property does not exist in given JSON. How to force this behaviour?

Example jackson:

ObjectMapper objectMapper = new ObjectMapper();
Ui ui = objectMapper.readValue("{\"name": "testname\"}", Ui.class);
System.out.println(ui == null); // should be true
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
Elron
  • 511
  • 4
  • 14

2 Answers2

0

Using gson it works with no issues, it will only set the value for name.

public class SO_50688866 {

    public static void main(String ... args) {
        String json = "{\"name\": \"testname\"}";

        Ui ui = new Gson().fromJson(json, Ui.class);

        System.out.println(ui.name);
    }

    public static class Ui {
        public String name;
        public String title;
    }
}

EDIT I

I see you wanted exactly the opposite :)

I don't see that gson support this natively, but I found this answer that could meet your needs: Java to Json validation using GSON

Also I came up with this class that can do a checking of the fields after deserializing the json string. It has a few caveats like if there is a missing primitive, like an int, it will be initialized to zero so it won't be null. Or if effectively if the fields comes as null in the json. But perhaps you can adapt it for your needs, like adding a method which takes the names of the fields to check.

public static class CheckNullFields<T>{
        @SuppressWarnings("unchecked")
        public void check(T obj) throws IllegalAccessException{
            Class<T> clazz = (Class<T>) obj.getClass();
            Field [] fields = clazz.getDeclaredFields();
            for(Field field : fields) {
                if(field.get(obj) == null) {
                    throw new RuntimeException("Null value in field " + field.getName());
                }
            }
        }
    }

You would use it like this:

String json = "{\"name\": \"testname\"}";       
try {
    Ui ui = new Gson().fromJson(json, Ui.class);
    new CheckNullFields<Ui>().check(ui);
    System.out.println(ui.name);
    System.out.println(ui.title);
}catch(Exception e) {
    e.printStackTrace();
}            
Juan
  • 5,525
  • 2
  • 15
  • 26
0

You have to create a constructor which requires all needed properties:

class Ui {
    private String name;
    private String title;

    @JsonCreator
    public Ui(@JsonProperty(required = true, value = "name") String name, @JsonProperty(required = true, value = "title") String title) {
        this.name = name;
        this.title = title;
    }
//....
}

And the same example gives:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Missing required creator property 'title' (index 1)
 at [Source: {"name": "name"}; line: 1, column: 16]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)

Also take a look on this question and answers: Jackson @JsonProperty(required=true) doesn't throw an exception

EDIT
If you have thousands of properties (which is weird but possible) the simple solution is to deserialize JSON to Map and check it's size. In case size is different then expected you can throw new exception or return null.

The best way I think, it would be generate JSON Schema for your JSON and try to validate it first.

Michał Ziober
  • 37,175
  • 18
  • 99
  • 146