Multiple custom serializers for same entity in Spring Boot - json

I'm working on a Spring Boot application. I've created a custom serializer for one entity A and registered it using #JsonSerialize(using = CustomSerializer.class) annotation. Whenever i send A in ResponseEntity<> the custom serializer is called and everything is working fine till this point.
Now there is another API in which i need to send a Collection of A in response. But i cant use same serializer to construct the list of A's as response parameters are totally different. I need to write one more serializer for same entity .
How can i configure 2 serializers for same entity? They should be called based on the object type sent in response i.e. When i'm sending A, then serializer1 should be called and when i'm sending Collection, the serializer2 should be called.
Please help!

A simple workaround would be to annotate the collection to use a specific serializer for content. E.g.
#JsonSerialize(using = CustomSerializer.class)
class A {
}
class AList {
#JsonSerialize(contentUsing = AnotherCustomSerializer.class)
private final List<A> list;
}

Related

JSON encoding using produces={"application/json; charset=UTF-8"} and ObjectMapper

I am trying to develop a microservice using Spring MVC and Spring Boot. In my service I am giving result back as JSON encoded format. Currently I added action like:
#RequestMapping("/checkUsers")
public String checkLogin() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
List<Users> useObj = (List<Users>) userRepo.findAll();
return(mapper.writeValueAsString(useObj));
}
And now I found the other options through the following method
produces={"application/json; charset=UTF-8"}
Here I am not sure which method is properly using for encoding the data into JSON format in Spring. How can I proceed?
Why don’t you just use
ResponseEntity
And return
new ResponseEntity<String>(“your message”, HttpStatus.OK);
#RequestMapping(method = GET, value = "my/random/uri", produces = "application/json;charset=UTF-8")
Here produces attribute inside my #RequestMapping annotation is the producible media types of the mapped request. The format is a single media type or a sequence of media types, with a request only mapped if mentioned one matches one of these media types. and here, my #RequestMapping annotation is already serving my purpose of encoding.
Now somewhere from Spring Boot documentation:
Spring Boot is a brand new framework designed to simplify the bootstrapping and development of a new Spring
application. The framework takes an opinionated approach to
configuration, freeing developers from the need to define boilerplate
configuration.
Please don't kill the purpose of Spring Boot. :)
Additionally, I would suggest you use org.springframework.http.MediaType class. It has got all encoding types you'll ever require. Happy coding.
Please let me know if you face any difficulty while going with suggested approach.
If you use #RestController on your controller, all request mappings will produce application/json by default.
Also, there is no need to to the object mapping yourself, just return the object without mapping and let Spring/Jackson do its thing.
#RestController
public class UsersController {
// #RequestMapping("/checkUsers")
// There is an even simpler and more concise
#GetMapping("/checkUsers")
public List<User> checkLogin() throws JsonProcessingException {
return userRepo.findAll();
}
}

Binding JSON request data to command objects

In a Grails 2.5.X app, I can directly bind request data to a command object field of type Map like so:
class MyController {
def myAction(Command command) {
Map requestData = command.data
}
}
class Command {
Map data
}
It seems that internally Grails uses Gson for the parsing of the JSON data. If for example, the request data is {"page": 6} the corresponding Map will be
[page: new LazilyParsedNumber(6)]
i.e. the value stored in the Map is an instance of com.google.gson.internal.LazilyParsedNumber.
This is problematic for me. I would prefer if the Map were equivalent to that which would be created by:
new groovy.json.JsonSlurper().parseText('{"page": 6}')
which is:
[page: new Integer(6)]
I've looked into the various options for customising the databinding, and none of them hook into the pipeline sufficiently early. In other words, no matter which of the options I choose, the request data has already been processed by Gson.
Is it possible to replace Gson with JsonSlurper as the default parser of JSON request data?
Is it possible to replace Gson with JsonSlurper as the default parser
of JSON request data?
Yes, but it isn't something that we document or provide any particular support hooks for.
The default JSON data binding source creator is at https://github.com/grails/grails-core/blob/v2.5.6/grails-web-databinding/src/main/groovy/org/codehaus/groovy/grails/web/binding/bindingsource/JsonDataBindingSourceCreator.groovy.
An instance of that class is added to the Spring application context by the data binding plugin at https://github.com/grails/grails-core/blob/bd7cc10e17d34f20cedce979724f0e3bacd4cdb4/grails-plugin-databinding/src/main/groovy/org/codehaus/groovy/grails/plugins/databinding/DataBindingGrailsPlugin.groovy#L97.
One thing you could do is write your own class which extends AbstractRequestBodyDataBindingSourceCreator (or just implements DataBindingSourceCreator) and register an instance of that class as a bean named jsonDataBindingSourceCreator and that will replace the default one with yours. Then you are on your own to use whatever techniques you like for parsing the body of the request and creating a Map.

Custom json with Swagger

I'm using Spring boot with Swagger 2(using springfox to wrapper).
I have a big entity that a lot of fields is filled automatic at server side and I have a service to store them. Instead of swagger show all the attributes of this entity like this
I want to show a custom json to store this entity, if possible I would like to show the attributes to send like this
My controller:
#RequestMapping(value = "/cadastrar", method = RequestMethod.POST, produces= "Application/JSON")
public ResponseEntity<?> cadastrarUsuario(#RequestBody #Valid AcessoUsuario usuario, BindingResult result) {
..
}
Please someone could help me? I'm a little lost how to do this with Swagger.
If you don't like all the auto-detected, public fields in your model, you have two choices.
Define an interface that shows what you are interested in, and map that to the operation that is either consuming or producing that entity.
Create a custom model processor which handles types as you like.

Dropwizard good practices

I have seen in a lot of places that a resource class in a dropwizard project has methods for GET and POST. These methods then access data from the database using the DAO and return back a json
public class DropwizardResource {
private DropwizardDAO ddao;
public DropwizardResource (DropwizardDAO ddao) {
this.ddao = ddao;
}
#GET
#Timed
#UnitOfWork
public List<String> getAllResources() {
return ddao.findAll();
}
}
Is it advisable to have a resource initialized with other clients for some other service and then have the json returned by manual conversion?
public class DropwizardResource {
private NonDbClient client;
public DropwizardResource (NonDbClient client) {
this.client = client;
}
#GET
#Timed
#UnitOfWork
public List<String> getAllResources() {
return toJson(client.findAll());
}
}
First off, let's be clear: you can do whatever you like in a Dropwizard resource - there's nothing inherently special about them.
On your specific question on whether you can use "[a client] for some other service" (e.g. another Dropwizard service, or something completely separate), the answer is yes, that's perfectly fine. Note, however, if you're not using Hibernate to access a database within your resource method, you don't need the #UnitOfWork annotation (which is for declaring that a session & transaction should be managed for you when that method is called).
Finally, you ask whether it's okay to "then have the json returned by manual conversion". It's a little hard to answer that question without knowing what client you're thinking of using, and what it returns when you call its findAll method. I can think of a couple of possible scenarios:
You get deserialised plain old Java objects back from your client (regardless of how they were serialised in transit - JSON, XML, crazy proprietary binary protocol, whatever). In this case, you just need to transform these into whatever object you want to return from your Dropwizard resource method (a List<String> in the case of your example). From there, Jersey and Jackson will deal with serialising this to JSON for you and putting that in the response from your resource.
You get a string containing JSON back from your client. In this case, you'll need to manually deserialise the JSON to Java objects (using a Jackson ObjectMapper - you can grab one from the Dropwizard Environment in your application's run method). At that point you can transform then and return them as in the above case.
In either case, I can't think why you'd want to be serialising to JSON (as in your example). That'd give you a String (not a List<String>). Unless you're doing something pretty quirky, you probably don't want to be returning a JSON string from your Dropwizard resource - that will then serialise it as JSON again, and will then result in a string full of JSON being deserialised again at the other end!

How to intercept the marshmalling (json serial/deserial) from a CrudRepository declared as a #RepositoryRestResource?

Given this repository
#RepositoryRestResource( path = "u", itemResourceRel="ui", collectionResourceRel = "us")
public interface IUserRepository extends CrudRepository<Users, Long> {
}
When I go through a controller to call my service method findAllUsers(). I transform the
list of entities result (returned by userRepository.findAll() method provided for free) to a list of domain model objects. This list of domain model objects will get properly deserialize into JSON because I am controlling how to do the deserialization. There is a specific reason why I am doing this, see further below.
Now, if I want to use the userRepository directly, I am running into a loop during the serialization because the object being deserialized are coming from the library com.vividsolutions.jts.geom.Geometry. This class contains a method as described below
Geometry getEnvelope() Returns this Geometrys bounding box.
During the deserialization, jackson runs into a loop, because of it. I am able to correct the deserialization process within my controller. How could I intercept the deserialization from a CrudRepository?
The first idea that came to me was to create an implementation of my interface and override all methods, but it defeats the purpose of doing boiler-plate code.
You show the usage of #RepositoryRestResource I am assuming you're using Spring Data REST to export your repositories. For standard Spring MVC marshaling configuration see the reference docs.
Precisely speaking, you're not intercepting the repositories. Spring Data REST uses Jackson to marshal and unmarshal the responses and requests. Hence you simply customize the Jackson ObjectMapper that SD REST will use. To do so, you extend RepositoryRestMvcConfiguration and override configureJacksonObjectMapper(…):
class MyConfiguration extends RepositoryRestMvcConfiguration {
protected void configureJacksonObjectMapper(ObjectMapper mapper) {
// register custom serialializers, modules etc.
}
}
For customization options in general, have a look at the Jackson reference documentation.