В моем проекте у меня есть два пакета, полные DTO, POJO только с геттерами и сеттерами.Несмотря на то, что важно, чтобы они были простыми Java-бинами (например, потому что Apache CXF использует их для создания XSD-файлов Web-служб и т. Д.), Они также ужасны и подвержены ошибкам.и объекты builder, поэтому я использую 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).Моя проблема: как я могу справиться с двумя вышеупомянутыми проблемами без введения каких-либо общих зависимостей (между проектом и плагином):
<Question>
Мне нужен класс Defaults (или аналогичный механизм) для получения значений по умолчанию для сгенерированных модульных тестов (это ключевая часть концепции, я бы не стал доверять автоматически сгенерированным компоновщикам, если бы они не были полностью протестированы).Пожалуйста, помогите мне найти хороший и общий способ решения этой проблемы, учитывая, что каждый проект будет иметь свои собственные доменные объекты.
Мне нужен общий способ передачи универсальных типов встроительный генератор.Текущая версия на основе аннотаций, которую я использую, не является удовлетворительной, поскольку и проект, и плагин должны знать одну и ту же аннотацию.
</Question>
Есть идеи?
Кстати: я знаю, что реальный ключевой момент использования строителей - сделать объекты неизменяемыми.Я не могу сделать мой неизменяемым, потому что стандартные Java-бины необходимы, но я использую AspectJ для обеспечения того, чтобы ни set-методы, ни конструкторы не вызывались нигде в моей базе кода, кроме как в сборщиках, поэтому для практических целей результирующие объекты являются неизменяемыми.
Также: Да, мне известны существующие плагины для IDE Builder-генератора.Это не соответствует моей цели, я хочу автоматизированное решение, которое всегда обновляется всякий раз, когда изменяется базовый код.
Мэтт Б запросил некоторую информацию о том, как я генерирую мои сборщики.Вот что я делаю:
Я читаю класс для каждого отражения, использую 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
создает экземпляр объекта и назначает все свойства в его карте свойств.