I'm using Jackson in my Spring Boot application.
I want to convert request parameters to POJO.
But when I use #ModelAttribute with #JsonAlias, it doesn't work.
Request POJO
#Data
public RequestPojo {
#JsonAlias( "FOO_SNAKE" ) // Not working
private String fooCamelAlias;
}
Controller:
#GetMapping("/foo")
public void getFoo( #ModelAttribute RequestPojo requestPojo ) {
...
}
Request:
(1) http://localhost?FOO_SNAKE=Foo_snake
(2) http://localhost?fooCamelAlias=Foo_snake
fooCamelAlias is null when I request with (1).
But (2) works.
#JsonAlias will not work with #ModelAttribute because #ModelAttribute is used for binding data for request param (in key value pairs). If you want to do JSON mapping then better to use #RequestBody
Related
I have this DTO Request Class
Public Class MyRequestDTO(){
private String name;
private MultipartFile docPic;
}
i want to retrieve in in controller
#PostMapping("/test")
public String test(#RequestBody MyRequestDTO dto){
system.out.print(dto.getdocPic.getOriginalFileName());
return "success;
}
but always get javaNullexception when i try to display this newly requested file, is it correct to mapping multipart file inside DTO ?
With the latest spring boot we have a running example without the #RequestBody annotation, so try this:
#PostMapping("/test")
public String test(MyRequestDTO dto){
If that doesn't work, the next spot you should double check is your request. Specifically the Content-type. The above signature works for us with a request that has a content type of: multipart/form-data
You're getting javaNullexception because you're receiving MyRequestDTO dto as null or some property of dto object is pointing to null.
So please be sure before calling the getter method on a null object.
Firstly get that dto.getdocPic is not pointing to null.
#PostMapping("/test")
public String test(#RequestBody MyRequestDTO dto){
if(dto.getdocPic() != null){
system.out.print(dto.getdocPic().getOriginalFileName());
}
return "success;
}
Let's say I have:
#GET
public UserList fetch(#PathParam("user") String userId) {
// Do stuff here
}
Now, let's say I have my own type for userId, let's call it UserId. Is it possible to parse that String to UserId when it is passed into the fetch method, i.e.:
#GET
public UserList fetch(#PathParam("user") UserId userId) {
// Do stuff here
}
I realize I can parse the String once I am inside the method, but it would be more convenient that my method gets the type I want.
Well you've attempted to make a GET call with a request body is what I find not very helpful. Do read Paul's answer here -
you can send a body with GET, and no, it is never useful to do so
What would be good to practice is, to make a PUT or a POST call (PUT vs POST in REST) as follows -
#POST
#Path("/some-path/{some-query-param}")
public Response getDocuments(#ApiParam("user") UserId userId,
#PathParam("some-query-param") String queryParam) {
UserId userIdInstance = userId; // you can use the request body further
Note - The ApiParam annotation used is imported from the com.wordnik.swagger.annotations package. You can similarily use FormParam,QueryParam according to your source of input.
Dropwizard is using Jersey for HTTP<->Java POJO marshalling. You could use the various annotations from Jersey #*Param (#FormParam, #QueryParam, etc.) for some of the parameters.
If you need to use map/marshall to/from Java POJOs take a look at the test cases in Dropwizard:
#Path("/valid/")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class ValidatingResource {
#POST
#Path("foo")
#Valid
public ValidRepresentation blah(#NotNull #Valid ValidRepresentation representation, #QueryParam("somethingelse") String xer) {
return new ValidRepresentation();
}
This defines an API endpoint responding to HTTP POST method which expects ValidRepresentation object and "somethingelse" as HTTP method query parameter. The endpoint WILL respond ONLY when supplied with JSON parameters and will return only JSON objects (#Produces and #Consumes on the class level). The #NotNull requires that object to be mandatory for the call to succeed and #Valid instructs Dropwizard to call Hibernate validator to validate the object before calling the endpoint.
The ValidRepresentation class is here:
package io.dropwizard.jersey.validation;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
public class ValidRepresentation {
#NotEmpty
private String name;
#JsonProperty
public String getName() {
return name;
}
#JsonProperty
public void setName(String name) {
this.name = name;
}
}
The POJO is using Jackson annotations to define how JSON representation of this object should look like. #NotEmtpy is annotation from Hibernate validator.
Dropwizard, Jersey and Jackson take care of the details. So for the basic stuff this is all that you need.
A Rest service is mapped on one url with some #RequestBody where i am mapping json to pojo. Pojo contains nested classes following is sample code.
#RequestMapping(value = "/saveExampleObject.html", method = RequestMethod.POST)
public #ResponseBody List<String> saveExampleObjectDefintion(#RequestBody ExampleObject exampleObject) throws DataAccessException,DataNotPersistException {
List<String> msg = saveService.save(exampleObject);
return msg;
}
and the object is like
class ExampleObject{
String name;
SubClass subClass;
.....
}
and json is
{
"name":"name",
"subClass":{
.....
}
I have configured spring mvc annotation and conversion is also happening.
But some fields are null. I cross checked names of null field they are same as in json and pojo.
P.S. Only first fields are getting values in subclass.Thanks.
in your json you have subClass but in your class you have subclass... is case sensitive
Here the setters were not defined properly and hence there was an error. Spring MVC uses the setters to properly convert POJO to JSON and vice versa.
I would like to process an HTTP POST request hitting my rest endpoint and convert its body to my defined POJO. I was successful in the past with mapping between JSON and POJOs but I am struggling with this form encoded content.
I have a controller as follows:
#Slf4j
#RestController("/example")
public class GatewayController {
#RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public void describeInstances(#RequestBody MyPojo body) {
log.debug("Value1: " + body.getValue1());
}
}
And a POJO:
#Data
public class MyPojo {
private String value1;
private String value2;
...
}
I am hitting the controller with a POST request which looks as follows:
Content-Type: application/x-www-form-urlencoded
Body: value1=abc&value2=efg...
But all I am getting is 415 Unsupported Media Type. Any help is appreciated.
EDIT: when I change the POJO into String and just print the body, it works (without receving the unsupported media type exception) so it is definitely in the POJO declaration.
Follow up:
Is it possible to annotate the POJO attributes to allow different names of the fields (to avoid using undorscope inside variable names, for example)?
Something like:
#Attribute("value_name")
private String valName;
#ModelAttribute is the recommended way to get form data in your controller. e.g.
public void describeInstances(#ModelAttribute("mypojo") MyPojo body)
and
#Data
#ModelAttribute("mypojo")
public class MyPojo {
Read the spring docs for more info here
How come this code just works? I didn't specify any custom converter or annotation (like #RequestBody or #ModelAttribute) before argument ? Request is filled correctly from this GET call:
http://localhost:8080/WS/foo?token=C124EBD7-D9A5-4E21-9C0F-3402A1EE5E9B&lastSync=2001-01-01T00:00:00&pageNo=1
Code:
#RestController
#RequestMapping(value = "/foo")
public class FooController {
#RequestMapping(method = RequestMethod.GET)
public Result<Foo> excursions(Request request) {
// ...
}
}
Request is just POJO with getters and setters. I use it to shorten argument code because plenty methods uses those same arguments ...
public class Request {
private String token;
#DateTimeFormat(pattern = IsoDateTime.DATETIME)
private Date lastSync;
private Integer pageNo;
// getters and setters
}
This was my original method before introducing Request.
#RestController
#RequestMapping(value = "/foo")
public class FooController {
#RequestMapping(method = RequestMethod.GET)
public Result<Foo> excursions(#RequestParam String token, #RequestParam #DateTimeFormat(pattern = IsoDateTime.DATETIME) Date lastSync, #RequestParam Integer pageNo) {
// ...
}
}
Request parameters will be mapped to POJOs, as it is happening in your case, by default. Additionally, if you use #ModelAttribute, an attribute in the Model will be created. That attribute can be then used in views, e.g. JSPs, to access the object.
#RequestBody annotation tells that the body of the request is NOT a set of form parameters like
token=C124EBD7-D9A5-4E21-9C0F-3402A1EE5E9B&lastSync=2001-01-01T00:00:00&pageNo=1
but is in some other format, such as JSON.
This is a feature provided by Spring MVC:
Customizable binding and validation. Type mismatches as application-level validation errors that keep the offending value, localized date and number binding, and so on instead of String-only form objects with manual parsing and conversion to business objects.
You can see it in the doc: http://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/htmlsingle/