Dozer неправильно отображает коллекцию

Итак, у меня возникла проблема, что кто-то здесь может помочь мне с Dozer.

Предыстория: я настроил Dozer для сопоставления моих сущностей сохраняемости с их классами DTO. Это довольно просто, я просто создаю точную копию своего класса сущностей как POJO и разрешаю подстановочным знакам бульдозеров видеть, что имя поля соответствует полю источников. Я решаю проблему ленивой загрузки гибернации с помощью специального преобразователя, как это сделано здесь . Я рассказываю Dozer, как сопоставить каждый класс с помощью класса, который сканирует аннотацию с именем @EntityMapping(DTOxxx.class) внутри сущности. Затем он добавляет его в картограф addMapping(builder)

Проблема: (прочитайте исследование в конце, чтобы получить актуальную информацию, но это также поможет получить представление о контексте, прочитав все это). Проблема в том, что Dozer неправильно отображает мои коллекции. в некоторых случаях. Например, в моем классе CategoryEntity есть набор других сущностей, которые Dozer должен сопоставить. Что происходит, так это то, что dozer находит коллекцию, которая в данном случае имеет 2 элемента, и отображает только 1 элемент в новой коллекции классов DTO.

введите здесь описание изображения

Как вы можете видеть на изображении после вызова toDomain (в нем есть вызов dozer mapper.map(source, desination)), у DTO есть только 1 из 2 объектов, которые он должен был сопоставить с ним из сущности. Вот метод toDomain, если вы хотите его увидеть:

@Transactional(readOnly=true)
public <T extends DomainObject> T toDomain(Class<T> clazz, Entity entity) {
    if (entity == null) {
        return null;
    }

    T domain = getCachedDomainObjects(clazz, entity.getId());
    if (domain == null) {
        domain = dozerMapper.map(entity, clazz);
        cacheDomainObject(domain);
    }
    return domain;
}

Я позаботился о том, чтобы он не захватил кешированный объект, если вы так думаете.

Поэтому я немного озадачен тем, почему в одних случаях это происходит, а в других нет. Я не вижу каких-либо очевидных различий в случаях, когда он работает, и в случаях, когда он не работает. Если кто-то сталкивался с такой проблемой раньше и думает, что сможет мне помочь, это было бы здорово! Вот мои классы из примера вопроса:

CategoryEntity.java:

@EntityMapping(Category.class)
@javax.persistence.Entity(name = "categories")
public class CategoryEntity implements Entity, PureTable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(unique = true, nullable = false)
    private int id = Entity.UNSAVED_ID;

    @OneToMany(mappedBy = "pk.category", fetch = FetchType.LAZY)
    @Cascade({CascadeType.SAVE_UPDATE})
    private Set<IncidentJoinCategoryEntity> incidentJoinCategories =
        new HashSet<IncidentJoinCategoryEntity>();

    @Override
    public int getId() {
        return this.id;
    }
    public void setId(int id) {
        this.id = id;
    }

    public Set<IncidentJoinCategoryEntity> getIncidentJoinCategories() {
        return incidentJoinCategories;
    }
    public void setIncidentJoinCategories(Set<IncidentJoinCategoryEntity> 
        incidentJoinCategories) {
        this.incidentJoinCategories = incidentJoinCategories;
    }
}

Этот класс имеет класс DTO, который полностью соответствует его значениям:

Категория.java:

public class Category {

    int id;

    Set<IncidentJoinCategory> incidentJoinCategories= 
    new HashSet<IncidentJoinCategory>();

    @Override
    public int getId() {
        return id;
    }
    @Override
    public void setId(int id) {
        this.id = id;
    }

    public Set<IncidentJoinCategory> getIncidentJoinCategories() {
        return incidentJoinCategories;
    }
    public void setIncidentJoinCategories(Set<IncidentJoinCategory> 
        incidentJoinCategories) {
        this.incidentJoinCategories = incidentJoinCategories;
    }
}

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ИССЛЕДОВАНИЕ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

РЕДАКТИРОВАНИЕ №1:

Хорошо! Поэтому я потратил часы на отладку этой проблемы, чтобы выяснить, что здесь происходит. Оказывается, проблема заключается в строке 749 класса MappingProcessor (Dozer 5.4.0) или строке 766 для последних источников (но я не проверял, сохраняется ли эта проблема в последних источниках, хотя сомневаюсь, что она исправлена).

Эта линия

((Set) field).addAll(result);

То, что он пытается отобразить здесь, это

HashSet<IncidentJoinCategoryEntity>

addAll(result) добавляет только 1 элемент в коллекцию ((Set) field). Результат, в котором есть 2 элемента (во время отладки он также имеет размер 2, я предоставлю свой снимок переменных), добавляет только 1 значение к приведению ((Set) field).

result  LinkedHashSet<E>  (id=220)  
    map LinkedHashMap<K,V>  (id=248)    
        accessOrder false   
        entrySet    HashMap$EntrySet  (id=251)  
        hashSeed    -1187793029 
        header  LinkedHashMap$Entry<K,V>  (id=253)  
        keySet  HashMap$KeySet  (id=5829)   
        loadFactor  0.75    
        modCount    2   
        size    2   
        table   HashMap$Entry<K,V>[16]  (id=258)    
        threshold   12  
        useAltHashing   false   
        values  null    
field   HashSet<E>  (id=221)    
    map HashMap<K,V>  (id=247)  
        entrySet    HashMap$EntrySet  (id=5856) 
        hashSeed    1372273954  
        keySet  HashMap$KeySet  (id=5821)   
        loadFactor  0.75    
        modCount    2   
        size    1   
        table   HashMap$Entry<K,V>[16]  (id=5822)   
        threshold   12  
        useAltHashing   false   
        values  null    

введите здесь описание изображения

РЕДАКТИРОВАНИЕ № 2:

Загрузил источник для дополнительной отладки:

if (field == null) {
  Class<? extends Set<?>> destSetType = (Class<? extends Set<?>>) fieldMap.getDestFieldType(destObj.getClass());
  return CollectionUtils.createNewSet(destSetType, result);
} else {
  System.out.println("----IN----");
  // Bug #1822421 - Clear first so we don't end up with the removed orphans again
  Set ret = (Set) field;
  ret.clear();
  //((Set) field).addAll(result);
  for(Object res : result) {
      System.out.println("FOUND " + res.toString());
      ret.add(res);
  }
  System.out.println("END SIZE " + ret.size());
  System.out.println("----OUT----");
  return ret;
}

Вывод для этого случая:

----IN----
FOUND nz.co.doltech.ims.project.shared.domains.joins.IncidentJoinCategory@3e2
FOUND nz.co.doltech.ims.project.shared.domains.joins.IncidentJoinCategory@3e2
END SIZE 1
----OUT----

Его вывод — 2 элемента, но, как вы можете видеть, @3e2 по какой-то причине это один и тот же элемент. Поэтому, когда вы вызываете addAll, он удаляет дубликат и оставляет нам только 1 элемент. Почему Dozer случайно отображает 2 одинаковых значения? Я проверил, чтобы убедиться, что в коллекции исходных объектов не дублируются одни и те же элементы, и, конечно же, это не так. Действительно странно.

РЕДАКТИРОВАНИЕ №3:

Я сделал дальнейшие тесты с небольшой удачей здесь. Это действительно проблема с отображением Dozer 2 одинаковых значений, и addAll удаляет дубликаты, делая их всего одним элементом в списке. К сожалению, я не могу очень легко отладить рекурсивные методы в addToSet, чтобы определить, почему это происходит.

Обновлю, если я выясню что-нибудь еще, иначе у меня нет идей на этот счет, ха-ха.


person Ben Dol    schedule 27.06.2013    source источник


Ответы (1)


Оказывается, на самом деле это не ошибка Dozer. Отладка показала, что виноват Dozer, но я не думаю, что это так. Причина, по которой я думаю, в том, что я перешел на другой маппер с той же проблемой, поэтому, если у этого нового маппера нет такой же проблемы (смеется), это не Dozer. Если у кого-нибудь есть идеи относительно того, почему это происходит для меня, я был бы признателен за помощь в этом.

Я предполагаю, что на данный момент это настраиваемый сопоставитель полей гибернации, который у меня есть для работы с коллекциями, чувствительными к ленивой загрузке. Единственная причина, по которой я проигнорировал это, заключается в том, что, когда я начал отлаживать Dozer, казалось, что Dozer сопоставляет поля до того, как возвращается из addToSet, поэтому я ошибочно предположил, что он уже применил настраиваемое сопоставление полей.

person Ben Dol    schedule 03.07.2013