Saturday, May 27, 2017

Validate Json Request Schema

Leave a Comment

So I have this Controller class that contain this method:

    @RequestMapping(value = "/x", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)     public ResponseEntity<MyRepsonseClass> get(         @ApiParam(value = "x", required = true) @Valid @RequestBody MyRequestClass request     ) throws IOException {         //yada yada my logic here         return something;     } 

The Json Request gets automatically Mapped to MyRequestClass.java

This is what that class looks like:

@lombok.ToString @lombok.Getter @lombok.Setter @JsonInclude(JsonInclude.Include.NON_EMPTY) @ApiModel(description = "description") public class MyRequestClass {     private List<SomeClass> attribute1;     private SomeOtherClass attribute2;     private YetAnotherClass attribute3; } 

This is an example of a valid json request:

{     "attribute1": [         {             "key":"value"         }     ],     "attribute3:" {         "key":"value"     } } 

Now, my requirement is to return an Error Message when the request contains an attribute that doesn't exist in the MyRequestClass.java.

As such:

{     "attribute1": [         {             "key":"value"         }     ],     "attribute_that_doesnt_exist:" {         "key":"value"     } } 

Right now it's not throwing any error. Rather, it's simply not mapping that attribute to anything. Are there annotations I can utilize that can make this happen quickly ?? Thank you.

2 Answers

Answers 1

Create a custom deserializer:

public class MyRequestClassDeserializer extends JsonDeserializer<MyRequestClass> {     @Override     public MyRequestClass deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {         MyRequestClass mrc = new MyRequestClass();         ObjectMapper mapper = new ObjectMapper();         JsonToken currentToken = null;         while((currentToken = jsonParser.nextValue()) != null) {             if(currentToken.equals(JsonToken.END_OBJECT)                      || currentToken.equals(JsonToken.END_ARRAY))                 continue;             String currentName = jsonParser.getCurrentName();             switch(currentName) {                 case "attribute1":                     List<SomeClass> attr1 = Arrays.asList(mapper.readValue(jsonParser, SomeClass[].class));                     mrc.setAttribute1(attr1);                     break;                 case "attribute2":                     mrc.setAttribute2(mapper.readValue(jsonParser, SomeOtherClass.class));                     break;                 case "attribute3":                     mrc.setAttribute3(mapper.readValue(jsonParser, YetAnotherClass.class));                     break;                 // <cases for all the other expected attributes>                 default:// it's not an expected attribute                     throw new JsonParseException(jsonParser, "bad request", jsonParser.getCurrentLocation());             }         }         return mrc;     } }   

And add this annotation to your MyRequestClass class: @JsonDeserialize(using=MyRequestClassDeserializer.class)

The only "problem" is that manually deserializing jsons can be a hassle. I would have written the complete code for your case but I'm not good enough at it right now. I might update the answer in the future.

Edit: Done, now it's working code. I thought it was more complicated.

Answers 2

Did you try this annotation @JsonIgnoreProperties(ignoreUnknown = false)

If Spring boot, even better, use this property in application.properties(yaml)

spring.jackson.deserialization.fail-on-unknown-properties=true 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment