Merge pull request #15225 from ovidiumihaitacu/master

[BAEL-7067] Difference Between Entity and DTO
This commit is contained in:
Liam Williams 2023-12-07 21:51:40 +00:00 committed by GitHub
commit 93ebe9cda7
14 changed files with 616 additions and 0 deletions

View File

@ -0,0 +1,12 @@
package com.baeldung.entitydtodifferences;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.entitydtodifferences.controller;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.baeldung.entitydtodifferences.dto.UserCreationDto;
import com.baeldung.entitydtodifferences.dto.UserResponseDto;
import com.baeldung.entitydtodifferences.mapper.UserMapper;
import com.baeldung.entitydtodifferences.repository.UserRepository;
@RestController
@RequestMapping("/users")
public class UserController {
private final UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping
public List<UserResponseDto> getUsers() {
return userRepository.findAll()
.stream()
.map(UserMapper::toDto)
.collect(Collectors.toList());
}
@PostMapping
public UserResponseDto createUser(@RequestBody UserCreationDto userCreationDto) {
return UserMapper.toDto(userRepository.save(UserMapper.toEntity(userCreationDto)));
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.entitydtodifferences.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
public class BookDto {
@JsonProperty("NAME")
private final String name;
@JsonProperty("AUTHOR")
private final String author;
// Default constructor for Jackson deserialization
public BookDto() {
this(null, null);
}
public BookDto(String name, String author) {
this.name = name;
this.author = author;
}
public String getName() {
return name;
}
public String getAuthor() {
return author;
}
}

View File

@ -0,0 +1,48 @@
package com.baeldung.entitydtodifferences.dto;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
public class UserCreationDto {
@JsonProperty("FIRST_NAME")
private final String firstName;
@JsonProperty("LAST_NAME")
private final String lastName;
@JsonProperty("ADDRESS")
private final String address;
@JsonProperty("BOOKS")
private final List<BookDto> books;
// Default constructor for Jackson deserialization
public UserCreationDto() {
this(null, null, null, null);
}
public UserCreationDto(String firstName, String lastName, String address, List<BookDto> books) {
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
this.books = books;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getAddress() {
return address;
}
public List<BookDto> getBooks() {
return books;
}
}

View File

@ -0,0 +1,48 @@
package com.baeldung.entitydtodifferences.dto;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
public class UserResponseDto {
@JsonProperty("ID")
private final Long id;
@JsonProperty("FIRST_NAME")
private final String firstName;
@JsonProperty("LAST_NAME")
private final String lastName;
@JsonProperty("BOOKS")
private final List<BookDto> books;
// Default constructor for Jackson deserialization
public UserResponseDto() {
this(null, null, null, null);
}
public UserResponseDto(Long id, String firstName, String lastName, List<BookDto> books) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.books = books;
}
public Long getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public List<BookDto> getBooks() {
return books;
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.entitydtodifferences.entity;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "books")
public class Book {
@Id
private String name;
private String author;
// Default constructor for JPA deserialization
public Book() {
}
public Book(String name, String author) {
this.name = name;
this.author = author;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}

View File

@ -0,0 +1,90 @@
package com.baeldung.entitydtodifferences.entity;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private String address;
@OneToMany(cascade = CascadeType.ALL)
private List<Book> books;
// Default constructor for JPA deserialization
public User() {
}
public User(String firstName, String lastName, String address, List<Book> books) {
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
this.books = books;
}
public String getNameOfMostOwnedBook() {
Map<String, Long> bookOwnershipCount = books.stream()
.collect(Collectors.groupingBy(Book::getName, Collectors.counting()));
return bookOwnershipCount.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse(null);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.entitydtodifferences.mapper;
import java.util.stream.Collectors;
import com.baeldung.entitydtodifferences.dto.BookDto;
import com.baeldung.entitydtodifferences.dto.UserCreationDto;
import com.baeldung.entitydtodifferences.dto.UserResponseDto;
import com.baeldung.entitydtodifferences.entity.Book;
import com.baeldung.entitydtodifferences.entity.User;
public class UserMapper {
public static UserResponseDto toDto(User entity) {
return new UserResponseDto(entity.getId(), entity.getFirstName(), entity.getLastName(), entity.getBooks()
.stream()
.map(UserMapper::toDto)
.collect(Collectors.toList()));
}
public static User toEntity(UserCreationDto dto) {
return new User(dto.getFirstName(), dto.getLastName(), dto.getAddress(), dto.getBooks()
.stream()
.map(UserMapper::toEntity)
.collect(Collectors.toList()));
}
public static BookDto toDto(Book entity) {
return new BookDto(entity.getName(), entity.getAuthor());
}
public static Book toEntity(BookDto dto) {
return new Book(dto.getName(), dto.getAuthor());
}
}

View File

@ -0,0 +1,11 @@
package com.baeldung.entitydtodifferences.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.baeldung.entitydtodifferences.entity.User;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

View File

@ -0,0 +1,15 @@
package com.baeldung.entitydtodifferences;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApplicationIntegrationTest {
@Test
public void contextLoads() {
}
}

View File

@ -0,0 +1,93 @@
package com.baeldung.entitydtodifferences.controller;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import com.baeldung.entitydtodifferences.entity.Book;
import com.baeldung.entitydtodifferences.entity.User;
import com.baeldung.entitydtodifferences.repository.UserRepository;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@Autowired
private ObjectMapper objectMapper;
@BeforeEach
public void beforeEach() {
userRepository.deleteAll();
}
@Test
public void givenUsersAreExisting_whenGetUsers_thenUsersAreReturned() throws Exception {
//given
Book book1 = new Book("Book1", "Author1");
Book book2 = new Book("Book2", "Author2");
User savedUser = userRepository.save(new User("John", "Doe", "123 Main St", Arrays.asList(book1, book2)));
String expectedJson = String.format(
"[{\"ID\":%s,\"FIRST_NAME\":\"John\",\"LAST_NAME\":\"Doe\",\"BOOKS\":[{\"NAME\":\"Book1\",\"AUTHOR\":\"Author1\"},{\"NAME\":\"Book2\",\"AUTHOR\":\"Author2\"}]}]",
savedUser.getId());
//when
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/users")
.contentType(MediaType.APPLICATION_JSON))
.andReturn();
//then
assertEquals(expectedJson, result.getResponse()
.getContentAsString());
}
@Test
public void givenValidUser_whenPostUser_thenUserIsCreated() throws Exception {
//given
String user = "{\"FIRST_NAME\":\"John\",\"LAST_NAME\":\"Doe\",\"BOOKS\":[{\"NAME\":\"Book1\",\"AUTHOR\":\"Author1\"},{\"NAME\":\"Book2\",\"AUTHOR\":\"Author2\"}]}";
//when
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/users")
.content(user)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andReturn();
JsonNode responseJson = objectMapper.readTree(result.getResponse()
.getContentAsString());
//then
assertEquals("John", responseJson.get("FIRST_NAME")
.asText());
assertEquals("Doe", responseJson.get("LAST_NAME")
.asText());
assertTrue(responseJson.has("BOOKS"));
JsonNode booksArray = responseJson.get("BOOKS");
assertEquals(2, booksArray.size());
assertEquals("Book1", booksArray.get(0)
.get("NAME")
.asText());
assertEquals("Author1", booksArray.get(0)
.get("AUTHOR")
.asText());
assertEquals("Book2", booksArray.get(1)
.get("NAME")
.asText());
assertEquals("Author2", booksArray.get(1)
.get("AUTHOR")
.asText());
}
}

View File

@ -0,0 +1,19 @@
package com.baeldung.entitydtodifferences.entity;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.Test;
public class BookUnitTest {
@Test
public void whenBookInitialized_thenInitializedCorrectly() {
//when
Book book = new Book("Book1", "Author1");
//then
assertNotNull(book);
assertEquals("Book1", book.getName());
assertEquals("Author1", book.getAuthor());
}
}

View File

@ -0,0 +1,51 @@
package com.baeldung.entitydtodifferences.entity;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
public class UserUnitTest {
@Test
public void whenUserInitialized_thenInitializedCorrectly() {
//when
Book book1 = new Book("Book1", "Author1");
Book book2 = new Book("Book2", "Author2");
User user = new User("John", "Doe", "123 Main St", Arrays.asList(book1, book2));
//then
assertNotNull(user);
assertEquals("John", user.getFirstName());
assertEquals("Doe", user.getLastName());
assertEquals("123 Main St", user.getAddress());
assertEquals(2, user.getBooks()
.size());
}
@Test
public void givenUserOwningMultipleBooks_whenGetNameOfMostOwnedBook_thenComputedCorrectly() {
//given
Book book1 = new Book("Book1", "Author1");
Book book2 = new Book("Book2", "Author2");
Book book3 = new Book("Book2", "Author3");
User user = new User("John", "Doe", "123 Main St", Arrays.asList(book1, book2, book3));
//when
String mostOwnedBook = user.getNameOfMostOwnedBook();
//then
assertEquals("Book2", mostOwnedBook);
}
@Test
public void givenUserWithNoBooks_henGetNameOfMostOwnedBook_thenReturnedNull() {
//given
User user = new User("John", "Doe", "123 Main St", Collections.emptyList());
//when
String mostOwnedBook = user.getNameOfMostOwnedBook();
//then
assertNull(mostOwnedBook);
}
}

View File

@ -0,0 +1,87 @@
package com.baeldung.entitydtodifferences.mapper;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import com.baeldung.entitydtodifferences.dto.BookDto;
import com.baeldung.entitydtodifferences.dto.UserCreationDto;
import com.baeldung.entitydtodifferences.dto.UserResponseDto;
import com.baeldung.entitydtodifferences.entity.Book;
import com.baeldung.entitydtodifferences.entity.User;
public class UserMapperUnitTest {
@Test
public void givenUserEntity_whenMappedToDto_thenMappedCorrectly() {
//given
Book book1 = new Book("Book1", "Author1");
Book book2 = new Book("Book2", "Author2");
User user = new User("John", "Doe", "123 Main St", Arrays.asList(book1, book2));
//when
UserResponseDto userDto = UserMapper.toDto(user);
//then
assertEquals(user.getId(), userDto.getId());
assertEquals(user.getFirstName(), userDto.getFirstName());
assertEquals(user.getLastName(), userDto.getLastName());
List<BookDto> bookDtos = userDto.getBooks();
assertEquals(2, bookDtos.size());
assertEquals(book1.getName(), bookDtos.get(0)
.getName());
assertEquals(book1.getAuthor(), bookDtos.get(0)
.getAuthor());
assertEquals(book2.getName(), bookDtos.get(1)
.getName());
assertEquals(book2.getAuthor(), bookDtos.get(1)
.getAuthor());
}
@Test
public void givenUserDto_whenMappedToEntity_thenMappedCorrectly() {
//given
BookDto bookDto1 = new BookDto("Book3", "Author3");
BookDto bookDto2 = new BookDto("Book4", "Author4");
UserCreationDto userDto = new UserCreationDto("Jane", "Doe", "456 Oak St", Arrays.asList(bookDto1, bookDto2));
//when
User user = UserMapper.toEntity(userDto);
//then
assertEquals(user.getFirstName(), userDto.getFirstName());
assertEquals(user.getLastName(), userDto.getLastName());
assertEquals(user.getAddress(), userDto.getAddress());
List<Book> books = user.getBooks();
assertEquals(2, books.size());
assertEquals(bookDto1.getName(), books.get(0)
.getName());
assertEquals(bookDto1.getAuthor(), books.get(0)
.getAuthor());
assertEquals(bookDto2.getName(), books.get(1)
.getName());
assertEquals(bookDto2.getAuthor(), books.get(1)
.getAuthor());
}
@Test
public void givenBookEntity_whenMappedToDto_thenMappedCorrectly() {
//given
Book book = new Book("Book5", "Author5");
//when
BookDto bookDto = UserMapper.toDto(book);
//then
assertEquals(book.getName(), bookDto.getName());
assertEquals(book.getAuthor(), bookDto.getAuthor());
}
@Test
public void givenBookDto_whenMappedToEntity_thenMappedCorrectly() {
//given
BookDto bookDto = new BookDto("Book6", "Author6");
//when
Book book = UserMapper.toEntity(bookDto);
//then
assertEquals(bookDto.getName(), book.getName());
assertEquals(bookDto.getAuthor(), book.getAuthor());
}
}