Can we pass multiple JSON objects in a REST url and capture it using Spring #RequestBody? - spring

Is there a better way to pass multiple JSON objects and capture it in #RequestBody in Spring 3? I had referred this, but do not wish to define new wrapper classes for the purpose as explained in that question? Is it Spring's limitation or REST limitation (based on my understanding, this should not be the case)? Desperately need answer, and since I could not post additional comments in same question (was deleted), hence posting it here.
Thanks,
Paddy

for each model use #JsonIgnoreProperties(ignoreUnknown = true)
#RequestMapping(value = "/users/testBean", method = RequestMethod.POST, consumes={"application/json","application/xml"}, produces={"application/json","application/xml"})
public #ResponseBody List<User> testBean(#RequestBody Object object) {
System.out.println("testBean called");
System.out.println(object.toString());
ObjectMapper mapper=new ObjectMapper();
User user =mapper.convertValue(object, User.class);
Tree tree =mapper.convertValue(object, Tree.class);
System.out.println("User:"+user.toString());
System.out.println("Tree:"+tree.toString());
return userService.findAll();
}

Related

Is it possible to customize ObjectMapper for single Spring Rest endpoint?

I know how to customize the default ObjectMapper bean. But for one specific Controller/endpoint, I'd like to use a different objectmapper. How can I do this?
I think my question is similar to this one but there are no answers yet. Happy to get an answer there and mark this as duplicate
There's a good solution by #xerx593 linked in the question's comments but I took a different approach for mine because I was returning a generic Map<String,Object> graphql return type and I didn't feel comfortable changing the media-type or applying the object mapper to all Map's. I prefer their solution for the general case as it's more elegant
I simply serialized the return object as a string and returned it.
For example, I turned something like this
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public Foo getFoo() {
return new Foo();
}
to something like this
private ObjectMapper customMapper = ...;
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public String getFoo() {
return customMapper.writeValueAsString(new Foo());
}

How to restrict JSON payload from containing additional fields with Spring?

I have a basic User DTO class...
public class User {
#JsonProperty("firstName")
private String firstName;
#JsonProperty("lastName")
private String lastName;
}
...and a basic request handler in a #RestController class:
#RequestMapping(path = "/users", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE })
public UserMessage createUser(#RequestBody User user){
return userService.createUser(user);
}
How can I restrict incoming JSON payloads to contain at most only the required keys?
i.e. accept this payload:
{
"firstName":"foo",
"lastName":"bar"
}
And throw a custom exception on this:
{
"firstName":"foo",
"lastName":"bar",
"type":"admin",
"asdf":"asdf"
}
I read about custom Converters, ArgumentResolvers, and I believe I could simply put an additional Map parameter in the handler and validate before service call, however I'd like to know the "best" way of handling this issue.
Regarding the User bean in your example it also already not possible, that potential other JSON fields than firstName and lastName could be mapped, simply because there are no fields in User which could hold the relevant data.
Should the User bean in your question be not complete, e.g. for simplicity reasons, and contain more fields, also then should everything be fine, as long as you did not configure your your ObjectMapper with com.fasterxml.jackson.databind.DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES => false or you use the annotation #JsonIgnoreProperties(ignoreUnknown = true) on your bean.
To sum it up: Jackson's default behavior is FAIL_ON_UNKNOWN_PROPERTIES (default: true)
For further information you can also consult the respective Deserialization docs.
Solved the issue, this thread helped
#JsonIgnoreProperties(ignoreUnknown=false) is not working in Spring 4.2.0 and upper version
mle, your answer wasn't right, since I was using the latest version of Spring Framework and the ObjectMapper's FAIL_ON_UNKNOWN_PROPERTIES is turned off by default. Additionally I was needed to set #JsonIgnoreProperties(ignoreUnknown = false) in my User DTO class (as the actual class' superclass had this set to true).
Tested it, runs like a charm, while custom errors can be handled in a #ExceptionHandler(HttpMessageNotReadableException.class) annotated handler.

Is there a way to map a Retrofit #QueryMap to some object for a Spring Rest Service?

The client interface looks like this
#GET("v3/users/posts")
Call<User> loadPosts(#QueryMap Map<String,String> data);
The RestController should then process the map of query data returning the user's post. There are multiple parameters that can be put in the map as shown in the UserService.findUserPosts(). Is it possible to use a map to pass data to the Spring Rest controller? The restriction I have is this is inherited from code using #Query parameters but it has now grown to quite a number and a query map would limit the changes on the client. I would be really grateful for some feedback. Many thanks
#RestController
public class UsersController{
#RequestMapping(value = "/user/posts", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> getUserPosts(.......What here) {
List<Posts> posts = userService.findPostsBy(id,postKey,offset,when);
}
Solved it. For anyone in the future who wants to do what I am doing , simply provide Request parameters for every key pair in the map
i.e #RequestParam("id") String id,
#RequestParam("postKey") Long, #RequestParam("offset") etc.

Spring RestController url for findById and findByIds

In my Spring Boot application I have a following REST controller:
#RestController
#RequestMapping("/v1.0/decisions")
public class CriterionController {
#Autowired
private CriterionService criterionService;
#RequestMapping(value = "/{decisionId}/criteria/{criterionId}", method = RequestMethod.GET)
public CriterionResponse findById(#PathVariable #NotNull #DecimalMin("0") Long decisionId, #PathVariable #NotNull #DecimalMin("0") Long criterionId) {
Criterion criterion = criterionService.findById(criterionId);
return new CriterionResponse(criterion);
}
}
Everything is working fine and I'm able to retrieve Criterion by its ID.
Right now I need to add additional logic to my CriterionController that will retrieve Criterion by a set of IDs.
Right now I'm in doubt how it can be implemented.. For example should I add a separated endpoint something like:
/{decisionId}/criteria/{criterionIds}
or for example reuse existing one for this purpose or in some other way. Please advise how to implement it according to a best practice of REST.
This is a tricky question, but there are 2 options I can suggest:
/{decisionId}/criteria?id=1&id=2&id=3
or
/{decisionId}/criteria?id=1,2,3
The former could be seen as more RESTful but can end up with a very long URL since you'll be specifying the query parameter each time.
The latter aggregates the ids in a comma separated list. I personally prefer this option and would go for this.
Although not about REST, both URLs are accepted in Section 3.2.8 of RFC 6570

Using jackson with spring mvc 2.5

sorry for general question, but I can't google anything on that, we use spring mvc 2.5 in our project, so there is no #ResponseBody annotation, how can I make something like this without it?
You could just return it as a string built with the Jackson object mapper:
public String getCustomDetails(#PathVariable String variable1) {
CustomDetails details = new CustomDetails(variable1);
ObjectMapper mapper = new ObjectMapper();
String result = null;
result = mapper.writeValueAsString(details);
return result;
}
That should work. Might have to surround the call to writeValueAsString in a try-catch.
Edit: I should clarify that "CustomDetails" and "variable1" are just example values... they could be anything.

Resources