introduce
In this article, we’ll deal with the transformations that need to take place between the internal entities of Spring applications and the Dtos (Data transfer Objects) outside the client.
Model mapping
Let’s start by introducing the main library for the entity-to-DTO transformation to be performed — ModelMapper. We need to add the following dependencies to pom.xml:
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.2</version>
</dependency>
Copy the code
We then define the ModelMapper bean in the Spring configuration:
@Bean
public ModelMapper modelMapper(a) {
return new ModelMapper();
}
Copy the code
DTO
Next, let’s introduce the DTO aspect of this two-sided problem — Post DTO:
public class PostDto {
private static final SimpleDateFormat dateFormat
= new SimpleDateFormat("yyyy-MM-dd HH:mm");
private Long id;
private String title;
private String url;
private String date;
private UserDto user;
public Date getSubmissionDateConverted(String timezone) throws ParseException {
dateFormat.setTimeZone(TimeZone.getTimeZone(timezone));
return dateFormat.parse(this.date);
}
public void setSubmissionDate(Date date, String timezone) {
dateFormat.setTimeZone(TimeZone.getTimeZone(timezone));
this.date = dateFormat.format(date);
}
// getters and setters
}
Copy the code
Note that two custom date-dependent methods handle date-to-date conversions between client and server:
- GetSubmissionDateConverted () method converts a Date string to the server time zone in the Date, to use it in the persistent Post entity
- The setSubmissionDate() method is used to set the Date of the DTO to the Date of Post in the current user’s time zone
Service
Now let’s look at a Service layer operation — it will obviously work with entities (not Dtos) :
public List<Post> getPostsList(
int page, int size, String sortDir, String sort) {
PageRequest pageReq
= PageRequest.of(page, size, Sort.Direction.fromString(sortDir), sort);
Page<Post> posts = postRepository
.findByUser(userService.getCurrentUser(), pageReq);
return posts.getContent();
}
Copy the code
We will next look at the upper layer of the service, the Controller layer, where the transformation actually takes place.
Controller
Now let’s look at a standard Controller implementation that exposes a simple REST API for Post. We’ll show you a few simple CRUD operations here: Create, update, get one, and get All.
@Controller
class PostRestController {
@Autowired
private IPostService postService;
@Autowired
private IUserService userService;
@Autowired
private ModelMapper modelMapper;
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public List<PostDto> getPosts(...). {
/ /...
List<Post> posts = postService.getPostsList(page, size, sortDir, sort);
return posts.stream()
.map(post -> convertToDto(post))
.collect(Collectors.toList());
}
@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public PostDto createPost(@RequestBody PostDto postDto) {
Post post = convertToEntity(postDto);
Post postCreated = postService.createPost(post));
return convertToDto(postCreated);
}
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public PostDto getPost(@PathVariable("id") Long id) {
return convertToDto(postService.getPostById(id));
}
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.OK)
public void updatePost(@RequestBody PostDto postDto) { Post post = convertToEntity(postDto); postService.updatePost(post); }}Copy the code
Here is our conversion from Post entities to PostDto:
private PostDto convertToDto(Post post) {
PostDto postDto = modelMapper.map(post, PostDto.class);
postDto.setSubmissionDate(post.getSubmissionDate(),
userService.getCurrentUser().getPreference().getTimezone());
return postDto;
}
Copy the code
This is the conversion from DTOS to entities:
private Post convertToEntity(PostDto postDto) throws ParseException {
Post post = modelMapper.map(postDto, Post.class);
post.setSubmissionDate(postDto.getSubmissionDateConverted(
userService.getCurrentUser().getPreference().getTimezone()));
if(postDto.getId() ! =null) {
Post oldPost = postService.getPostById(postDto.getId());
post.setRedditID(oldPost.getRedditID());
post.setSent(oldPost.isSent());
}
return post;
}
Copy the code
So, as you can see, the transformation logic is fast and simple with the help of the model mapping — we use the map API of the mapping to get the transformed data without writing any transformation logic.
Unit testing
Finally, let’s do a very simple test to ensure that the transformation between entities and Dtos works:
public class PostDtoUnitTest {
private ModelMapper modelMapper = new ModelMapper();
@Test
public void whenConvertPostEntityToPostDto_thenCorrect(a) {
Post post = new Post();
post.setId(Long.valueOf(1));
post.setTitle(randomAlphabetic(6));
post.setUrl("www.test.com");
PostDto postDto = modelMapper.map(post, PostDto.class);
assertEquals(post.getId(), postDto.getId());
assertEquals(post.getTitle(), postDto.getTitle());
assertEquals(post.getUrl(), postDto.getUrl());
}
@Test
public void whenConvertPostDtoToPostEntity_thenCorrect(a) {
PostDto postDto = new PostDto();
postDto.setId(Long.valueOf(1));
postDto.setTitle(randomAlphabetic(6));
postDto.setUrl("www.test.com"); Post post = modelMapper.map(postDto, Post.class); assertEquals(postDto.getId(), post.getId()); assertEquals(postDto.getTitle(), post.getTitle()); assertEquals(postDto.getUrl(), post.getUrl()); }}Copy the code
conclusion
This is an article about simplifying entity-to-DTO and DTO-entity transformations in the Spring REST API by using a model mapping library rather than writing these transformations manually.
Welcome to follow my official account: Qulingfeng, for exclusive learning resources and daily dry goods push. If you are interested in my feature content, you can also follow my blog: sagowiec.com