WARNING! This is a new feature, of BETA quality. Use it at your own risk! Feedback is highly welcome!
By default, JHipster uses its domain objects (typically JPA entities) directly in its REST endpoints. This has a lot of benefits, the main one being that it makes the code easy to use, understand and extend.
For complex use cases, however, you might want to use Data Transfer Objects (or DTOs) that will be exposed by the REST endpoints. Those objects add an extra layer on top of the domain objects, and are specifically tuned for the REST layer: their main benefit is that they can aggregate several domain objects.
When generating a JHipster entity, you have the option to also generate a DTO for this entity. If you select that option:
User
entity will add a userId
field and a userLogin
field to the DTO.@JsonIgnore
annotation on those fields).Set
. Thus, this can only work if the other entity also uses DTOs.As DTOs look a lot like entities, it’s a frequent requirement to have a solution to map them automatically with each other.
The selected solution in JHipster is to use MapStruct. It is an annotation processor, plugged into the Java compiler, that will generate the required mapping automatically.
We have found it very clean and efficient, and liked that it does not use reflection (which is bad for performance when used as heavily as in a mapper).
It has a limitation:
MapStruct is an annotation processor, and as such can be set up to be run automatically when your IDE compiles the project. We have found this approach difficult to use, and prefer to use the mvn compile
goal directly.
If you want to configure your IDE to use MapStruct, you will need to add the MapStruct processor to your pom.xml
dependencies:
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
If you find a good workflow using your IDE as well as Maven, please send us some feedback!
MapStruct mappers are configured as Spring Beans, and support dependency injection. One nice tip is that you can inject a Repository
into a mapper, so you can fetch a managed JPA entity from the mapper, using its ID.
Here is an example code, fetching a User
entity:
@Mapper
public abstract class CarMapper {
@Inject
private UserRepository userRepository;
@Mapping(source = "user.id", target = "userId")
@Mapping(source = "user.login", target = "userLogin")
public abstract CarDTO carToCarDTO(Car car);
@Mapping(source = "userId", target = "user")
public abstract Car carDTOToCar(CarDTO carDTO);
public User userFromId(Long id) {
if (id == null) {
return null;
}
return userRepository.findOne(id);
}
}
In the future, if we find out that MapStruct is not enough for everyone, we will add another DTO mapper. The easiest solution would be to generate that mapping automatically with JHipster, and not use any third-party library.