0

I'm struggling with a problem: is it possible to configure Jackson to throw an error if no field is mapped?

Example: deserializing an empty object("{}") or without any of the fields that the target object contains.

4EACH
  • 2,132
  • 4
  • 20
  • 28
  • The solution may depend on Jackson version that you use. Have a look here for examples/discussion on different versions and alternative solutions: https://stackoverflow.com/questions/18320731/jackson-jsonpropertyrequired-true-doesnt-throw-an-exception – Nestor Milyaev May 20 '22 at 11:24

3 Answers3

0

I always check if some fields is null after get Jackson deserialize api. But i think you can extends Jackson deserializer to rewrite deserialize method to achieve your purpose.

Wrynn
  • 1
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 20 '22 at 18:05
0

if all from as set of fields are required:

If using the constructor for deserializing the object you can use required from @JsonProperty annotation.

For example, for a class Foo, a field name is required:

class Foo
{
    String name;
    Integer number; 
    
    @JsonCreator
    public Foo(
       @JsonProperty(value = "name", required = true) String name,
       @JsonProperty(value = "number") Integer number)
    {
        this.name = name;
        this.number = number;
    }
    // ... more methods ...
}

When trying to deserialize from an JSON with no name property, it will fail with MismatchedInputException:

objectMapper.readValue("{}", Foo.class); // FAILURE

Note that if JSON object explicitly sets the field as null, it will succeed:

objectMapper.readValue("{\"name\": null}", Foo.class); // SUCCESS

if any from a set of fields must be present:

This is a simple variation of the previous case, as we can put validation logic inside the @JsonCreator-annotated constructor.

For example:

class Foo
{
    String name;
    Integer number;
     
    @JsonCreator
    public Foo(
       @JsonProperty("name") String name,
       @JsonProperty("number") Integer number)
    {
       if (name == null && number == null)
            throw new IllegalArgumentException("at least one of (name, number) fields must be non-null");
            
       this.name = name;
       this.number = number;
    }
    // ... more methods ...    
}
Michail Alexakis
  • 1,405
  • 15
  • 14
  • IMO, It does not answer on his needs, in case all properties not required and it should contain at least one property. – 4EACH May 20 '22 at 11:45
  • @4EACH, i have updated the answer to cover this case also (where any of the fields must be non-null) – Michail Alexakis May 20 '22 at 12:35
  • In case object holds 100 properties you will check 100 times if property is null? – 4EACH May 20 '22 at 13:52
  • this is just a pattern to follow if you want to check _any_ of a set. Well, If your object holds 100 properties, your design has some serious flaws. In any case, `equals` method will do exactly this, there is no difference in terms of complexity. – Michail Alexakis May 20 '22 at 14:14
  • So why do you want to do it here if equals do the same thing ? you cleared my point – 4EACH May 20 '22 at 15:03
0

Check if it equals to empty object:

    @NoArgsConstructor
    @Getter
    @Setter
    @ToString
    @EqualsAndHashCode
    @JsonIgnoreProperties
    public class Foo {
        private String a;
        private String b;
        private String c;
        private String d;
    }


    public class FooMain {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final Foo EMPTY_FOO = new Foo();
    
    public static void main(String[] args) {
        try {
            // This attempt will throw an exception:        
            Optional.ofNullable(OBJECT_MAPPER.readValue("{}", Foo.class))
                    .filter(foo1 -> !foo1.equals(EMPTY_FOO))
                    .orElseThrow(IllegalArgumentException::new);
            // This attempt will not throw an exception:
            Optional.ofNullable(OBJECT_MAPPER.readValue("{a:\"123\"}", Foo.class))
                    .filter(foo1 -> !foo1.equals(EMPTY_FOO))
                    .orElseThrow(IllegalArgumentException::new);

        } catch (JsonProcessingException e) {
            // cannot deserialize json string to FOO  
        }
    }
}
4EACH
  • 2,132
  • 4
  • 20
  • 28