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.
Related
I am trying to intercept the object that is being returned in my controller so that I can create a flat JSON structure of the response, before Spring invokes Jackson's serialization process.
I am going to support a query parameter that allows the client to flatten the response body. Something like:
/v1/rest/employees/{employeId}/id?flat=true
The controller method looks something like:
public Employee getEmployee(...) {}
I would like to avoid implementing this flattening logic in every one of my service calls and continue to return the Employee object.
Is there some kind of facility in Spring that would allow me to A) read the query string and B) intercept the object that is being returned as the response body?
Here's one idea. There may be a better way, but this will work:
Define an extra request mapping to do the flat mapping:
#RequestMapping(path = "/endpoint", params = {"flat"})
public String getFlatThing() {
return flatMapper.writeValueAsString(getThing());
}
// The Jackson converter will do its ordinary serialization here.
#RequestMapping(path = "/endpoint")
public Thing getFlatThing() {
return new Thing();
}
the "flatMapper" implementation can be whatever you like so long as it works.
One option is to use Jackson's ObjectMapper to write the value as json first and then use https://github.com/wnameless/json-flattener to flatten that to your desired output. There may also be a way to define a custom ObjectMapper that does flat mapping, though that would take some more work on your part.
I have a DTO class and some REST services that sometimes return (among other things) a List of those DTOs.
I cannot alter that DTO, as it's used in several places of the project.
However, only for one specific REST service, I need to exclude some of the fields of that DTO object.
Basically I need to be able to apply this solution only at a certain point.
I tried applying #JsonFilter("restrictionFilter") to my DTO class, but then I get an error if I don't use that filter with a mapper every time I marshall the object into a JSON, like this:
final String writeValueAsString = mapper.writer(
new SimpleFilterProvider()
.addFilter("restrictionFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name", "sizeInByte"))
).writeValueAsString(objectsList);
The error is Cannot resolve PropertyFilter with id 'restrictionFilter'; no FilterProvider configured...
This issue sounds like a perfect Decorator design pattern use.
Create a new DTO with a constructor that gets the original DTO and create which get methods you want or ignore whatever get methods you like.
For example:
public class NewDto {
OldDto oldDto;
public NewDto(OldDto oldDto){
this.oldDto = oldDto;
}
public String getName(){
return oldDto.getName();
}
}
Now you will only need to return the NewDto object, like so:
return new NewDto(oldDto)
So I am just trying out Jersey for REST services and it seems to we working out fine. I only expose get services and all of the object types that I expose with these services have an immutable object representation in Java. By default Jersey seems to use a parser (JAXB?), requiring a #XmlRootElement annotation for the class that should be parsed, zero-arg constructor and setters.
I have been using Gson with no zero-arg constructor, no setters and final on all fields with no problems at all. Is there any way to accomplish this with Jersey(i.e. the paser it is using)? I have seen solutions with adapter classes that map data from a immutable object to a mutable representation, but this seems like a lot of boilerplate(new classes, more annotations, etc.) if it can be achieved with Gson without anything added.
Note: 1) I have heard people promote using zero-arg constructor and claim that Gson should not work without it. This is not what I am interested in. 2) I really have tried googling this but my keywords might be off. In other words, humiliate me in moderation.
EDIT 1:
My webservice works if I do like this:
#XmlRootElement
public class Code{
private String code; //Silly object just used for example.
public Code(){}
//(G || S)etters
}
With this class exposing the object:
#GET
#Produces(MediaType.APPLICATION_JSON)
public Set<Code> get(#QueryParam("name") String name) { // Here I want to use a class of my own instead of String name, haven't figured out how yet.
return this.codeService.get(name);
}
If I replace the Code with the following, the webservice stops working:
public class Code{
private final String code;
#JsonCreator
public Code(#JsonProperty("code") String code) {
this.code = code;
}
//Getters omitted
}
What I want is to be able to 1) have immutable objects that can be parsed to/from json and 2) Be able to define something like #RequestBody in Spring MVC for my incoming objects.
Actually this could be pretty easy with Genson. You just need the jar and then configure the Genson feature to use constructors with arguments (if you don't want to put annotations on it).
Genson genson = new GensonBuilder().useConstructorWithArguments(true).create();
// and then register it with jersey
new ResourceConfig().register(new GensonJaxRSFeature().use(genson));
Or you can use JsonProperty on the arguments. See the User Guide for more details.
I'm using spring MVC (spring 3.1.0).
I would like to html encode every string output from my system due to XSS.
But there are outputs (like links) that I don't want to encode in that manner - in order to do that I've decided to use ContextualSerializer and create a class that implements it.
The method createContextual checks for existence of a custom annotation (#NoHTMLEscap) and determine the JsonSerializer to return.
Here is my annotation:
#Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#JacksonAnnotation
public #interface NoHTMLEscap {
}
I tried it and it works just great - on POJOs, but here is a case that fails:
#Controller
#RequestMapping(value = "/something")
public class MyController {
...
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
#ResponseBody
#ResponseStatus(value = HttpStatus.OK)
public String getName(#PathVariable String id) {
return "Here is your answer";
}
}
Spring sends to jackson the returned value and since this method returns String and not POJO - there is no way to check the existence of my annotation - so I cannot actually use my annotation there...
Is there a way to get this information to Jackson's serializer?
I'm not sure but I thought that maybe I need to use a spring specific converter which will never escape strings (not really sure if this will solve correctly my issue and how this can be implemented)?
I don't think jackson can provide a straightforward actual solution for your use-case but I can suggest a different solution.
If you can afford to have a wrapper object around these Strings, let's say LinkWrapper, you can add another serializer of LinkWrapper which will just delegate to your current serializer. In your LinkWrapper object you will annotate the String with your annotation and so your delegated serializer will serialize it unencoded.
Also your output won't be that of an object since your custom serializer only delegates to that of a string serializer.
If you need a code sample just say but I think it's a really simple case of composition.
I'm building a simple RESTFul Service; and for achieve that I need two tasks:
Get an instance of my resource (i.e Book) from request parameters, so I can get that instance to be persisted
Build an XML document from that instance to send the representation to the clients
Right now, I'm doing both things in my POJO class:
public class Book implements Serializable {
private Long id;
public Book(Form form) {
//Initializing attributes
id = Long.parseLong(form.getFirstValue(Book.CODE_ELEMENT));
}
public Element toXml(Document document) {
// Getting an XML Representation of the Book
Element bookElement = document.createElement(BOOK_ELEMENT);
}
I've remembered an OO principle that said that behavior should be where the data is, but now my POJO depends from Request and XML API's and that doesn't feels right (also, that class has persistence anotations)
Is there any standard approach/pattern to solve that issue?
EDIT:
The libraries i'm using are Restlets and Objectify.
I agree with you when you say that the behavior should be where the data is. But at the same time, as you say I just don't feel confortable polluting a POJO interface with specific methods used for serialization means (which can grow considerably depending on the way you want to do it - JSON, XML, etc.).
1) Build an XML document from that instance to send the representation to the clients
In order to decouple the object from serialization logic, I would adopt the Strategy Pattern:
interface BookSerializerStrategy {
String serialize(Book book);
}
public class XmlBookSerializerStrategy implements BookSerializerStrategy {
public String serialize(Book book) {
// Do something to serialize your book.
}
}
public class JsonBookSerializerStrategy implements BookSerializerStrategy {
public String serialize(Book book) {
// Do something to serialize your book.
}
}
You POJO interface would become:
public class Book implements Serializable {
private Long id;
private BookSerializerStrategy serializer
public String serialize() {
return serializer.serialize(this);
}
public void setSerializer(BookSerializerStrategy serializer) {
this.serializer = serializer;
}
}
Using this approach you will be able to isolate the serialization logic in just one place and wouldn't pollute your POJO with that. Additionally, returning a String I won't need to couple you POJO with classes Document and Element.
2) Get an instance of my resource (i.e Book) from request parameters, so I can get that instance to be persisted
To find a pattern to handle the deserialization is more complex in my opinion. I really don't see a better way than to create a Factory with static methods in order to remove this logic from your POJO.
Another approach to answer your two questions would be something like JAXB uses: two different objects, an Unmarshaller in charge of deserialization and a Marshaller for serialization. Since Java 1.6, JAXB comes by default with JDK.
Finally, those are just suggestions. I've become really interested in your question actually and curious about other possible solutions.
Are you using Spring, or any other framework, in your project? If you used Spring, it would take care of serialization for you, as well as assigning request params to method params (parsing as needed).