как генерировать экземпляры класса атрибутов по запросу?

Я правильно оцениваю структуру бульдозера. Мне было интересно, можно ли обработать следующий вариант использования:

классы:

public ClassA {

   private Set<ItemA> aItems;
}

public ClassB {

   private ClassC cInstance;
}

public ClassC {

   private List<ItemB> bItems;
}

отображение бульдозера:

<mapping>
   <class-a>ClassA</class-a>
   <class-b>ClassB</class-b>
   <field>
      <a>aItems</a>
      <b>cInstance.bItems</b>
   </field>
 </mapping>

Судя по моим тестам, это не работает. Мне было особенно интересно, как я должен сказать dozer, что он должен генерировать экземпляр ClassB и ClassC по запросу? В частности, мне нужно конкретное сопоставление бульдозера для класса B, который существует только как «промежуточный» класс в моей целевой модели?

PS: если это поможет, моя модель назначения состоит из классов JAXB.

PPS: я также попытался изменить метод установки для cInstance, чтобы, если он равен нулю, он должен генерировать новый экземпляр ClassC - к сожалению, безуспешно. Кроме того, я не хочу изменять метод установки таким образом (однако, возможно, я могу передать это классу Factory, который будет использоваться для сопоставления)


person zazi    schedule 19.03.2013    source источник
comment
Ничего себе, не уверен, что вы пытаетесь сделать здесь. Похоже, вы пытаетесь использовать Dozer как фабрику объектов, а не как инструмент копирования.   -  person Perception    schedule 19.03.2013
comment
Вы изменили сеттер для cInstance или геттер? Вы написали первое, но должно быть второе. Глубокое картографирование похоже на то, что вы хотите, но также и на то, что вы пробовали, поэтому я не не знаю, как это не удалось. create method может помочь создать экземпляры ClassB, где поле cInstance уже инициализировано, если это приемлемо.   -  person MvG    schedule 19.03.2013
comment
большое спасибо за ваш комментарий @MvG. Да, вы, вероятно, правы, я изменил сеттер, а не геттер (поэтому я попробую наоборот). Вы также правы, что я пытаюсь сделать более глубокое отображение. Я попробую обходной путь с помощью определенного метода создания (хотя изначально я не собирался изменять сгенерированные классы JAXB целевой модели).   -  person zazi    schedule 19.03.2013
comment
просто в качестве короткого примечания: я заставил его работать как-то, правда, не совсем идеально, т.е. я сейчас использую прямой доступ ('is-accessible=true') и сделал некоторые модификации в классах JAXB (но это не было это не мое первоначальное намерение). Поэтому я попытаюсь найти решение с настроенной фабрикой бинов и, возможно, с прямым доступом.   -  person zazi    schedule 20.03.2013


Ответы (2)


У меня нет опыта работы с Dozer, но, судя по руководству, должно работать следующее: bean factory для ClassB реализации интерфейса dozer BeanFactory:

public class FactoryB implements BeanFactory {
  public Object createBean(Object source, Class sourceClass,
                           String targetBeanId) {
    assert(sourceClass.equals(ClassA.class));
    assert(ClassB.class.getName().equals(targetBeanId));
    ClassA a = (ClassA)source;
    ClassB b = new ClassB();
    if (a.aItems != null && !a.aItems.isEmpty())
      b.cInstance = new ClassC();
    return b;
  }
}

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

Теперь вы должны иметь возможность сопоставлять объекты с помощью глубокого сопоставления, например:

<mapping>
   <class-a>ClassA</class-a>
   <class-b bean-factory="FactoryB">ClassB</class-b>
   <field>
      <a>aItems</a>
      <b>cInstance.bItems</b>
   </field>
 </mapping>
person MvG    schedule 19.03.2013
comment
Большое спасибо за ваш ответ @MvG. Насколько я понимаю руководство по бульдозеру, я должен определить org.dozer.factory.JAXBBeanFactory как bean factory, а затем он загрузит связанный ObjectFactory классов JAXB, которые были сгенерированы XJC. Однако, возможно, мне нужно создать и определить другую фабрику, связанную с требованиями бульдозера. - person zazi; 19.03.2013
comment
@zazi: фабрика JAXB будет создавать объекты в порядке, но она не сможет создать этот начальный экземпляр cInstance тогда и только тогда, когда это потребуется. Если схема уже не определяет, что объект будет там, если и только если его битовые элементы не пусты. В любом случае вы можете заменить new ClassB() и new ClassC() в моем коде вызовом фабрики JAXB, хотя я ожидаю, что фабрика сделает то же самое. - person MvG; 19.03.2013
comment
Я попробовал ваше предложение (также в сочетании с методом создания) в поле назначения, но безуспешно. он все еще выдает NPE и не может понять, почему. - person zazi; 20.03.2013
comment
см. мой комментарий к вопросу. Я нашел работоспособное, но не идеальное решение на данный момент. - person zazi; 20.03.2013

Итак, похоже, что окончательное решение довольно простое, поскольку мои целевые классы — это классы JAXB, я мог бы просто использовать фабрику по умолчанию для классов JAXB (org.dozer.factory.JAXBBeanFactory). Переломный момент, вероятно, заключается в том, что к полю назначения глубокого сопоставления следует обращаться напрямую ('is-accessible="true"'). Однако я также создал дополнительное прямое сопоставление ClassA.aitems с ClassC.cItems (но я не уверен на 100%, будет ли это использоваться для описанного сопоставления ClassA с ClassB). В любом случае, наконец, я нашел довольно простое и интуитивно понятное решение с меньшим количеством / без дополнительного заводского кодирования.

person zazi    schedule 20.03.2013