Nie nudząc technicznymi szczegółami przejdźmy do przykładu. Klasę np. Order oznaczamy adnotacją @GenerateBuilder, która informuje procesor, że dla niej ma zostać wygenerowany builder:
@GenerateBuilder
public class Order {
private List<OrderItem> items;
private Date createDate;
private boolean realized;
public boolean isRealized() {
return realized;
}
public void orderRealized() {
// very complex implementation
realized = true;
}
}
Żeby w jakiś sposób automatycznie aktualizować istniejące buildery o nowe pola, które doszły w klasie Order (lub odpowiednio usuwać metody inicjujące nieistniejące pola), builder został rozbity na 2 klasy. Jedna z nich jest aktualizowana zawsze przy uruchomieniu procesora, druga generowana tylko raz, dzięki czemu możemy do niej dodawać własne metody budujące. Dla klasy Order powstaną następujące klasy:
public abstract class AbstractOrderBuilder<B> extends AbstractBuilder<Order, B> {
public abstract B withItems(List<OrderItem> items);
public abstract B withCreateDate(Date createDate);
public abstract B withRealized(boolean realized);
public B withItems(OrderItem... items){
return withItems(new ArrayList<OrderItem>(Arrays.asList(items)));
}
}
public abstract class OrderBuilder extends AbstractOrderBuilder<OrderBuilder> {
public static OrderBuilder anOrder(){
return AbstractBuilderFactory.createImplementation(OrderBuilder.class);
}
}
Samo użycie może wyglądać następująco:
@Test
public void shouldCreateRealizedOrder() {
// when
Order order = anOrder().withRealized(true).build();
// then
assertTrue(order.isRealized());
}
Klasę OrderBuilder można rozszerzać, wywołując rzeczywiste metody domenowe, np:
public abstract class OrderBuilder extends AbstractOrderBuilder<OrderBuilder> {
public static OrderBuilder create() {
return AbstractBuilderFactory.createImplementation(OrderBuilder.class);
}
public OrderBuilder realized() {
Order order = targetObject();
// invoking real domain method
order.orderRealized();
// other methods
return builder();
}
}
@Test
public void shouldCreateRealizedOrder() {
// when
Order order = anOrder().realized().build();
// then
assertTrue(order.isRealized());
}
Do podłączenia procesora do projektu może zostać wykorzystany ant, maven, eclipse. Jest również możliwość użycia generatora w starym stylu, czyli wygenerowania ciała klasy buildera do konsoli.Procesor może również poszukiwać klas z adnotacjami JPA (@Entity, @Ebeddable, @MappedSuperclass).
Do poznania szczegółów odsyłam do wiki projektu. Zachęcam do forkowania i dzielenia się uwagami.