FluentBuilder

FluentBuilder is a small Java library which implements builder design pattern. It uses developer-configured interfaces and reflection methods to analyze target model and provides convenient builder API.

Fork me on GitHub

Simple

FluentBuilder designed as simple as possible. It requires implementation of your model-specific interface only. Target classes (or model) may be present as simple POJO. No XML/JSON/etc configuration files required.

Ready for extension

There is a possibility to use your own services. However you may completely redefine builder process.

Please check at the following extension points if you like:

  • BuilderIntrospector
  • PropertySetter
  • TargetInstantiator

Compact size

FluentBuilder is really small:

  • The only one JAR artifact (24K size)
  • The only one external dependency (SLF4J)

1  Model class

public class Product
{
    private String name;
    private Integer price;
    private Integer quantity;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public Integer getPrice() { return price; }
    public void setPrice(Integer price) { this.price = price; }

    public Integer getQuantity() { return quantity; }
    public void setQuantity(Integer quantity) { this.quantity = quantity; }
}
  1. You may create or use existing class.
  2. Add get/set methods to turn your class into the POJO bean.

2  Builder interface

@TargetClass(Product.class)
public interface ProductBuilder<R>
		extends NestedBuilder<Product, R>
{
    public ProductBuilder<R> setName(String name);
    public ProductBuilder<R> setPrice(Integer price);
    public ProductBuilder<R> setQuantity(Integer quantity);
}
  1. Create interface as shown.
  2. Add @TargetClass annotation to link builder with its target type.
  3. Extend interface from the NestedBuilder. It is required to marks your interface as builder and also allows to use ProductBuilder as part of subsequent calls of builder methods.
  4. Copy setter methods from model class into the builder interface. Every setter method should have the same signature as used in the target type except the return type signature.

Note: The builder interface should be generic-enabled to avoid unnecessary cast and use compile time checking.

3  BuilderFactoryFacade

BuilderFactoryFacade factoryFacade = new DefaultBuilderFactoryFacade();
ProductBuilder builder = factoryFacade.createRootBuilder(ProductBuilder.class);
Product product = builder
	        .setName("Potato")
	        .setPrice(10)
	        .setQuantity(20)
	        .build();
  1. Create instance of the DefaultBuilderFactoryFacade.
  2. Create instance of the ProductBuilder.
  3. Build the target instance using fluent interface.

There are a set of rules for implementing builder interface:

  • Builder interfaces should extend the RootBuilder interface. Inheritance of builders are supported, you may use sub-interfaces like NestedBuilder.
  • Your builder interface should be marked with @TargetClass annotation.
  • Only following interface methods are supported:
    • build()/back(). Please use methods inherited from RootBuilder/NestedBuilder interfaces only, do not declare your own. Use correct generic types to get expected target type.
    • set*(). Each set method should have the same signature as method from the target type. Setter methods should return current builder interface type.
    • add*() method allows to add objects to the target field of collection type. It shouldn't have any arguments. Add methods should return type of interface inherited from NestedBuilder interface.

  • Default constructor is required for the target type.
  • set*()/add*() builder methods require appropriate methods in the target type.
  • add*() methods work only with collection-type fields. Arrays are not supported.

  • Since version 0.0.2 set*() methods support primitive type arguments with automatic conversion of values between Model and Builder interfaces