In a RESTful Spring Web Service, we can use FasterXML Jackson to deserialize JSON request to Java object.

Configuration
Java Compilation:
Java Runtime:
Web Server:
Maven:
Java Compilation:
Java Runtime:
Web Server:
Gradle:
JDK 11.0.12
JRE HotSpot 11.0.12
Tomcat 9.0.58
Maven 3.8.4
JDK 11.0.12
JRE HotSpot 11.0.12
Tomcat 9.0.58
Gradle 7.4.2
This tutorial is about deserialization(convert JSON to Java object), for serialization(convert Java object to JSON), please visit
In a RESTful Web Service, we need a library to convert JSON request body to Java object
In Spring, we can configure FasterXML Jackson as the library
In the application context xml, add the following:
<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven>
In pom.xml, add the following dependency: (Using Gradle please see)
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.9</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.9</version> </dependency>
dependencies { implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.9' implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.9' }
Define a controller class with a @PostMapping annotated method with Customer object as the param:
import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/myapp") public class MyController { @PostMapping("/customer") public void postCustomer(@RequestBody Customer customer) { System.out.println("name = " + customer.getName() + ", age = " + customer.getAge() + ", state = " + customer.getState() + ", zip = " + customer.getZip()); } }
And the Customer class:
public class Customer { private String name; private Integer age; private String state; private Integer zip; // public setter and getter of all the fields }
After building and deployed to <CONTEXT_PATH>, by calling
curl --request POST '<CONTEXT_PATH>/myapp/customer' --header 'Content-Type: application/json' --data ' { "name": "Sam", "age": 30, "state": "CA", "zip": 90008 }'
System.out.println will print:
name = Sam, age = 30, state = CA, zip = 90008
Customized field name could be used. If a field does not start with lower case letter or have special characters, for instance:
{"@Name!":"Sam","age":30,"state":"CA","zip":90008}
The @JsonProperty annotation could be used to change the field name. The Customer class will look like this:
public class Customer { @JsonProperty("@Name!") private String name; private Integer age; private String state; private Integer zip; // public setter and getter of all the fields }
example:
curl --request POST '<CONTEXT_PATH>/myapp/customer' --header 'Content-Type: application/json' --data ' { "@Name!": "Sam", "age": 30, "state": "CA", "zip": 90008 }'
System.out.println will still print:
ame = Sam, age = 30, state = CA, zip = 90008
Complete customization of deserialization. For example, if you want the state field to take the value CA in both following situations:
{"name":"Sam","age":30,"state":{"postal":"CA"},"zip":90008}
or:
{"name":"Sam","age":30,"state":"CA","zip":90008}
a custom JsonDeserializer can be used:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.TreeNode; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; public class CustomerDeserializer extends JsonDeserializer<String> { @Override public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { TreeNode tree = jsonParser.readValueAsTree(); String value = tree.toString(); if (value.startsWith("{\"postal\":\"")) { int startPos = "{\"postal\":\"".length(); int endPos = value.lastIndexOf("\"}"); return value.substring(startPos, endPos); } else { return tree.toString().substring(1, tree.toString().length() - 1); } } }
To use the CustomerDeserializer, just annotate the field with it:
public class Customer { private String name; private Integer age; @JsonDeserialize(using = CustomerDeserializer.class) private String state; private Integer zip; // public setter and getter of all the fields }
So both of the following will print the same output:
curl --request POST '<CONTEXT_PATH>/myapp/customer' --header 'Content-Type: application/json' --data ' { "name": "Sam", "age": 30, "state": "CA", "zip": 90008 }'
or
curl --request POST '<CONTEXT_PATH>/myapp/customer' --header 'Content-Type: application/json' --data ' { "@Name!": "Sam", "age": 30, "state": {"postal":"CA"}, "zip": 90008 }'
Both System.out.println will still print:
name = Sam, age = 30, state = CA, zip = 90008
Fields are dynamic. If the number of fields is not fixed, instead of defining all the fields, define a map and use @JsonAnySetter on the setter method of the map:
Customer class will become:
public class Customer { private Map<String, String> dynamicFields = new HashMap<≶(); @JsonAnySetter public void setDynamicFields(String key, String value) { dynamicFields.put(key, value); } public Map<String, String> getDynamicFields() { return dynamicFields; } }
Change the postCustomer method in the controller for printing differently:
@PostMapping("/customer") public void postCustomer(@RequestBody Customer customer) { for (String s : customer.getDynamicFields().keySet()) { System.out.println("key = " + s + " value = " + customer.getDynamicFields().get(s)); } }
example:
curl --request POST '<CONTEXT_PATH>/myapp/customer' --header 'Content-Type: application/json' --data ' { "name": "Sam", "age": 30, "state": "CA", "zip": 90008 }'
System.out.println will print:
key = zip value = 90008
key = name value = Sam
key = state value = CA
key = age value = 30
another example:
curl --request POST '<CONTEXT_PATH>/myapp/customer' --header 'Content-Type: application/json' --data ' { "name": "Sam", "state": "CA", "phone": "123456789", "email": "customer@maxjava.net" }'
System.out.println will print:
key = phone value = 123456789
key = name value = Sam
key = state value = CA
key = email value = customer@maxjava.net