Странное поведение ModelMapper, используемого в Spring с HibernateTemplate

У меня действительно странное поведение фреймворка ModelMapper в сочетании с Spring и Hibernate 4. И после 2 дней поиска в SO я все еще немного запутался и не могу понять причину такого странного поведения.

У меня есть 3 класса: класс A, класс B и класс пользователя.

Класс пользователя:

@Entity
@Table(name = "users")
@Data
@EqualsAndHashCode(of = "id")
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements UserDetails {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

...
}

Класс Б:

@Entity
@Audited
@Table
@Data
@Builder
@EqualsAndHashCode(of = "id")
@AllArgsConstructor
@NoArgsConstructor
public class B implements Serializable{

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

...

    @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(/*some join definition*/)
    private Set<A> a;
}

Класс А:

@Entity
@Audited
@Table
@Data
@Builder
@EqualsAndHashCode(of = "id")
@AllArgsConstructor
@NoArgsConstructor
public class A implements Serializable{
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

    ...
    @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    private User user;

    @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(/*some join definition*/)
    private Set<User> subscribers;
}

В моем контроллере у меня есть код ниже:

List<B> bObjects = bService.findAll();
return modelMapper.map(bObjects, new TypeToken<List<BDto>>() {
}.getType());

И проблема заключается в первом запуске запроса после того, как база данных была удалена и воссоздана. Я удаляю базу данных и запускаю свое приложение и добавляю новые объекты класса A и B. И затем, когда я пытаюсь перечислить все объекты, которые находятся в моей таблице, ModelMapper возвращает null вместо объекта класса User. При каждом первом запуске он возвращает null. Когда я перезапускаю приложение, пользователи отображаются правильно. Более того, когда я использую UserController для возврата всех пользователей, все пользователи возвращаются правильно, и все свойства правильно отображаются. Более того, объекты класса B содержат отношения класса A, и эти объекты класса A возвращаются правильно даже при первом запуске приложения.

Эти объекты загружаются с нетерпением, поэтому hibernate должен загрузить их. Когда я использую стандартный конвертер для преобразования A в AD, все работает нормально. Конвертер содержит жестко закодированную строку:

aDtoObject.setUserDto(aObject.getUser());

Я вставляю пользователей по умолчанию в свой класс ApplicationStartUp.

Мои свойства конфигурации гибернации:

hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
hibernate.showSql=false
hibernate.formatSql=false
hibernate.hbm2ddl.auto=update
hibernate.jdbc.batchSize=100
hibernate.orderInserts=true
hibernate.orderUpdates=true
hibernate.jdbc.batchVersionedData=true
hibernate.ejb.event.post-insert = org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener
hibernate.ejb.event.post-update = org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener
hibernate.ejb.event.post-delete = org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener
hibernate.ejb.event.pre-collection-update = org.hibernate.envers.event.AuditEventListener
hibernate.ejb.event.pre-collection-remove = org.hibernate.envers.event.AuditEventListener
hibernate.ejb.event.post-collection-recreate = org.hibernate.envers.event.AuditEventListener

Конфигурация ModelMapper:

@Configuration
public class ModelMapperConfig {

    @Bean
    public ModelMapper strictModelMapper() {
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STANDARD);
        return modelMapper;
    }
}

ПОМ:

        <spring-version>4.2.4.RELEASE</spring-version>
        <hibernate-version>4.3.8.Final</hibernate-version>

    <dependency>
        <groupId>org.modelmapper</groupId>
        <artifactId>modelmapper</artifactId>
        <version>0.7.5</version>
    </dependency>


    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate-version}</version>
    </dependency>


    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-envers</artifactId>
        <version>${hibernate-version}</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate-version}</version>
    </dependency>

Кто-нибудь может помочь мне разобраться? Любые идеи, что я могу проверить и что может быть причиной такого странного поведения?

P.S. что нужно изменить только с помощью класса User. Остальные классы работают нормально.


person 4the3eam    schedule 08.12.2016    source источник


Ответы (1)


Вам также необходимо добавить сопоставления в ваш сопоставитель модели, если вы не сделали этого в своем классе конфигурации -

modelMapper.addMappings(new OutputMapper());

Вы получаете конфигурацию, когда определяете сопоставитель модели, но рассмотрите возможность переопределения метода configure() в PropertyMap для индивидуального сопоставления ваших атрибутов:

class OutputMapper extends PropertyMap<AData, Output> {

   @Override
   protected void configure(){

     map().setABCD(source.getABCD());

   }
}
person Righto    schedule 09.03.2017