Reputation: 1
I'm trying to use mapstruct to map entity with buisness object. I have layer structure in project. (DTO, Buisness, Entity) In this configure of mapping I am ignoring user/reservations so they are "null". If i set it to different value it gets into infinite cycle (StackOverFlow) I need to get reservation with info about user (userId etc.)
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface ReservationsEntityMapper {
@Mapping(target = "user", ignore = true)
ReservationsEntity mapToEntity(Reservations entity);
@Mapping(target = "user", ignore = true)
Reservations mapFromEntity(ReservationsEntity entity);
}
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface UsersEntityMapper {
@Mapping(target = "reservations", ignore = true)
User mapFromEntity(FlightAppUsersEntity entity);
@Mapping(target = "reservations", ignore = true)
FlightAppUsersEntity mapToEntity(User user);
}
@Mapper(componentModel = "spring")
public interface ReservationsMapper {
@Mapping(target = "user.userId", source = "user.userId")
ReservationsDTO map(final Reservations reservations);
@Mapping(target = "user.createdAt", ignore = true)
@Mapping(target = "user.active", ignore = true)
@Mapping(target = "user.roles", ignore = true)
@Mapping(target = "createdAt", ignore = true)
@Mapping(target = "user.userId", source = "user.userId")
Reservations map(ReservationsDTO reservationsDTO);
}
@Mapper(componentModel = "spring", uses = ReservationsMapper.class)
public interface UsersMapper {
@Mapping(target = "userId", source = "userId")
UserDTO map(final User user);
@Mapping(target = "roles", ignore = true)
@Mapping(target = "active", ignore = true)
@Mapping(target = "createdAt", ignore = true)
User map(UserDTO userDTO);
}
DTO/Buisness/Entity
@Value
@With
@Builder
@EqualsAndHashCode(of = "reservationId")
@ToString(of = {"reservationId", "origin", "destination", "departureDate", "returnDate", "airline", "price", "currency", "numberOfPassengers", "createdAt", "user"})
public class Reservations {
Integer reservationId;
//some fields
ReservationStatus status;
User user;
}
@Value
@With
@Builder
@EqualsAndHashCode(of = "email")
@ToString(of = {"userId", "firstName", "lastName", "email", "roles", "createdAt", "reservations"})
public class User {
Integer userId;
//some fields
Set<FlightAppRoles> roles;
Set<Reservations> reservations;
}
@Getter
@Setter
@EqualsAndHashCode(of = "userId")
@ToString(of = {"userId", "firstName", "lastName", "email", "createdAt"})
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "flightapp_users")
public class FlightAppUsersEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id", nullable = false)
private Integer userId;
//some fields
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private Set<ReservationsEntity> reservations;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(
name = "flightapp_user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<FlightAppRoles> roles;
}
@Getter
@Setter
@EqualsAndHashCode(of = "reservationId")
@ToString(of = {"reservationId", "user", "origin", "destination", "departureDate", "returnDate", "airline", "price", "currency", "numberOfPassengers", "createdAt"})
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "reservations")
public class ReservationsEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "reservation_id", nullable = false)
private Integer reservationId;
//some fields
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_id", nullable = false)
private FlightAppUsersEntity user;
}
Example of reservation:
reservation: Reservations(reservationId=29, origin=EWR, destination=LIS, departureDate=2025-02-27T17:40, returnDate=2025-03-01T12:50, airline=TP, price=805.37, currency=EUR, numberOfPassengers=1, createdAt=2025-02-27T04:28:35.877725, user=null)
How to implement maybe @Aftermapping or other solution to this??
Upvotes: 0
Views: 42
Reputation: 9175
I actually gave a presentation about this at work this morning.
MapStruct has an example for this themselves, at https://github.com/mapstruct/mapstruct-examples/tree/main/mapstruct-jpa-child-parent/src/main/java/org/mapstruct/jpa. Basically, you create a context class that allows you to store references to the parent and pass that along using @Context
. The context will then take care of setting the relations due to its own MapStruct annotations. The generated code will do the following:
You can go deeper than just one relation by simply adding more content to your context class.
Upvotes: 1