Jackson Object Mapper in Spring not working - json

I have Spring MVC app which receives JSON POSTed from Javascript frontend.
Using Jackson 2, custom object mapper only to set ACCEPT_SINGLE_VALUE_AS_ARRAY as true.
Below is my code snippet.
Enable MVC Java config:
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, jackson2Converter());
}
#Primary
#Bean
public MappingJackson2HttpMessageConverter jackson2Converter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper());
return converter;
}
#Primary
#Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
return objectMapper;
}
}
Controller.java:
#RequestMapping(value = "home", method = RequestMethod.POST, consumes = "application/json")
#ResponseBody
public String submitForm(#RequestBody final Shipment shipment) {
...
}
POJO:
class Shipment implements Serializable {
private String dstState;
private List<String> dstCities;
// getters, setters and default constructor
}
Ajax POST call:
$.ajax({ url: ".../home", type: "POST", data: JSON.stringify(("#shipForm").serializeArray()), contentType: "application/json", dataType: 'json', ....
JSON object posted: mydata: {"dstState":"NV" ,"dstCities":"Las Vegas"}
Upon receiving POST, there is error:
Could not read JSON: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
at [Source: java.io.PushbackInputStream#44733b90; line: 1, column: 90] (through reference chain: com.*.Shipment["dstCities"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
Please point to anything I am missing here

You input json data format is incorrect.
Shipment Json Representation:
Shipment is Json object
String dstState is also Json object
List<String> dstCities is Json Array
Correct Json Data format for your Shipment class is like
[{"dstState":"NV" , "dstCities": ["Las Vegas"]}]
or
[{"dstState":"NV" , "dstCities": ["Las Vegas", "Las Not Vegas"]}]

Related

Json Parse Error. Can not Deserialize from Object Value

There was an unexpected error (type=Bad Request, status=400).
JSON parse error:
Can not construct instance of javax.xml.bind.JAXBElement: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?);
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of javax.xml.bind.JAXBElement: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?) at [Source: java.io.PushbackInputStream#da18a91; line: 1, column: 622] (through reference chain:
Below is my code:
Here is my controller
#RestController
#RequestMapping(value = { "/api" })
public class TestController {
/*
* #Autowired BeanTest bean;
*/
private final static QName _PersonalNameTypeGivenNames_QNAME = new QName("http://sita.aero/iborders/evisa/Common/V1", "GivenNames");
private final static QName _PersonalNameTypeFamilyName_QNAME = new QName("http://sita.aero/iborders/evisa/Common/V1", "FamilyName");
#RequestMapping(value="/getBeanTest", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getTestBean() {
BeanTest bean = new BeanTest();
List<BeanTest> beanTest = new ArrayList<BeanTest>();
final List<JAXBElement<String>> jaxbElements = new ArrayList<JAXBElement<String>>();
JAXBElement<String> jaxbElementGivenNames = new JAXBElement<String>(_PersonalNameTypeGivenNames_QNAME, String.class, BeanTest.class, "Gaurav");
jaxbElements.add(jaxbElementGivenNames);
JAXBElement<String> jaxbElementFamilyNames = new JAXBElement<String>(_PersonalNameTypeFamilyName_QNAME, String.class, BeanTest.class, "Chhimwal");
jaxbElements.add(jaxbElementFamilyNames);
bean.getContent().addAll(jaxbElements);
return new ResponseEntity<Object>(bean,HttpStatus.OK);
}
}
My Entity is
public class BeanTest {
protected List<JAXBElement<String>> content;
public List<JAXBElement<String>> getContent() {
if (content == null) {
content = new ArrayList<JAXBElement<String>>();
}
return this.content;
}
}
I am calling this service from another rest api. Getting this error while calling the service:
#RestController
#RequestMapping(value = { "/api" })
public class SpringRestController {
#Autowired
private RestTemplateBuilder restTemplateBuilder;
#Autowired
public Environment env;
#GetMapping(value = "/getApplicationTest", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getApplicationTest() {
RestTemplate restTemplate = restTemplateBuilder.build();
BeanTest obj = restTemplate.getForObject("http://localhost:1010/api/getBeanTest",
BeanTest.class);
return new ResponseEntity<Object>(obj, HttpStatus.OK);
}
}

No converter found for return value of type: class org.json.JSONObject when returning JSONObject

I am migrating my project from springMVC to springboot. One of the controller has an API returning in this way.
I am trying to return JSONObject,
Here is my interface:
public class myController{
#RequestMapping(value = "/api", method = { RequestMethod.GET,
RequestMethod.POST })
public #ResponseBody JSONObject myfunction(HttpServletRequest request,
HttpServletResponse response);
}
I get the the following error:
No converter found for return value of type: class org.json.JSONObject
I have added jackson dependencies. I want to return JSONObject only. I have seen solutions but they are advising me to convert to a string. But i cannot do that as this could affect when i am returning to the front end(Which has been written already in jsp and jQuery and is expecting a JSONObject.)
How do i solve this?
Thanks.
You can use ObjectNode of Jackson library to keep JSONObject structure refer link. For that you have to autowire ObjectMapper in your service
public class myController{
#Autowired
private ObjectMapper jacksonObjectMapper;
#GetMapping
public ObjectNode sayJSONObject() {
ObjectNode objectNode = jacksonObjectMapper.createObjectNode();
objectNode.put("key", "value");
return objectNode;
}
}

Spring MVC jackson exception handling

Can I handle Jackson UnrecognizedPropertyException for a #RequestBody parameter? How can I configure this?
I'm working on a spring MVC project, and I use jackson as json plugin. Any mis-spell of the field name in a json request will lead to a error page, which should be a json string consist of error message. I'm a newbie to spring, and I think this error handling can be done with some spring configuration, but failed after several attempts. Any help?
Here is my mvc configure:
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver resolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
return bean;
}
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
My controller:
#RequestMapping(value = "/Login", method = RequestMethod.POST,
consumes="application/json", produces = "application/json")
public #ResponseBody AjaxResponse login(
#RequestBody UserVO user, HttpServletRequest request) {
//do something ...
}
Normal request json is:
{"Username":"123123", "Password":"s3cret"}
But if I send the following request:
{"Username":"123123", "pwd":"s3cret"}
which field name is mis-spell, then Spring catch this UnrecognizedPropertyException, and returned a error page, but I want to catch this exception and return a json string. How can I achieve this?
Use #ExceptionHandler annotation. Some documentation about it: http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
#Controller
public class WebMvcConfig {
#RequestMapping(value = "/Login", method = RequestMethod.POST,
consumes="application/json", produces = "application/json")
public #ResponseBody AjaxResponse login(#RequestBody UserVO user, HttpServletRequest request) {
//do something ...
}
#ExceptionHandler(UnrecognizedPropertyException.class)
public void errorHandler() {
// do something. e.g. customize error response
}
}

Spring MVC/Jackson: how to ask Spring to validate the JSON object in the request body?

I'm using Spring MVC 3.2.3 + Jackson 2.1.4 for JSON serialization.
I would like to known if it's possible to ask Spring to validate the JSON object in the request body*, especially if a required field is missing ?
I tries to set #JsonProperty(require = true) on one attribute of the Java bean but no exception seems to be raised when the field is missing in the JSON object of the request.
JSON in request body (missing "field1")
{
"field2": "value2",
"field3": "value3"
}
Controller code :
#Controller
#RequestMapping("/myBaseUrl")
public class MyController{
//...
#RequestMapping(method = RequestMethod.POST, value = "/myUrl", consumes = MediaType.APPLICATION_JSON_VALUE)
public void handle(#RequestBody MyRequestBean requestBean) throws IOException {
// code reach at execution whereas I expected the throw of an exception because "field1" is missing in JSON.
}
}
Bean for the request:
public class MyRequestBean {
//...
#JsonProperty(required = true)
private String field1
//...
public String getField1(){ return field1; }
public void setField1(String field1){ this.field1 = field1; }
}

How to generate JSON schema from a JAXB annotated class?

I have a entity class looks like this.
#XmlRootElement
public class ImageSuffix {
#XmlAttribute
private boolean canRead;
#XmlAttribute
private boolean canWrite;
#XmlValue;
private String value;
}
And I'm using following dependency for JSON generation.
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.1.4</version>
</dependency>
When I tried with following code, (which referred from Generating JSON Schemas with Jackson)
#Path("/imageSuffix.jsd")
public class ImageSuffixJsdResource {
#GET
#Produces({MediaType.APPLICATION_JSON})
public String read() throws JsonMappingException {
final ObjectMapper objectMapper = new ObjectMapper();
final JsonSchema jsonSchema =
objectMapper.generateJsonSchema(ImageSuffix.class);
final String jsonSchemaString = jsonSchema.toString();
return jsonSchemaString;
}
}
Server complains with following error message
java.lang.IllegalArgumentException: Class com.googlecode.jinahya.test.ImageSuffix would not be serialized as a JSON object and therefore has no schema
at org.codehaus.jackson.map.ser.StdSerializerProvider.generateJsonSchema(StdSerializerProvider.java:299)
at org.codehaus.jackson.map.ObjectMapper.generateJsonSchema(ObjectMapper.java:2527)
at org.codehaus.jackson.map.ObjectMapper.generateJsonSchema(ObjectMapper.java:2513)
How can I fix this?
Have you tried configuring your ObjectMapper to include jaxb introspector? We use spring mvc3 for implementing REST services and use the same model objects to serialize into xml/json.
AnnotationIntrospector introspector =
new Pair(new JaxbAnnotationIntrospector(), new JacksonAnnotationIntrospector());
objectMapper.setAnnotationIntrospector(introspector);
objectMapper.generateJsonSchema(ImageSuffix.class);
EDIT: Here is the output I get from jackson:
{
"type" : "object",
"properties" : {
"canRead" : {
"type" : "boolean",
"required" : true
},
"canWrite" : {
"type" : "boolean",
"required" : true
},
"value" : {
"type" : "string"
}
}
}
Hope this helps!
The provided answer is a bit old and some of the things have been deprecated now. So try the following code with the latest Jackson and JAXB/Moxy annotated classes:
Approach-1
class JsonSchemaGenerator{
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
TypeFactory typeFactory = TypeFactory.defaultInstance();
AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(typeFactory);
objectMapper.getDeserializationConfig().with(introspector);
objectMapper.getSerializationConfig().with(introspector);
//To force mapper to include JAXB annotated properties in Json schema
objectMapper.registerModule(new JaxbAnnotationModule());
SchemaFactoryWrapper visitor = new SchemaFactoryWrapper();
objectMapper.acceptJsonFormatVisitor(objectMapper.constructType(Customer.class), visitor);
JsonSchema inputSchema = visitor.finalSchema();
String schemaString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(inputSchema);
System.out.println(schemaString);
}
}
Approach -2 :
class JsonSchemaGenerator{
public static void main(String[] args) throws JsonProcessingException, ClassNotFoundException {
final ObjectMapper mapper = new ObjectMapper();
final TypeFactory typeFactory = TypeFactory.defaultInstance();
final AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(typeFactory);
mapper.getDeserializationConfig().with(introspector);
mapper.getSerializationConfig().with(introspector);
final JsonSchema jsonSchema = mapper.generateJsonSchema(Class.forName("com.jaxb.Customer"));
System.out.println(jsonSchema);
}
}