2017-01-05 4 views
0

У меня есть сущности User и Event которые имеют отношение . Если я попытаюсь вернуть объект User из Controller в REST API, это приведет к циклической зависимости.Модель mapper - как карта несовместимых типов

Я решил использовать DTOs, где я бы использовал вместо List<Event> только List<Integer>, который будет представлять идентификаторы объектов событий.

Но если я попытаюсь создать пользовательский номер PropertyMap, он не работает. Вы рекомендуете другой подход, как это сделать?

объект Event

@Entity 
@Table(name = "events") 
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
public class Event extends AbstractEntity { 

@ManyToMany(cascade = CascadeType.PERSIST) 
@JoinTable(name = "event_participants", 
     joinColumns = @JoinColumn(name = "event_id"), 
     inverseJoinColumns = @JoinColumn(name = "user_id")) 
private List<User> eventParticipants; 

объект пользователя

@Entity 
@Table(name = "users") 
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
public class User extends AbstractEntity { 

@ManyToMany(mappedBy = "eventParticipants") 
private List<Event> participatingEvents; 

UserController

@RestController 
@RequestMapping("/users") 
public class UserController extends AbstractController { 

@Autowired 
private UserService userService; 

@Autowired 
private ModelMapper modelMapper; 

@RequestMapping(method = RequestMethod.GET, value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) 
public UserDTO find(@PathVariable("id") Integer id) { 
    final User user = userService.find(id); 
    if (user == null) { 
     //TODO throw some exception 
     return null; 
    } 
    UserDTO userDTO = userToDTO(user); 
    return userDTO; 
} 

private UserDTO userToDTO(User user) { 
    modelMapper.addMappings(new UserMap()); 
    return modelMapper.map(user, UserDTO.class); 
} 

И, наконец, мой PropertyMap класс

public class UserMap extends PropertyMap<User, UserDTO> { 

    @Override 
    protected void configure() { 
     map().setFirstName(source.getFirstName()); 

     map().setLastName(source.getLastName()); 

     map().setEmail(source.getEmail()); 

     List<Integer> friendsDTO = new ArrayList<>(); 
     for(User u : source.getFriends()){ 
      friendsDTO.add(u.getId()); 
     } 
     map().setFriends(friendsDTO); 

     List<Integer> participatingEventsDTO = new ArrayList<>(); 
     for(Event e : source.getParticipatingEvents()){ 
      participatingEventsDTO.add(e.getId()); 
     } 
     map().setParticipatingEvents(participatingEventsDTO); 

     List<Integer> ownedEventsDTO = new ArrayList<>(); 
     for(Event e : source.getOwnedEvents()){ 
      ownedEventsDTO.add(e.getId()); 
     } 
     map().setOwnedEvents(ownedEventsDTO); 

     List<Integer> commentsDTO = new ArrayList<>(); 
     for(Comment c : source.getComments()){ 
      commentsDTO.add(c.getId()); 
     } 
     map().setComments(commentsDTO); 

     List<Integer> thingsDTO = new ArrayList<>(); 
     for(ThingToTake t : source.getThingsToTakeList()){ 
      thingsDTO.add(t.getId()); 
     } 
     map().setThingsToTakeList(thingsDTO); 
    } 

} 

Это исключение я получу, если я пытаюсь получить с помощью отдыха:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.modelmapper.ConfigurationException: ModelMapper configuration errors: 

1) Invalid source method java.util.List.add(). Ensure that method has zero parameters and does not return void. 

2) Invalid source method java.util.List.add(). Ensure that method has zero parameters and does not return void. 

3) Invalid source method java.util.List.add(). Ensure that method has zero parameters and does not return void. 

4) Invalid source method java.util.List.add(). Ensure that method has zero parameters and does not return void. 

5) Invalid source method java.util.List.add(). Ensure that method has zero parameters and does not return void. 

5 errors 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982) 
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622) 
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729) 
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 

root cause 

org.modelmapper.ConfigurationException: ModelMapper configuration errors: 

1) Invalid source method java.util.List.add(). Ensure that method has zero parameters and does not return void. 

2) Invalid source method java.util.List.add(). Ensure that method has zero parameters and does not return void. 

3) Invalid source method java.util.List.add(). Ensure that method has zero parameters and does not return void. 

4) Invalid source method java.util.List.add(). Ensure that method has zero parameters and does not return void. 

5) Invalid source method java.util.List.add(). Ensure that method has zero parameters and does not return void. 

5 errors 
    org.modelmapper.internal.Errors.throwConfigurationExceptionIfErrorsExist(Errors.java:241) 
    org.modelmapper.internal.ExplicitMappingBuilder.visitPropertyMap(ExplicitMappingBuilder.java:229) 
    org.modelmapper.PropertyMap.configure(PropertyMap.java:380) 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    java.lang.reflect.Method.invoke(Method.java:483) 
    org.modelmapper.internal.ExplicitMappingBuilder.build(ExplicitMappingBuilder.java:195) 
    org.modelmapper.internal.TypeMapImpl.addMappings(TypeMapImpl.java:72) 
    org.modelmapper.internal.TypeMapStore.getOrCreate(TypeMapStore.java:101) 
    org.modelmapper.ModelMapper.addMappings(ModelMapper.java:93) 
    com.ear.tripplan.rest.UserController.userToDTO(UserController.java:50) 
    com.ear.tripplan.rest.UserController.find(UserController.java:39) 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    java.lang.reflect.Method.invoke(Method.java:483) 
    org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) 
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) 
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114) 
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) 
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) 
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) 
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) 
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) 
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622) 
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729) 
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 
+0

Вы можете указать "Не работает"? Есть ли исключение? Или это ничего? Пробовали ли вы конвертацию в автономной среде? Используете ли вы некоторую (Hibernate) ленивую инициализацию (и, следовательно, список не инициализируется в этой точке)? –

+0

Я отредактирую вопрос на добавление исключения. –

+2

Мое предположение заключается в том, что вы не можете использовать реальное преобразование (реализация (для каждого добавления)) для списков в mapper, и вместо этого вы определили конвертер или вызовите картупер во второй раз. ('using (converter) .map(). setListe (source.getList());') (IMO этот конвертер просто добавляет много сложности, вам не нужно, и вам будет лучше, если вы сделаете полное преобразование самостоятельно.) –

ответ

0

У меня была такая же проблема и я сделал это, обернув идентификатор в другой объект

public class UserDTO { 

    List<EventDTO> participatingEvents 
    /// getter setter 
} 

public class EventDTO { 
    private Long id; 
    // getter setter 
} 

и вам не нужно владениеВстроение или код

UserDTO userDTO = modelmapper.map(user, UserDTO.class); 

надеюсь, что это помогает

ОБНОВЛЕНО

Вы можете сделать это с преобразователями, а

public class UserMap extends PropertyMap<User, UserDTO> { 

@Override 
protected void configure() { 
    Converter<List<User>, List<Long>> converter = new AbstractConverter<List<User>, List<Long>>() { 
     List<Long> result = new ArrayList<>(); 
     @Override 
     protected List<Long> convert(List<User> source) { 
      source.forEach(user -> result.add(user.getId())); 
      return result; 
     } 
    }; 
    using(converter).map(source.getUsers(), destination.getUsers()); 
} 

}