2
\$\begingroup\$

I have User entity that has relationship to other entities(Order,Profile) When I assemble entity from dto and back I need assemble order and profile entity too.

User entity:

@Table(name = "user_info")
@Entity
@Getter
@Setter
public class User implements Serializable {
 private static final long serialVersionUID = 1789771068899105277L;
 @Id
 @GeneratedValue
 @Column(name = "userId",columnDefinition = "BINARY(16)")
 private UUID userId ;
 @Column(name = "login", unique = true, length = 20)
 private String login;
 @Column(name = "userPassword", length = 100)
 private String password;
 @Column(name = "userEmail", unique = true, length = 320)
 private String userEmail;
 @OneToOne(mappedBy = "user", cascade = CascadeType.ALL,
 fetch = FetchType.LAZY, optional = false)
 private Profile profile;
 @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
 private Set<Role> roles = new HashSet<>();
 @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
 private List<Order> orders = new ArrayList<>();
 @Override
 public boolean equals(Object o) {
 if (this == o) return true;
 if (o == null || getClass() != o.getClass()) return false;
 User user = (User) o;
 return Objects.equals(getUserId(), user.getUserId());
 }
 @Override
 public int hashCode() {
 return Objects.hash(getUserId());
 }
 @Override
 public String toString() {
 final StringBuilder sb = new StringBuilder("User{");
 sb.append("userId=").append(userId);
 sb.append(", login='").append(login).append('\'');
 sb.append(", password='").append(password).append('\'');
 sb.append(", userEmail='").append(userEmail).append('\'');
 sb.append('}');
 return sb.toString();
 }
}
 @Override
 public int hashCode() {
 return Objects.hash(getId(), getUserAuthority());
 }
 @Override
 public String toString() {
 final StringBuilder sb = new StringBuilder("Role{");
 sb.append("id=").append(id);
 sb.append(", userAuthority='").append(userAuthority).append('\'');
 sb.append(", user=").append(user);
 sb.append('}');
 return sb.toString();
 }
}

For example If I need transform User entity to Dto I need assembler:

public interface Assembler <E,D>{
 D mergeAggregateIntoDto(E entity);
 E mergeDtoIntoAggregate(D dto);
}
@Service
public class UserAssembler implements Assembler<User, UserDto>{
 @Autowired
 private CarDao carDao;
 @Override
 public UserDto mergeAggregateIntoDto(User entity) {
 UserDto userDto = new UserDto();
 userDto.setUserId(entity.getUserId());
 userDto.setUserEmail(entity.getUserEmail());
 userDto.setLogin(entity.getLogin());
 userDto.setPassword(entity.getPassword());
 userDto.setProfile(mergeAggregateIntoDto(entity.getProfile()));
 userDto.setRoles(entity.getRoles().stream().map(this::mergeAggregateIntoDto).collect(Collectors.toSet()));
 userDto.setOrders(entity.getOrders().stream().map(this::mergeAggregateIntoDto).collect(Collectors.toList()));
 return userDto;
 }
 @Override
 public User mergeDtoIntoAggregate(UserDto dto) {
 User user = new User();
 Map<UUID,Car> uuidCarMap = getCars(dto);
 Profile profile = mergeDtoIntoAggregate(dto.getProfile());
 profile.setUser(user);
 user.setUserId(dto.getUserId());
 user.setUserEmail(dto.getUserEmail());
 user.setLogin(dto.getLogin());
 user.setPassword(dto.getPassword());
 user.setProfile(profile);
 user.setRoles(dto.getRoles().stream().map(roleDto->{
 Role role = mergeDtoIntoAggregate(roleDto);
 role.setUser(user);
 return role;
 }).collect(Collectors.toSet()));
 user.setOrders(dto.getOrders().stream().map(orderDto -> {
 Order order = mergeDtoIntoAggregate(orderDto);
 order.setUser(user);
 order.setCar(uuidCarMap.get(orderDto.getCarId()));
 return order;
 }).collect(Collectors.toList()));
 return user;
 }
 private Map<UUID, Car> getCars(UserDto userDto){
 List<UUID> carIds = userDto.getOrders().stream().map(OrderDto::getCarId).collect(Collectors.toList());
 List<Car> cars = carDao.findByIds(carIds);
 return cars.stream().collect(Collectors.toMap(Car::getCarId, Function.identity()));
 }
 private ProfileDto mergeAggregateIntoDto(Profile profile){
 ProfileDto profileDto = new ProfileDto();
 profileDto.setProfileId(profile.getProfileId());
 profileDto.setUserId(profile.getUser().getUserId());
 profileDto.setAccountBalance(profile.getAccountBalance());
 profileDto.setUserFirstName(profile.getUserFirstName());
 profileDto.setUserSurName(profile.getUserSurName());
 profileDto.setUserRegistrationDate(profile.getUserRegistrationDate());
 return profileDto;
 }
 private Profile mergeDtoIntoAggregate(ProfileDto profileDto){
 Profile profile = new Profile();
 profile.setProfileId(profileDto.getProfileId());
 profile.setAccountBalance(profileDto.getAccountBalance());
 profile.setUserFirstName(profileDto.getUserFirstName());
 profile.setUserSurName(profileDto.getUserSurName());
 profile.setUserRegistrationDate(profileDto.getUserRegistrationDate());
 return profile;
 }
 private RoleDto mergeAggregateIntoDto(Role role){
 RoleDto roleDto = new RoleDto();
 roleDto.setId(role.getId());
 roleDto.setUserAuthority(role.getUserAuthority());
 roleDto.setUserId(role.getUser().getUserId());
 return roleDto;
 }
 private Role mergeDtoIntoAggregate(RoleDto roleDto){
 Role role = new Role();
 role.setUserAuthority(roleDto.getUserAuthority());
 role.setId(roleDto.getId());
 return role;
 }
 private OrderDto mergeAggregateIntoDto(Order order){
 OrderDto orderDto = new OrderDto();
 orderDto.setOrderCost(order.getOrderCost());
 orderDto.setOrderDate(order.getOrderDate());
 orderDto.setOrderId(order.getOrderId());
 orderDto.setUserAddress(order.getUserAddress());
 orderDto.setUserDestination(order.getUserDestination());
 orderDto.setUserId(order.getUser().getUserId());
 orderDto.setCarId(order.getCar().getCarId());
 return orderDto;
 }
 private Order mergeDtoIntoAggregate(OrderDto orderDto){
 Order order = new Order();
 order.setOrderId(orderDto.getOrderId());
 order.setOrderCost(orderDto.getOrderCost());
 order.setUserAddress(orderDto.getUserAddress());
 order.setUserDestination(orderDto.getUserDestination());
 order.setOrderDate(orderDto.getOrderDate());
 return order;
 }
}

So I used dao in assembler and I want to know can I do that? Thanks.

asked Sep 4, 2021 at 9:23
\$\endgroup\$
1
  • \$\begingroup\$ This question actually reads like it should belong to stackoverflow rather than codereview. \$\endgroup\$ Commented Sep 5, 2021 at 1:19

1 Answer 1

1
\$\begingroup\$

Entity Relationships

First you could draw the ER diagram to visualize entity-relations. An UML class-diagram for Order could do, like this:

,----------------.
|Order |
|----------------|
|customer: User |
|orderedAt : Date|
|items: Car[] |
`----------------'

Relations:

  • an order has exactly a single customer of type User (is ordered by)
  • an order is submitted at a specific date of type Date (is ordered at)
  • an order can have zero, one or many items of type Car (has order line items)

Class Design

A valid order must at least fulfill the two is-relationships.

class Order {
 final Date orderedAt;
 final User customer;
 final List<Car> lineItems = new ArrayList<Car>();
 public Order(User customer, Date orderedAt) {
 this.orderedAt = orderedAt;
 this.customer = customer;
 }
 public Order(User customer) {
 this(customer, new Date()); // default: ordered today
 }
 public Address getInvoiceAddress() {
 return this.customer.getUserAddress(); // delegate to customer (user)
 }
 public Address getDeliveryAddress() {
 return this.customer.getDestinationAddress(); // delegate to customer (user)
 }
 public void addItem(Car item) {
 this.lineItems.add(item);
 }
}

This shows, that you can simply construct an order by passing a User object. The other attributes (e.g. addresses) can be derived from the customer or user (delegation).

Mapping: from DTO to Entity and vice-versa

For this mapping there are plenty of mapping frameworks like MapStruct, Dozer etc.

You can also implement the Adapter Pattern yourself, which fits pretty well here.

Hibernate: is an OR-mapper already!

Hiberernate is often described as object-relational mapper (OR-mapper).

Because it maps from object-oriented structures (expressed in Java classes) to relational data structures (expressed in database tables) and back.

The fact, that you are using the JPA-annotations @Entity and @Table on the class describes exactly this mapping.

When properly using Hibernate and JPA (and their annotations), then you don't need further mapping frameworks or assembly-services.

answered Sep 5, 2021 at 10:20
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.