CodeBlooded
CodeBlooded

Reputation: 175

Do we have to have to post json object with exactly same fields as in pojo object in controller?

I am new to spring rest and am having problem to map JSON object from jquery to controller. My jquery JSON object have some field absent which are present in java object on controller. Do I have to create new class to map such object or is there any way to map these objects without creating new class?

Here are the code

Controller:

@RequestMapping(value = "/createTest", method = RequestMethod.POST,consumes="application/json")
    @ResponseBody
    public String createTest(@RequestBody TestJsonDTO testJson)
            throws JsonProcessingException, IOException {
//....

TestJsonDTO:

 public class TestJsonDTO {

 private TestSet testSet;

 private List<MainQuestion> questionsInTest;

 //gettters and setters

TestSet:

public class TestSet implements Serializable {

public TestSet() {
}

@Id
@GeneratedValue
private int id;
private String name;
private int fullmark;
private int passmark;
String duration;
Date createDate = new Date();
Date testDate;
boolean isNegativeMarking;
boolean negativeMarkingValue;

MainQuestion:

public class MainQuestion implements Serializable {

private static final long serialVersionUID = 1L;
public MainQuestion() {

}
@Id
@GeneratedValue
private int id;
private String name;

and my jquery post method

function createTest() {
    $.ajax({
        type : 'POST',
        url : "http://localhost:8085/annotationBased/admin/createTest",
        dataType : "json",
        contentType : "application/json",
        data : testToJSON(),
        success : function() {
            alert("success")
        },
        error : function(msg) {
            alert("error while saving test");
        }
    });

}

function testToJSON() {
    listOfQuestionForTest = questionToAdd;//array of ids of questions
    return JSON.stringify({
        "testSet.name" : $('#testname').val(),
        "testSet.fullmark" : parseInt($('#fullmark').val()),
        "testSet.passmark" : parseInt($('#passmark').val()),
        "questionsInTest" : listOfQuestionForTest
    // "testDate":$('#testDate').value()
    })

}

In JSON.stringify I am not sending all the fields in TestJsonDto. How can I map this?

Upvotes: 4

Views: 4166

Answers (1)

fps
fps

Reputation: 34460

You should configure Spring this way:

@Configuration
public class ServiceContext
    extends WebMvcConfigurationSupport {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter converter = this.getMappingJackson2HttpMessageConverter();
        converters.add(converter);
    }

    @Bean
    public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = this.getObjectMapper();
        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        return mappingJackson2HttpMessageConverter;
    }

    @Bean
    public ObjectMapper getObjectMapper() {
        JsonFactory jsonFactory = new JsonFactory();
        ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // this is what you need
        objectMapper.setSerializationInclusion(Include.NON_NULL); // this is to not serialize unset properties
        return objectMapper;
    }
}

Here Spring is configured with an ObjectMapper that doesn't serialize properties whose value is null and that doesn't fail on deserialization if some property is missing.

EDIT: (Added some background and explanations)

Spring converts what comes in HTTP request's body into a POJO (that's what @RequestBody actually tells Spring to do). This conversion is performed by a HttpMessageConverter, which is an abstraction. Spring provides default specific message converters for common media types, such as Strings, JSON, form fields, etc.

In your case, you need to tell Spring how to deserialize the incoming JSON, i.e. how to read the JSON that you're sending from jQuery and how to convert this JSON into the POJO you're expecting to receive in your @Controller (TestJsonDTO in your question).

Jackson 2 is a JSON serialization/deserialization library that is widely used. It's most important class is ObjectMapper, which is used to perform the actual serialization and deserialization. Spring has a specific HttpMessageConverter that uses Jackson in order to serialize and deserialize JSON. This is MappingJackson2HttpMessageConverter, which can receive a Jackson's ObjectMapper instance that you can configure if you want to override default behavior.

This ObjectMapper is configured to not serialize properties that are null in your POJO (i.e. your JSON won't contain these properties as fields), and more important, when deserializing, it is configured to not fail with an exception if there is a missing property in either your JSON or your POJO. This is what objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); actually does.

Upvotes: 2

Related Questions