Can we convert entity to dto/pojo object patially? - java

Is there any approach to convert entity to dto object partially? Or are there any best practices for using the entity, pojo/dto and response object in MVC pattern?

You have couple of approaches. I assume you have a web project.
Manual mapping approach. Create Dto map it manually to your entity. This would involve all the boilerplate code around it - Builders, all argument Constructor, getters, setters whatever approach you will use to populate the DTO.
The different hydration Technics apply in different situations. Builder pattern presumes you would have an immutable objects. Getters and Setters are supported out opf the box by frameworks as Jackson. You may decide to minimize your boilerplate code by using lombok, imutables or other frameworks.
Mapping framework. Another option would be to use a supplied mapper like ObjectMapper, or FastMap there may be other choices. This would remove large portion of manual mapping you would need to establish following aproach 1.
Deserializer. Example of such aproach would be spring-data-rest where your repository returns the entities straight which are than serialized in JSON . Using normal spring MVC this would be to return your entity straight to your controller layer and based on annotations or other means (serializers) map it to your network format JSON, XML whatever you use.
These are the different options. Which one is best depends on your usecase.

One of possible approaches is copy constructor. The example below.
// entity annotations ...
public class EntityExample {
private Long id;
private String name;
private Integer score;
// getters and setters ...
}
public class DtoExample {
private Long id;
pricate String name;
// For serialization and deserialization
public DtoExample() {
}
public DtoExample(EntityExample entity) {
this.id = entity.getId();
this.name = entity.getName();
}
// getters and setters ...
}

Related

Validation through "mixins"

I am developing a RESTful API in Spring Boot 2+, for which I need to perform several validations. Nothing really fancy, just the typical #NotNull, #NotEmpty, #Max, #Min, #Email, #Regex, #Future, etc stuff...
Except that I have beans from an API that I must use yet cannot modify. This means that I cannot annotate the fields and methods in those DTOs.
It would be great if I could create mixin-like classes or interfaces with the same structure of the real DTOs I must use in the API, on which I would happily place bean-validation's annotations.
For example, if I had the following DTOs that I couldn't modify:
public class Person {
private String name;
private String dateOfBirth;
private Address address;
// constructors, getters and setters ommited
}
public class Address {
private String street;
private String number;
private String zipCode;
// constructors, getters and setters ommited
}
I would create the following 2 interfaces that mimic their structure and annotate them as I need:
public interface PersonMixin {
#NotBlank String name();
#Past String dateOfBirth();
#Valid #NotNull Address address();
}
public interface AddressMixin {
#NotBlank String street();
#Positive int number();
#NotBlank String zipCode(); // Or maybe a custom validator
}
As you see, the name of the methods in the interfaces match the names of the properties of the bean classes. This is just one possible convention...
Then, ideally, somewhere while the app is loading (typically some #Configuration bean) I would be very happy to do something along the lines of:
ValidationMixinsSetup.addMixinFor(Person.class, PersonMixin.class);
ValidationMixinsSetup.addMixinFor(Address.class, AddressMixin.class);
Except that ValidationMixinsSetup.addMixinFor is pure fantasy, i.e. it doesn't exist.
I know that there exists a similar construct for Jackson regarding JSON serialization/deserialization. I've found it extremely useful many times.
Now, I've been looking at both Spring and Hibernate Validator's source code. But it's not a piece of cake... I've dug into ValidatorFactory, LocalValidatorFactoryBean, TraversableResolver implementations, but I haven't been able to even start a proof-of-concept. Could anyone shed some light into this? I.e. not how to implement the whole functionality, but just how and where to start. I'm after some hints regarding which are the essential classes or interfaces to extend and/or implement, which methods to override, etc.
EDIT 1: Maybe this approach is not the best one. If you think there's a better approach please let me know.
EDIT 2: As to this approach being overly complicated, too convoluted, Rube Goldberg, etc, I appreciate and respect these points of view, but I'm not asking whether validation through mixins is good or bad, convenient or inconvenient, neither why it might be like so. Validation through mixins has pros on its own and I think it could be a good approach for some valid use cases, i.e. having declarative validation instead of scripted or programmatic validation while also separating validation from the model, letting the underlying framework do the actual validation job while I only specify the constraints, etc.
Using programmatic API (as mentioned in the comment) in case of Person you could apply next mappings for your constraints:
HibernateValidatorConfiguration config = Validation.byProvider( HibernateValidator.class ).configure();
ConstraintMapping mapping = config.createConstraintMapping();
mapping.type( Person.class )
.field( "name" )
.constraint( new NotNullDef() )
.field( "number" )
.constraint( new PositiveDef() )
.field( "address" )
.constraint( new NotNullDef() )
.valid();
Validator validator = config.addMapping( mapping )
.buildValidatorFactory()
.getValidator();
And as you are using Spring - you would need to do that in one of your sping config files where you define a validator bean.

Should i use model classes or payload classes to serialize a json response

I'm using spring boot with mysql to create a Restful API. Here's an exemple of how i return a json response.
first i have a model:
#Entity
public class Movie extends DateAudit {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Date releaseDate;
private Time runtime;
private Float rating;
private String storyline;
private String poster;
private String rated;
#OneToMany(mappedBy = "movie", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MovieMedia> movieMedia = new ArrayList<>();
#OneToMany(mappedBy = "movie", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MovieReview> movieReviews = new ArrayList<>();
#OneToMany(mappedBy = "movie", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MovieCelebrity> movieCelebrities = new ArrayList<>();
// Setters & Getters
}
and correspond repository:
#Repository
public interface MovieRepository extends JpaRepository<Movie, Long> {
}
Also i have a payload class MovieResponse which represent a movie instead of Movie model, and that's for example if i need extra fields or i need to return specific fields.
public class MovieResponse {
private Long id;
private String name;
private Date releaseDate;
private Time runtime;
private Float rating;
private String storyline;
private String poster;
private String rated;
private List<MovieCelebrityResponse> cast = new ArrayList<>();
private List<MovieCelebrityResponse> writers = new ArrayList<>();
private List<MovieCelebrityResponse> directors = new ArrayList<>();
// Constructors, getters and setters
public void setCelebrityRoles(List<MovieCelebrityResponse> movieCelebrities) {
this.setCast(movieCelebrities.stream().filter(movieCelebrity -> movieCelebrity.getRole().equals(CelebrityRole.ACTOR)).collect(Collectors.toList()));
this.setDirectors(movieCelebrities.stream().filter(movieCelebrity -> movieCelebrity.getRole().equals(CelebrityRole.DIRECTOR)).collect(Collectors.toList()));
this.setWriters(movieCelebrities.stream().filter(movieCelebrity -> movieCelebrity.getRole().equals(CelebrityRole.WRITER)).collect(Collectors.toList()));
}
}
As you can see i divide the movieCelebrities list into 3 lists(cast, directos and writers)
And to map a Movie to MovieResponse I'm using ModelMapper class:
public class ModelMapper {
public static MovieResponse mapMovieToMovieResponse(Movie movie) {
// Create a new MovieResponse and Assign the Movie data to MovieResponse
MovieResponse movieResponse = new MovieResponse(movie.getId(), movie.getName(), movie.getReleaseDate(),
movie.getRuntime(),movie.getRating(), movie.getStoryline(), movie.getPoster(), movie.getRated());
// Get MovieCelebrities for current Movie
List<MovieCelebrityResponse> movieCelebrityResponses = movie.getMovieCelebrities().stream().map(movieCelebrity -> {
// Get Celebrity for current MovieCelebrities
CelebrityResponse celebrityResponse = new CelebrityResponse(movieCelebrity.getCelebrity().getId(),
movieCelebrity.getCelebrity().getName(), movieCelebrity.getCelebrity().getPicture(),
movieCelebrity.getCelebrity().getDateOfBirth(), movieCelebrity.getCelebrity().getBiography(), null);
return new MovieCelebrityResponse(movieCelebrity.getId(), movieCelebrity.getRole(),movieCelebrity.getCharacterName(), null, celebrityResponse);
}).collect(Collectors.toList());
// Assign movieCelebrityResponse to movieResponse
movieResponse.setCelebrityRoles(movieCelebrityResponses);
return movieResponse;
}
}
and finally here's my MovieService service which i call in the controller:
#Service
public class MovieServiceImpl implements MovieService {
private MovieRepository movieRepository;
#Autowired
public void setMovieRepository(MovieRepository movieRepository) {
this.movieRepository = movieRepository;
}
public PagedResponse<MovieResponse> getAllMovies(Pageable pageable) {
Page<Movie> movies = movieRepository.findAll(pageable);
if(movies.getNumberOfElements() == 0) {
return new PagedResponse<>(Collections.emptyList(), movies.getNumber(),
movies.getSize(), movies.getTotalElements(), movies.getTotalPages(), movies.isLast());
}
List<MovieResponse> movieResponses = movies.map(ModelMapper::mapMovieToMovieResponse).getContent();
return new PagedResponse<>(movieResponses, movies.getNumber(),
movies.getSize(), movies.getTotalElements(), movies.getTotalPages(), movies.isLast());
}
}
So the question here: is it fine to use for each model i have a payload class for the json serialize ? or it there a better way.
also guys id it's there anything wrong about my code feel free to comment.
I had this dilemma not so long back, this was my thought process. I have it here https://stackoverflow.com/questions/44572188/microservices-restful-api-dtos-or-not
The Pros of Just exposing Domain Objects
The less code you write, the less bugs you produce.
despite of having extensive (arguable) test cases in our code base, I have came across bugs due to missed/wrong copying of fields from domain to DTO or viceversa.
Maintainability - Less boiler plate code.
If I have to add a new attribute, I don't have to add in Domain, DTO, Mapper and the testcases, of course. Don't tell me that this can be achieved using a reflection beanCopy utils like dozer or mapStruct, it defeats the whole purpose.
Lombok, Groovy, Kotlin I know, but it will save me only getter setter headache.
DRY
Performance
I know this falls under the category of "premature performance optimization is the root of all evil". But still this will save some CPU cycles for not having to create (and later garbage collect) one more Object (at the very least) per request
Cons
DTOs will give you more flexibility in the long run
If only I ever need that flexibility. At least, whatever I came across so far are CRUD operations over http which I can manage using couple of #JsonIgnores. Or if there is one or two fields that needs a transformation which cannot be done using Jackson Annotation, As I said earlier, I can write custom logic to handle just that.
Domain Objects getting bloated with Annotations.
This is a valid concern. If I use JPA or MyBatis as my persistent framework, domain object might have those annotations, then there will be Jackson annotations too. If you are using Spring boot you can get away by using application-wide properties like mybatis.configuration.map-underscore-to-camel-case: true , spring.jackson.property-naming-strategy: SNAKE_CASE
Short story, at least in my case, cons didn't outweigh the pros, so it did not make any sense to repeat myself by having a new POJO as DTO. Less code, less chances of bugs. So, went ahead with exposing the Domain object and not having a separate "view" object.
Disclaimer: This may or may not be applicable in your use case. This observation is per my usecase (basically a CRUD api having 15ish endpoints)
We should each layer separate from other. As in your case, you have defined the entity and response classes. This is right way to separate things, we should never send the entity in the response. Even for request thing we should have a class.
What the issue if we are sending entity instead of response dto.
Not available to modify them because we already expose it with our client
Sometimes we don't want to serialize some fields and send as response.
Some overhead are there to translate request to domain, entity to domain etc. But its okay to keep more organized. ModelMapper is the best choice for translation purpose.
Try to use construct injection instead of setter for mandate dependency.
It is always recommended to separate DTO and Entity.
Entity should interact with DB/ORM and DTO should interact with client layer(Layer for request and response) even if the structure of Entity and DTO same.
Here Entity is Movie and
DTO is MovieResponse
Use your existing class MovieResponse for request & response.
Never use Movie class for request & response.
and the class MovieServiceImpl should contain business logic for converting Entity to DTO, Or you can use Dozer api to do auto conversion.
The reason for sepating:
In case you need to add/remove new elements in Request/response you dont have to change much code
if 2 entity have 2 way mapping(e.g. one-to-many/many-to-many relationship) then
JSON object cant be created if object have nested data, this will throw error while serializing
if Anything changed in DB or Entity, then this will not affect JSON Response(most of the time).
Code will be clear and easy to maintain.
On one side you should separate them because sometimes some of the JPA annotations which you use in your model don't work well with the json processor annotations. And yes, you should keep the things separated.
What if you later decide to change your data layer? Will you have to rewrite all your client side?
On the other side, there is this problem of mapping. For that, you can use a library with a small performance penalty.
DTO is a design pattern and solves the problem of fetching as maximum useful data from a service as possible.
In case of a simple application as yours, the DTOs tend to be similar to the Entity classes. However for certain complex applications, DTOs can be extended to combine data from various entities to avoid multiple requests to the server and thus save valuable resources and request-response time.
I would suggest not to duplicate the code in a simple case like this and use model classes in response to the APIs as well. Using separate response classes as DTOs will not solve any purpose and will only make maintaining the code difficult.
While most people have answered pros and cons of using DTO objects, I would like to give my 2 cents. In my case DTO was necessary because not all fields persisted in database were captured from user. There were a few fields which were computed based on user input(of other fields) and were not exposed to users. Also, it can also reduces the size of payload which could result in better performance in such cases.
I advocate for separating the "Payload" or "Data" object from the "Model" or "Display" object. Pretty much always. This just keeps things easier to manage.
Here's an example:
Let's say you need to hit an API that gives you data about cats for sale. Then you parse the data into a cat model object and populate a list of cats that is then displayed to the user. Cool.
But now you want to integrate another API and pull cats from 2 databases. But you run into a problem. One API returns furColor for the color and the new one returns catColor for the color.
If you were using the same object to also display the info, you have some options:
Add both furColor and catColor to the model object, make them both optional, and do some kind of computed property to check which one is set and use that one to display the color
In reality, this is rarely an option because the responses will usually be much more different than just one value like this so you would likelly need a whole new parser anyway
Add a new data object and then also a new adapter and then have to do some kind of check to know which adapter to use when
Something else that still isn't pretty or fun to work with
However, if you create a data object that catches the response, and then a display object that has only the info needed to populate the list, this becomes really easy:
You have a data object that captures the response from the first API
Now make a data object that captures the response from the second API
Now all you need is some kind of simple mapper to map the response to the Display Object
Now both will be converted to a common simple display object, and the same adapter can be used to display the new cats without additional work
This also will make storing the data locally much cleaner.

Spring projections without Spring Data REST

spring-data-rest provides a fantastic way how to specify the view of an entity - Spring projections. I am curious if there is a way for achieving similar functionality without using spring-data-rest - just repositories and simple rest controllers.
Let's say I have an entity:
#Entity
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstname;
private String lastname;
// …
}
and two controller endpoints. One should return the full entity and the second only subset of the entity (eq. just firstname, although the real example is a bit more complex). Basically, I would like to avoid returning nested collections from some endpoints.
I know that I can achieve this by creating a second entity pointing to the same table that contains only the values needed but the problem is that I would have to create a separate repository for it as well and it creates a lot of unnecessary boilerplate.
So my question is, do I need to have two entities with two separate repositories or is there some more elegant way how to do this in Spring?
You can use Spring's property filters to filter out few fields from response to an API:
#RequestMapping(...)
public MappingJacksonValue getUserEntities(...)
Page<UserEntity> entities = service.findAll();
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(entities);
FilterProvider filters = new SimpleFilterProvider()
.addFilter("UserEntity", SimpleBeanPropertyFilter
.filterOutAllExcept("fieldName"));
mappingJacksonValue.setFilters(filters);
return mappingJacksonValue;
}
You could use JSON Views to filter out the fields you need. Here are some examples.
Alternatively you could create a DTO instead of a full entity but that is, IMHO an elegant approach.

Best way to convert a JPA entity to REST representations using JAX-RS and Jackson

I'm looking for a way to export some JPA entities to a REST API, but instead of sending the whole entity every time I want to share just some specific fields depending of the entry point. Here's a small example:
Say we have an Author class with few fields:
#Entity
public class Author implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = SEQUENCE)
private Long id;
#NotNull
#Size(min = 1, message = "{required.field}")
private String name;
#NotNull
#Size(min = 1, message = "{required.field}")
private String country;
private LocalDate birthDate;
// getters and setters
}
And say we have this REST service (just two methods):
#Path("authors")
public class AuthorREST {
#Inject
private AuthorBC bc;
#GET
#Produces("application/json")
public List<Author> find(#QueryParam("q") String query) throws Exception {
List<Author> result;
if (Strings.isEmpty(query)) {
result = bc.findAll();
} else {
result = bc.find(query);
}
return result;
}
#GET
#Path("{id}")
#Produces("application/json")
public Author load(#PathParam("id") Long id) throws Exception {
Author result = bc.load(id);
if (result == null) {
throw new NotFoundException();
}
return result;
}
}
Now, this way, I'll always have the 4 fields when my API is called.
I understand that if I use Jackson I can set an #JsonIgnore to fields I want to ignore, and they will always be ignored.
But what if I want that, in some cases, my whole entity is returned by one service, and in other service (or other method in the same service), only 2 or 3 fields are returned?
Is there a way to do it?
#JsonView and mix-in
You already know you can use annotations such as #JsonIgnore and #JsonIgnoreProperties to make Jackson ignore some properties.
You also could check the #JsonView annotation. For some details on how to use #JsonView with JAX-RS, have a look here.
If modifying the JPA entities is not an option, consider mix-in annotations as described in this answer.
Data Transfer Object
Data Transfer Object (DTO) is a pattern that was created with a very well defined purpose: transfer data to remote interfaces, just like webservices. This pattern fits very well in REST APIs and using DTOs you'll have more flexibility in the long run. You can have tailored classes for your needs, once the REST resource representations don't need to have the same attributes as the persistence objects.
To avoid boilerplate code, you can use mapping frameworks such as MapStruct to map your REST API DTOs from/to your persistence objects.
For details on the benefits of using DTOs, check the following answers:
Why you should use DTOs in your REST API
Using tailored classes of request and response
To give better names to your DTOs, check the following answer:
Giving meaningful names to your DTOs
If you want to decouple the parsing from your JPA entities and return only certain attributes you can always use Mixins for this purpose.
http://www.cowtowncoder.com/blog/archives/2009/08/entry_305.html
https://github.com/FasterXML/jackson-docs/wiki/JacksonMixInAnnotations
One more thing. If you want things to be dynamic in one service to return one representation in another to return another representation. Your option is to write a custom JSON serializer!
Check this post for how to create a customer serializer:
How do I use a custom Serializer with Jackson?
For myself I found it quite suitable to use #JsonView annotation. So you can define fields to be rendered in specific view. You can find more info here http://wiki.fasterxml.com/JacksonJsonViews
I think you can write a custom MessageBodyWriter using Jersey framework and you can control the response payload the way you want. Here you have to write few lines of code in-order to manage the response payload. For more information please visit https://jersey.java.net/documentation/latest/message-body-workers.html#d0e6826
I would use Spring Data REST and then use the ApiModel annotation to hide the attributes you do not want exposed.

Is it ok to pass interface of DTO to DAO

It's about passing interface of DTO to DAO.
For example I have following code
public interface User {
String getName();
}
public class SimpleUser implements User {
protected String name;
public SimpleUser(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
}
// Mapped by Hibernate
public class PersistentUser extends SimpleUser {
private Long id;
// Constructor
// Getters for id and name
// Setters for id and name
}
I'm using generic DAO. Is it ok if I create DAO with using interface User instead PersistentUser?
User user = new PersistentUser(name);
UserDao.create(user);
I read a lot of topics on stack but not figured out is this approach ok or no. Please help me. Maybe this is stupid and I can achive only problems.
About separating beans.
I did this because some classes I want to share via API module, that can be used outside to create entities and pass them to my application. Because they uses interface I developed so I can pass them to my DAO for persisting.
Generally, I would say it is ok, but there are a few hidden problems. A developer could cast the object down or access some state via a toString method that shouldn't be accessible. If you don't be careful, it could happen that state is serialized as JSON/XML in webservices that shouldn't be serialized. The list goes on.
I created Blaze-Persistence Entity Views for exactly that use case. You essentially define DTOs for JPA entities as interfaces and apply them on a query. It supports mapping nested DTOs, collection etc., essentially everything you'd expect and on top of that, it will improve your query performance as it will generate queries fetching just the data that you actually require for the DTOs.
The entity views for your example could look like this
#EntityView(PersistentUser.class)
interface User {
String getName();
}
Querying could look like this
List<User> dtos = entityViewManager.applySetting(
EntityViewSetting.create(User.class),
criteriaBuilderFactory.create(em, PersistentUser.class)
).getResultList();

Categories

Resources