I'm using spring 4.0.5.RELEASE and jackson-databind 2.2.3 in my web application.
When sending this JSON:
{"keyField1":"57579","keyField2":"sdf","someField":"sdasd","parameters":[{"parameterName":"dfgdfg","parameterValue":"sdf"},{"parameterName":"erwer","parameterValue":"sdfsdf"}]}
to the controller all I get is a HTTP 400 Bad Request at browser,
I don't see any error at local websphere log, but after some tests I saw that the problem is with deserialization of the JSON array to the map.
I never get into the save method at the controller.
Tried some annotation like #JsonDeserialize(as=HashMap.class) without success.
How can I resolve this?
My POJO:
class MyClassId implements Serializable {
private static final long serialVersionUID = 5022985493208399875L;
String keyField1;
String keyField2;
}
#Entity
#IdClass(MyClassId.class)
public class MyClass {
#Id
String keyField1;
#Id
String keyField2;
String someField;
#ElementCollection
#MapKeyColumn(name="parameterName")
#Column(name="parameterValue", length=400)
Map<String, String> parameters;
... Getters and Setters ...
My controller:
#RestController
#RequestMapping("/myclass/**")
public class MyClassController {
#Transactional
#RequestMapping(value = "/save", method = RequestMethod.POST, consumes={"application/json"})
public #ResponseBody ServiceResponce<MyClass> save(#RequestBody MyClass processToSave) {
... Code ...
}
}
I see two solutions to your problem:
You distinguish the entity class that is persistent to the representation class that is sent back to the client. The drawback is that you need to make the representation creation explicitely in your code from the entity
If you use Jackson to serialize your response in the respone (JSON, ...), you can leverage it feature "custom serializer" to adapt the structure of the returned payload according to your needs. See this answer for more details:
Spring 3.2 and Jackson 2 custom object mapper - Spring 3.2 and Jackson 2: add custom object mapper
Register a custom Jackson ObjectMapper using Sprint JavaCconfig - http://magicmonster.com/kb/prg/java/spring/webmvc/jackson_custom.html
Restlet Complex Object to XML serializaton - Restlet Complex Object to XML serializaton
Hope it helps you,
Thierry
In the JSON, parameters is not an object but an array of objects:
"parameters":[{"parameterName":"dfgdfg","parameterValue":"sdf"}, ...
You can not map this on a
Map<String, String> parameters;
Use at least
List<Map<String, String>> parameters;
Related
I am using a domain object imported from other service which implements builder pattern and hence have no No-arg Constructor and setters. I want to map JSON coming from #RequestBody to this domain object. I know I can annotate it with #JSONPojoBuilder and some other ones but i don't have control over it. So I'm stuck with writing my own JSON to Object mapper which i don't think is a good idea as it involves validations etc. and is tightly coupled with request body.
Code -
#RequestMapping(value = "someurl", method = RequestMethod.POST)
public ResponseEntity<ObjectA> addObject(#PathVariable String id, #RequestBody #NonNull String body) {
ObjectA obj = service.addObject(id, mapper.mapJSONToObject(body));
return new ResponseEntity<>(obj , HttpStatus.CREATED);
}
Instead of writing my own mapper, I heard we can use some message convertor and pass our Builder class as some argument. I did not find such examples, if anybody has done it before or can point me to some site, that'd be helpful.
I've never tried that, but in general Spring MVC supports the abstraction of "Custom Converters" that you can write in order to help spring to convert JSON to complicated objects.
I assume that you have a MyComplicatedClass without no-ops constructor but with a builder.
So you can do the following:
import org.springframework.core.convert.converter.Converter;
#Component // note the converter is also a spring bean so you can, say, inject object mapper and convert to JsonNode-s for example (see below)
public class MyComplicatedClassConverter implements Converter<String, MyComplicatedClass> {
#Autowired // or use constructor injection
private ObjectMapper objectMapper;
/**
* Override the convert method
* #param object in a string representation to be converted
* #return
*/
#Override
public MyComplicatedClass convert(String object) {
JsonNode node= objectMapper.readTree(/*byte array input stream from object string or something */);
return MyComplicatedClass.builder()
.withSomeProperty(node.get("someProperty").textValue()
.withAnotherProperty(node.get("anotherProperty").intValue()
.build();
}
}
Now, when your application recognizes this converter it allows using MyComplicatedClass in the controller's methods as if spring knows how to convert it.
So the code snippet that you've presented in your example should work.
All this is done without "touching" the code of MyComplicatedClass.
In my Spring web application, I have an API that accepts requests with application/x-www-form-urlencoded content type.
#RequestMapping(value = "/do-it", method = {RequestMethod.POST})
public String test(#ModelAttribute("request")RequestDTO request,HttpServletRequest
httpServletRequest, Map<String, Object> model, RedirectAttributes redirectAttributes){
.....
}
My RequestDTO has following fields in it.
public class RequestDTO {
private String paramOne;
private String paramTwo;
// standard getters and setters
}
This implementation works fine, all the request params get mapped to the request dto as expected. However, now I have this requirement to accept the requests with the fields in following pattern.
param_one, param_two
I understand that, using #JsonProperty annotation on the fields in my request dto is not gonna work in my case since the request is not in the type of application/json.
The only way I have found to solve the issue is creating new setters like following (which looks ugly in my opinion when it comes to naming convention).
public void setParam_one(String param_one) {
this.paramOne = param_one;
}
Can some one help me to find a better way to get this done? I cannot change the param names in original request dto.
Thank you..!
I was able to get this done. Thanks to #neetash for guiding me.
Everything I needed to have was a Custom HandlerMethodArgumentResolver to map the post request body data to the object that I wanted to get.
I followed following linked tutorial to implement it. It contains every single thing someone needs to know to create a HandlerMethodArgumentResolver.
https://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-creating-a-custom-handlermethodargumentresolver/
I'm having a JAX-RS web application method which takes a JSON entity and produces one. But I'm having problems with the POJOS matching the consumed JSON entity, specificly with their annotations.
How do I configure the POJOS so I don't need to write the name of the properties in the consumed JSON entity? I would rather have a custom name for them.
Example
Prefered JSON entity:
{
"foo_bar" : "spam"
}
POJO:
#XmlRootElement
public class A {
private String fooBar;
public String getFooBar() {
return fooBar;
public void setFooBar(String fooBar) {
this.fooBar = fooBar;
}
So far I tried the #XmlElement(name="foo_bar") annotation, but it didn't work. Some other stackoverflow thread suggested #JsonProperty("foo_bar"), but what's the difference between them? Additionally, does this annotation work with the existing #Xml annotations?
I had Jackson deserializing problem of one of my java class which is come from third party API that doesn't have default constructors.To overcome that issue i used JacksonMixIn and it worked fine.But the problem was that i have a REST endpoint implemented on Jersey API which is accepted one of above mentioned classes as a method parameter from client side to server side.So when deserializing it throws me following error.
No suitable constructor found for type [simple type, class net.rcarz.jiraclient.Priority]: can not instantiate from JSON object (need to add/enable type information?)
at [Source: org.glassfish.jersey.message.internal.EntityInputStream#558e8ae; line: 1, column: 454]...
Affected classes
public class TestCaseVO{
private Priority priority;
private User reporter;
}
public class Priority {
protected Priority(RestClient restclient, JSONObject json) {
super(restclient);
if (json != null)
deserialise(json);
}
}
This is the object used to communicate client to server
public class myDataObject{
private String userName;
private List<TestCaseVO> testCases;
//Getter and setters
}
Jersey Endpoint
#POST
#Path("/bug")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public TestCaseVO attachBugForTestCase(myDataObject myDataObject){
// when deserializing to MyDataObject it thorows above error
//Handle logic
}
Client side code snippet
var myDataObject= {
"testCases": [$scope.bug.TestCaseVO],
"userName":userName}
angularJsMyService.Bug.attachBug({},myDataObject)
.$promise.then(function(data){
...
}
My question is that how can i use Jackson mixin on REST methods parameters prior to Jackson deserializing them.Appreciate any help.
I guess you probably didn’t integrate Jackson with Jersey in the right way. Check out Jersey’s doc on Jackson. In your project, there should be a class implementing ContextResolver<ObjectMapper>. The ObjectMapper instance returned by getContext(Class<?> type) in this class is used by Jersey’s REST endpoints. You may to configure that ObjectMapper with your Mix-in.
I have the following situation
public class MyCustomForm {
private MyCustomType a;
private MyCustomType b;
}
#RestController
public class AController {
#RequestMapping(...)
public void myMethod(#RequestBody MyCustomForm form){
...
}
}
I want to send in a POST request the necessary data to fill the form. The problem is that MyCustomType is a complex data type and cannot be deserialized from JSON.
The first thing I tried was to write a PropertyEditor so that Spring will know how the make the deserialization from a string. This solution works if I use anything else beside #RequestBody (it works with #PathVariable for example).
I made some research and the reason why #RequestBody is not working is because this annotation generates a proxy which uses its own deserialization rules. Those rules do not interfere with custom PropertyEditors.
The next thing I tried was to use a custom Converter. This solution still didn't solved the issue.
Any other ideas?
I understood that the newest version of jackson (version 2) will know about the custom Converters or PropertyEditors but updating my jackson mapper is not really a solution in my case.
You can use #JsonDeserialize for your MyCustomType classes like
public class MyCustomForm {
#JsonDeserialize(using = MyCustomTypeDeserializer.class)
private MyCustomType a;
#JsonDeserialize(using = MyCustomTypeDeserializer.class)
private MyCustomType b;
}
Some references:
https://fasterxml.github.io/jackson-databind/javadoc/2.3.0/com/fasterxml/jackson/databind/annotation/JsonDeserialize.html
http://www.davismol.net/2015/06/05/jackson-using-jsonserialize-or-jsondeserialize-annotation-to-register-a-custom-serializer-or-deserializer/
http://www.baeldung.com/jackson-custom-serialization