Проблема с генератором Java Builder

В моем проекте у меня есть два пакета, полных DTO, POJO только с геттерами и сеттерами. Хотя важно, чтобы они являются простыми Java-компонентами (например, потому что Apache CXF использует их для создания XSD веб-сервисов и т. д.), это также ужасно и подвержено ошибкам программировать подобное.

Foo foo = new Foo();
foo.setBar("baz");
foo.setPhleem(123);
return foo;

Я предпочитаю плавные интерфейсы и объекты построителя, поэтому я использую maven / gmaven для автоматически создавать компоновщики для DTO. Итак, для приведенного выше кода автоматически создается FooBuilder , который я могу использовать следующим образом:

Foo foo = new FooBuilder()
           .bar("baz")
           .phleem(123)
           .build();

Я также автоматически генерирует модульные тесты для сгенерированных построителей. Модульный тест генерирует оба приведенных выше кода (версия построителя и версия не построителя) и утверждает, что обе версии эквивалентны с точки зрения equals () и hashcode () . Я могу добиться этого, имея глобально доступную карту со значениями по умолчанию для каждого типа свойства. Примерно так:

public final class Defaults{
    private Defaults(){}
    private static final Map, Object> DEFAULT_VALUES =
        new HashMap, Object>();
    static{
        DEFAULT_VALUES.put(String.class, "baz");
        // argh, autoboxing is necessary :-)
        DEFAULT_VALUES.put(int.class, 123);
        // etc. etc.
    }
    public static getPropertyValue(Class type){
        return DEFAULT_VALUES.get(type);
    }
}

Другой нетривиальный аспект состоит в том, что у pojos иногда есть члены коллекции. например:

foo.setBings(List bings)

, но в моем конструкторе я хотел бы, чтобы это сгенерировало два метода из этого случая: метод набора и метод добавления:

fooBuilder.bings(List bings); // set method
fooBuilder.addBing(Bing bing); // add method

Я решил это, добавив пользовательскую аннотацию к полям свойств в Foo

@ComponentType(Bing.class)
private List bings;

Построитель Builder (sic) считывает аннотацию и использует значение в качестве универсального типа генерируемых методов.

Теперь мы приближаемся к вопросу (извините, краткость не является одним из моих достоинств: -)).

Я понял, что этот конструкторский подход может использоваться более чем в одном проекте, поэтому я думаю о превратив его в плагин maven. Я прекрасно понимаю, как создать плагин maven, так что это не является частью вопроса (как и то, как сгенерировать действительный исходный код Java). Моя проблема: как я могу справиться с двумя вышеуказанными проблемами, не вводя какие-либо общие зависимости (между Project и Plugin):

  1. Мне нужен класс Defaults (или аналогичный механизм) для получения значений по умолчанию для сгенерированные модульные тесты (это ключевая часть концепции, я бы не стал доверять автоматически сгенерированным сборщикам, если бы они не были полностью протестированы). Пожалуйста, помогите мне придумать хороший и общий способ решения этой проблемы, учитывая, что каждый проект будет иметь свои собственные объекты домена.

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

Есть идеи?

Кстати: Я знаю, что настоящий ключ Смысл использования конструкторов - сделать объекты неизменяемыми. Я не могу сделать свой неизменяемым, потому что стандартные java beans необходимы, но я использую AspectJ, чтобы обеспечить, чтобы ни set-методы, ни конструкторы не вызывались где-либо в моей кодовой базе, кроме построителей, поэтому для практических целей результирующие объекты неизменяемы .

Также: Да, мне известны существующие плагины IDE Builder-generator. Это не соответствует моей цели, мне нужно автоматическое решение, которое ' s всегда в актуальном состоянии при изменении базового кода.


Мэтт Б. запросил некоторую информацию о том, как я генерирую свои компоновщики. Вот что я делаю:

Я читаю класс для каждого отражения, использую Introspector.getBeanInfo (clazz) .getPropertyDescriptors () , чтобы получить массив дескрипторов свойств. Все мои конструкторы имеют базовый класс AbstractBuilder , где T будет Foo в приведенном выше случае. Вот код класса Abstract Builder . Для каждого свойства в массиве PropertyDescriptor создается метод с именем свойства. Это будет реализация FooBuilder.bar (String) :

public FooBuilder bar(String bar){
    setProperty("bar", bar);
    return this;
}

метод build () в AbstractBuilder создает экземпляр объекта и назначает все свойства в его карте свойств.

8
задан Sean Patrick Floyd 23 November 2010 в 17:25
поделиться