2010-11-23 9 views
8

В моем проекте у меня есть два пакета, полный 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>

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

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

</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 конкретизирует объект и присваивает все свойства в его карте недвижимости.

+0

Кроме того: когда мне нужно генерировать код Java (особенно огромные наборы модульных тестов), я использую grep/sed + python ... – khachik 2010-11-23 14:41:03

+0

Мне нравится использовать технологию, которая понимает язык. Что ограничивает его: a) отражение b) парсер исходного кода c) инструмент байтового кода, такой как ASM – 2010-11-23 14:59:08

+0

Из любопытства, какой плагин Maven генерирует классы Builder для вас? – 2010-11-23 14:59:23

ответ

1

Вы просмотрели Diezel? Это генератор Builder.

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^