В моем проекте у меня есть два пакета, полный DTO, POJO с только геттерами и сеттерами. Хотя важно, чтобы они были просто java-компонентами (например, поскольку Apache CXF использует их для создания XSD-сервисов и т. Д.), Это также ужасно и подвержено ошибкам для такой программы.Задача генератора Java Builder
Foo foo = new Foo();
foo.setBar("baz");
foo.setPhleem(123);
return foo;
Я предпочитаю беглые интерфейсы и объекты строитель, поэтому я использую Maven/gmaven для автоматического создания строителей для DTOS. Таким образом, для приведенного выше кода, 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)
но в моем строителе я хотел бы, чтобы генерировать два метода этого случая: метод набора и метод добавления:
fooBuilder.bings(List<Bing> bings); // set method
fooBuilder.addBing(Bing bing); // add method
Я решил, добавив пользовательскую аннотацию поля недвижимости в Foo
@ComponentType(Bing.class)
private List<Bing> bings;
строитель строитель (так в оригинале) читает аннотацию и использует значение в качестве универсального типа методов генерации.
Теперь мы приближаемся к вопросу (извините, краткость не является одним из моих достоинств :-)).
Я понял, что этот подход строителя можно использовать в более чем одном проекте, поэтому я думаю превратить его в плагин maven. Я прекрасно понимаю, как сгенерировать плагин maven, так что это не часть вопроса (равно как и не генерировать действительный исходный код Java). Моя проблема: как я могу иметь дело с двумя вышеуказанными проблемами без введения каких-либо общих зависимостей (между Project и Plugin):
<Question>
мне нужен класс Defaults (или аналогичный механизм) для получения значений по умолчанию для сгенерированных модульных тестов (это ключевая часть концепции, я бы не стал доверять автоматически созданным сборщикам, если они не были полностью протестированы). Пожалуйста, помогите мне придумать хороший и общий способ решить эту проблему, учитывая, что каждый проект будет иметь свои собственные объекты домена.
Мне нужен общий способ передачи общих типов генератору-генератору. Текущая версия, основанная на аннотациях, которую я использую, не является удовлетворительной, так как и проект, и плагин должны быть осведомлены об одной и той же аннотации.
</Question>
Любые идеи?
BTW: Я знаю, что реальная ключевая точка использования строителей делает объекты неизменными. Я не могу сделать мой неизменным, потому что стандартные компоненты java необходимы, но я использую AspectJ для обеспечения того, чтобы ни методы, ни конструкторы ни назывались нигде в моей базе кода, кроме как в сборщиках, поэтому для практических целей результирующие объекты неизменяемы ,
Также: Да, я знаю о существующих плагинах-установщиках Builder-генератора. Это не соответствует моей цели, я хочу автоматическое решение, которое всегда обновляется при изменении базового кода.
Matt B запросил некоторую информацию о том, как я генерирую своих строителей. Вот что я делаю:
Я прочитал класс за отражение, используйте Introspector.getBeanInfo(clazz).getPropertyDescriptors()
, чтобы получить массив дескрипторов свойств. Все мои строители имеют базовый класс AbstractBuilder<T>
, где T
будет Foo
в вышеуказанном случае. Вот the code of the Abstract Builder class. Для каждого свойства массива PropertyDescriptor
создается метод с именем свойства. Это будет реализация FooBuilder.bar(String)
:
public FooBuilder bar(String bar){
setProperty("bar", bar);
return this;
}
метод build()
в AbstractBuilder
конкретизирует объект и присваивает все свойства в его карте недвижимости.
Кроме того: когда мне нужно генерировать код Java (особенно огромные наборы модульных тестов), я использую grep/sed + python ... – khachik 2010-11-23 14:41:03
Мне нравится использовать технологию, которая понимает язык. Что ограничивает его: a) отражение b) парсер исходного кода c) инструмент байтового кода, такой как ASM – 2010-11-23 14:59:08
Из любопытства, какой плагин Maven генерирует классы Builder для вас? – 2010-11-23 14:59:23