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

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

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<Class<?>, Object> DEFAULT_VALUES =
        new HashMap<Class<?>, 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<Bing> bings)

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

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

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

@ComponentType(Bing.class)
private List<Bing> bings;

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

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

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

<Question>

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

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

</Question>

Есть идеи?

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

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


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

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

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

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

2 ответа

Решение

Вы смотрели на Дизеля? Это генератор Builder.

  1. Он обрабатывает универсальные типы, поэтому он может быть полезен здесь для вопроса 2
  2. Он генерирует все интерфейсы и реализацию, основанную на файле описания XML. Вы можете с помощью самоанализа сгенерировать этот XML (или даже перейти непосредственно к более низкому API)
  3. Он поставляется как плагин Maven.

POJO - это объект, который не следует за спуком Java Bean. то есть. у него нет сеттеров / геттеров.

JavaBeans не обязаны иметь сеттеры, если вы не хотите, чтобы они вызывались, не генерируйте их. (Ваш конструктор может вызвать пакет локальным или частным конструктором для создания ваших неизменяемых объектов)

Другие вопросы по тегам