Crosk Cool
Crosk Cool

Reputation: 734

What is the best way to make a builder return objects of two different POJOs having same fields

POJO1

@Builder
Class POJO1 
{ 
   private String astring;
   private String bstring;
}

POJO2

@Builder
Class POJO2
{
   private String astring;
   private String bstring;
}

builderMethod

private POJO1 buildPOJO()
{
   return POJO1.builder().withaString().withbString().build();
}

What i want

POJO1 pojo = buildPOJO();
POJO2 pojo = buildPOJO(); // Same method to build both pojo's

I have these two pojo's in my code. And I have to build them at several places. Both the pojo's will always contain same fields, and the number of fields is substantial too. I have to build a buildPOJO method by which i can make the objects of both POJO. I don't have a clear-cut idea but as the fields are always similar. Can casting or any other way will be helpful in achieving this?

Upvotes: 0

Views: 599

Answers (1)

teppic
teppic

Reputation: 7286

With a proxy wrapper you can use a common interface without having to implement it in your classes. Extract the common setters to an interface and use it in your builder to set the common fields.

The proxy code is minimal:

public class Wrapper<T> implements InvocationHandler {
    private final T delegate;

    public Wrapper(T delegate) {
        this.delegate = delegate;
    }

    public static <T, I> I proxy(T delegate, Class<I> facade) {
        return (I) Proxy.newProxyInstance(
            facade.getClassLoader(),
            new Class[] { facade },
            new Wrapper(delegate)
        );
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return delegate.getClass().getDeclaredMethod(method.getName(), method.getParameterTypes()).invoke(delegate, args);
    }
}

And simple enough to use in the builder:

class PojoBuilder {
    private String foo;
    private int bar;
    private String a, b;

    public PojoBuilder withFoo(String foo) {
        this.foo = foo;
        return this;
    }

    public PojoBuilder withBar(int bar) {
        this.bar = bar;
        return this;
    }

    public PojoBuilder withA(String a) {
        this.a = a;
        return this;
    }

    public PojoBuilder withB(String b) {
        this.b = b;
        return this;
    }

    public PojoA buildA() {
        PojoA a = new PojoA();
        buildCommon(Wrapper.proxy(a, Pojo.class));
        a.setA(this.a);
        return a;
    }

    public PojoB buildB() {
        PojoB b = new PojoB();
        buildCommon(Wrapper.proxy(b, Pojo.class));
        b.setB(this.b);
        return b;
    }

    private void buildCommon(Pojo common) {
        common.setFoo(foo);
        common.setBar(bar);
    }
}

// Common setters for all pojos
interface Pojo {
    void setFoo(String foo);
    void setBar(int bar);
}

// One of the pojos.
// Note that this doesn't actually implement Pojo
class PojoA {
    private String foo;
    private int bar;
    private String a;

    public String getFoo() {
        return foo;
    }

    public void setFoo(String foo) {
        this.foo = foo;
    }

    public int getBar() {
        return bar;
    }

    public void setBar(int bar) {
        this.bar = bar;
    }

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }
}

class PojoB {
    private String foo;
    private int bar;
    private String b;

    public String getFoo() {
        return foo;
    }

    public void setFoo(String foo) {
        this.foo = foo;
    }

    public int getBar() {
        return bar;
    }

    public void setBar(int bar) {
        this.bar = bar;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }
}

Upvotes: 1

Related Questions