Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Jackson validation

Tags:

I have a springboot rest service. The user passes in a json object that gets deserialized into this java pojo:

public final class Request {     private String id;     private double code;     private String name;      public String getId() {         return id;     }      public double getCode() {         return code;     }      public String getName() {         return name;     } } 

So the user needs to pass in the following json:

{     "id": “123457896”,     "code": "Foo",     "name": "test" }  

I want to make all of those fields required. Providing anything less or more will throw an exception. Is there a way to tell jackson to validate the input when it deserializes? I've tried @JsonProperty(required=true) but this doesn't work; apparently from here and here it seems the JsonProperty annotation is not respected.

I have this validator that I call in my controller:

@Component public class RequestValidator implements Validator {     @Override     public boolean supports(Class<?> clazz) {         return false;     }      @Override     public void validate(Object target, Errors errors) {         String id = ((Request) target).getId();         if(id == null || id.isEmpty()) {             throw new InvalidRequestException("A valid id is missing. Please provide a non-empty or non-null id.");         }     } } 

But that just seems tedious and ugly to check every field. So given I'm using java 8, spring boot and latest version of jackson what is the best practice in terms of validating an incoming json input? Or am I already doing it in the most up to date manner?

like image 460
Richard Avatar asked Apr 01 '16 13:04

Richard


People also ask

Why we use @JsonProperty?

@JsonProperty is used to mark non-standard getter/setter method to be used with respect to json property.

How do I check if a JSON object is valid?

The simplest way to check if JSON is valid is to load the JSON into a JObject or JArray and then use the IsValid(JToken, JSchema) method with the JSON Schema. To get validation error messages use the IsValid(JToken, JSchema, IList<String> ) or Validate(JToken, JSchema, SchemaValidationEventHandler) overloads.

How do you check if a string is a valid JSON string in Java?

The common approach for checking if a String is a valid JSON is exception handling. Consequently, we delegate JSON parsing and handle the specific type of error in case of incorrect value or assume that value is correct if no exception occurred.


Video Answer


1 Answers

There is no need for custom validator. There is a way to tell jackson to throw

  • JsonMappingException if you don't have required fields

  • UnrecognizedPropertyException if you have extra fields (UnrecognizedPropertyException is just extended JsonMappingException) .

You just need to add @JsonCreator or custom constructor. Something like this should work:

public Request(@JsonProperty(value= "id", required = true)String id,                @JsonProperty(value= "code",required = true)double code,                @JsonProperty(value= "name",required = true)String name) {     this.id = id;     this.code = code;     this.name = name; } 

Full Demo:

import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException;  public class Main {  public static void main(String[] args) throws IOException {     test("{\"id\": \"123457896\",\"code\": 1,\"name\": \"test\"}");     test("{\"id\": \"123457896\",\"name\": \"test\"}");     test("{\"id\": \"123457896\",\"code\": 1, \"c\": 1,\"name\": \"test\"}"); }  public static void test(String json) throws IOException{     ObjectMapper mapper = new ObjectMapper();     try {         Request deserialized = mapper.readValue(json, Request.class);         System.out.println(deserialized);         String serialized = mapper.writeValueAsString(deserialized);         System.out.println(serialized);     } catch (JsonMappingException e) {         System.out.println(e.getMessage());     } }  public static class Request {     private String id;     private double code;     private String name;      public Request(@JsonProperty(value= "id", required = true)String id,                    @JsonProperty(value= "code",required = true)double code,                    @JsonProperty(value= "name",required = true)String name) {         this.id = id;         this.code = code;         this.name = name;     }      public String getId() {         return id;     }      public void setId(String id) {         this.id = id;     }      public double getCode() {         return code;     }      public void setCode(double code) {         this.code = code;     }      public String getName() {         return name;     }      public void setName(String name) {         this.name = name;     }      @Override     public String toString() {         return "Request{" +                 "id='" + id + '\'' +                 ", code=" + code +                 ", name='" + name + '\'' +                 '}';     } } } 

Result:

Request{id='123457896', code=1.0, name='test'} {"id":"123457896","code":1.0,"name":"test"} Missing required creator property 'code' (index 1)  at [Source: {"id": "123457896","name": "test"}; line: 1, column: 34] Unrecognized field "c" (class Main7$Request), not marked as ignorable (3 known properties: "id", "code", "name"])  at [Source: {"id": "123457896","code": 1, "c": 1,"name": "test"}; line: 1, column: 53] (through reference chain: Request["c"]) 
like image 161
varren Avatar answered Sep 20 '22 12:09

varren