We are using mapstruct in our project . While it works awesum for a dto to a domain object (say EmployeeDTO to EmployeeData with similiar properties) - we have a need to process an incoming json string . We are trying to write a very generic mapper that maps from the incoming json string to a java object.
So lets say we have EmployeeDTO like this
{ id: 1,name="xxx"} but its coming as a string and i have a mapstruct mapper thusly
#Mapper
EmployerMapper()
{
EmployeeData toEmployeeFromJsonString( String empString} ;// where empString is a jsonString
}
its not working properly and i am not getting the appropriate object created with the right property from the json String( I also tried with jsonobject as well but that doesn't work either)
The reason why we cant have specific DTOs is because we want to have a loose coupling between the Employee microservice and the rest of the microservices ( there are a handful )
mapstruct is not creating the appropriate getters and setters and there could be more properties in the DTO that we dont care in this microservice.
1. Is there support for json objects in mapstruct directly?
2. If i enhance it with GSON support how can i integrate it with mapstruct so that i have only one way of mapping in my product.
No. MapStruct is a mapping framework, not a parsing framework
For deserialising JSON you have few specific frameworks: checkout How to parse JSON in Java
Related
I'm migrating a legacy application from Spring-core 4 to Springboot 2.5.2.
The application is using spring-data-rest (SDR) alongside spring-data-mongodb to handle our entities.
The legacy code was overriding SDR configuration by extending the RepositoryRestMvcConfiguration and overriding the bean definition for persistentEntityJackson2Module to remove serializerModifier and deserializerModifier.
#EnableWebMvc
#EnableSpringDataWebSupport
#Configuration
class RepositoryConfiguration extends RepositoryRestMvcConfiguration {
...
...
#Bean
#Override
protected Module persistentEntityJackson2Module() {
// Remove existing Ser/DeserializerModifier because Spring data rest expect linked resources to be in href form. Our platform is not tailored for it yet
return ConverterHelper.configureSimpleModule((SimpleModule) super.persistentEntityJackson2Module())
.setDeserializerModifier(null)
.setSerializerModifier(null);
}
It was to avoid having to process DBRef as href link when posting entities, we pass the plain POJO instead of the href and we persist it manually before the entity.
Following the migration, there is no way to set the same overrided configuration but to avoid altering all our processes of creation we would like to keep passing the POJO even for DbRef.
I will add an exemple of what was working before :
We have the entity we want to persist :
public class EntityWithDbRefRelation {
....
#Valid
#CreateOnTheFly // Custom annotation to create the dbrefEntity before persisting the current entity
#DBRef
private MyDbRefEntity myDbRefEntity;
}
the DbRefEntity
public class MyDbRefEntity {
...
private String name;
}
and the JSON Post request we are doing:
POST base-api/entityWithDbRefRelations
{
...
"myDbRefEntity": {
"name": "My own dbRef entity"
}
}
In our database this request create our myDbRefEntity and then create the target entityWithDbRefRelation with a dbRef linked to the other entity.
Following the migration, the DBRef is never created because when deserializing the JSON into a PersistingEntity, the myDbRefEntity is ignored because it's expecting an href instead of a complex object.
I see 3 solutions :
Modify all our process to first create the DBRef through one request then create our entity with the link to the dbRef
Very costly as we have a lot of services creating entities through this backend
Compliant with SDR
Define our own rest mvc controllers to do operations, to ignore the SDR mapping machanism
Add AOP into the RepositoryRestMvcConfiguration around the persistentEntityJackson2Module to set le serializerModifier and deserializedModifier to null
I really prefer to avoid this solution as Springboot must have remove a way to configure it on purpose and it could break when migrating on newer version
Does anyone know a way to continue considering the property as a complex object instead of an href link except from my 3 previous points ?
Tell me if you need more information and thanks in advance for your help!
I am new in Spring MVC. My question is, why do we need jackson databind? Because We can receive the Request Params by #ModelAttribute and requests through http PUT or POST by #RequestBody. I can't find a reason why we need jackson databind to convert json/xml to POJO or vice versa.
Thanks.
Why do we need jackson databind?
Because representing structured data is much easier using XML (or JSON) than using simple name-value pairs.
Because it is more convenient to send and receive JSON from the client side when you are doing AJAX.
Because once you have to deal with sending and receiving JSON or XML in the server side Java app, it is more convenient to deal with structured data as POJOs.
None of the above points mean you have to use a binding. There are other ways of dealing with each of the above. But many Java developers think that data bindings the better way to go: more efficient in terms of developer time, and more reliable. Especially if you are implementing services with a complex APIs. That's why they are popular.
And as other answers/comments point out, if you are using #RequestBody, then that is using a binding library under the hood to give you the POJOs. In the case of Spring, it is Jackson that is being used.
By default, when an endpoint expects a JSON document as input and a given controller method argument is annotated with #RequestBody, Spring will use Jackson databind features to map the incoming JSON document to a Java object. You don't need to use the Jackson's ObjectMapper directly, as Spring does it for you.
For example purposes, consider the following HTTP request to create a comment:
POST /comments HTTP/1.1
Host: example.org
Content-Type: application/json
{
"content": "Lorem ipsum"
}
And the following class which represents a comment:
#Data
public class Comment {
private String content;
}
A #RestController to handle such request would be like:
#RestController
#RequestMapping("/comments")
public class CommentController {
#PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Foo> createComment(#RequestBody Comment comment) {
// By default, Spring will rely on Jackson databind to map the incoming
// JSON document to the comment argument annotated with #RequestBody
...
}
}
If you are interested in the Spring component that maps the incoming JSON document to a Java object, have a look at the MappingJackson2HttpMessageConverter class:
Implementation of HttpMessageConverter that can read and write JSON using Jackson 2.x's ObjectMapper.
This converter can be used to bind to typed beans, or untyped HashMap instances.
By default, this converter supports application/json and application/*+json with UTF-8 character set. [...]
If you are creating a HTTP API and exposing resources that can be manipulated with JSON representations, it's unlikely you'll use #ModelAtribute. Such annotation is particularly useful when you are dealing with web views.
When you get some request in some data types like json/xml, the Spring MVC platform will try to deserialize this request attributes in some model object of your project.
But the platform itself don't provide a des-serialize implementation out of the box. So it will try to use some des-serializer provider in the classpath like jackson, jersey, gson, etc.
As you said - is possible to use #ModelAttribute - but this annotation is a better option to a request from a form view in the front-end. In cases rest json/xml requests, the #ModelAttribute won't be able to convert correctly the received data to a business class of your program.
In my Spring Boot application I use a following DTO with #RestController:
public abstract class ComparableQuery extends BaseQuery {
private final Object value;
...
}
Everything works fine but when I use Spring RestTemplate and pass java.util.Date as ComparableQuery.value I see that Jackson serialize the date object into the following "magic" number:
"value":1009836000000
Right now I don't understand how the date object serialized into the 1009836000000 number representation and how to emulate it when I use for example AngularJS as a client of my back-end API. Please advise.
This is a very similar problem as described in this answer about null handling with jackson and spring boot.
The corresponding configuration for date formatting in application.properties should look like:
spring.jackson.write-dates-as-timestamps=false
There are following URLS - /users/2/profile , /users/2/userPosts
I need to concat output of both Spring Data REST results in server side and build single JSON from them and send on different URL /users/2/custom.
So, I am thinking to make 2 calls to SDR urls from Spring MVC, can we do this using RestTemplate and some JSON concat utility , here server and database is on same machine so RestTemplate will probably have localhost
An example will help
You might rather want to look into the projections feature of Spring Data REST which allows you to craft custom responses by using interfaces as described in this blog post.
As both properties (profile and userPosts) seem to be associations of a user item resource it should be sufficient to do something like this:
#Projection(types = User.class)
interface UserWithDetails {
// List getters for basic properties you want to expose…
// Add dedicated getters for associations to be included
Profile getProfile();
List<Post> getUserPosts();
}
Clients can now pass a projection parameter to the resources exposed to see the expanded representation.
As an alternative, you can create these kinds of interfaces for Profile and Post and configure #RepositoryRestResource on the repositories for both of these types to contain excerptProjection = YourProjectionInterface.class. This will cause the projections to be rendered whenever an association is included in the response (i.e. an actually-linked-to-resource could be embedded).
I am using MappingJacksonHttpMessageConverter in Spring MVC to automatically serialize objects like this:
#RequestMapping(value="/*/getAccount", method=RequestMethod.GET)
#ResponseBody
public Account getAccountAction() {
Account account = accountService.getAccount();
return account;
}
Is it possible to configure which properties of the object are serialized? In my example, Account has 3 collections as properties and serializing all these contents would result in a huge object tree. Here I only want to return the flat object.
Sincerely,
Erik
Did you already try to use the Jackson Annotations?
There is the Annotation #JsonIgnoreProperties that can be used to ignore a given list of properties for serialization on class level and there is #JsonIgnore to mark properties to ignore for serialization on field level.
I could figure it out: Configure Jackson with annotatons, it is described in detail in the Jackson configuration.