Question

I'm trying to implement the builder pattern for generating Apache XmlBeans objects.

I've generated builders for all my classes, which inherit from:

public abstract class Builder<T extends XmlObject> {

    protected T xmlObject;

    @SuppressWarnings("unchecked")
    public T build() {
        return (T) xmlObject.copy();
    }
}

Then I've created several builders like this one (Time2Save inherits from XmlObject):

public class Time2SaveBuilder extends Builder<Time2Save> {
    public Time2SaveBuilder(int amount, String unit) {
        xmlObject = Time2Save.Factory.newInstance();
        xmlObject.setUnit(unit);
        xmlObject.setValue(amount);
    }
}

It works perfectly fine. But the problem I have is that I don't really like the duplication of having to instantiate the xmlObject in each builder, and I'd rather do it in the abstract Builder class if possible. So I've tried adding this constructor to the Builder class:

@SuppressWarnings("unchecked")
public Builder() {
    xmlObject =  (T) T.Factory.newInstance();
}

And leaving the implementations like this:

public class Time2SaveBuilder extends Builder<Time2Save> {
    public Time2SaveBuilder(int amount, String unit) {
        xmlObject.setUnit(unit);
        xmlObject.setValue(amount);
    }
}

The problem is that I get the following error:

Exception in thread "main" java.lang.ClassCastException:
    org.apache.xmlbeans.impl.values.XmlAnyTypeImpl cannot be cast to
    a.b.c.d.Time2SaveDocument$Time2Save

I think XmlAnyTypeImpl is the result of calling the static XmlObject.Factory instead of one from the inheriting class (in this case, Time2Save). I'd like to know why this is happening (since I'm calling T.Factory and not XmlObject.Factory) and if there's any way to do this without duplicating the Factory call in each builder implementation. Thanks!

Was it helpful?

Solution

Assuming all the built objects have a no-arg constructor (and a bunch of other assumptions), you can use this idiom:

class Builder<SHAPE extends Shape> {

  public final SHAPE shape = build();

  @SuppressWarnings("unchecked")
  private SHAPE build() {
    try {
      ParameterizedType parent = 
             (ParameterizedType) getClass().getGenericSuperclass();   
      Class<?> arg = (Class<?>) parent.getActualTypeArguments()[0];
      return (SHAPE) arg.newInstance();
    } catch (ReflectiveOperationException e) {
      throw new RuntimeException(e);
    }
  }

  public SHAPE shape() { return shape; }
}

But be warned that this may hide a problem with your design.

Why you should anyway look for alternatives

Static methods are convenient when you know how to use them, otherwise they will bite you. Without cheating with reflection, static methods must be invoked by naming the enclosing class in the very source code, making the code effectively impossible to reuse. Also, static methods are not virtual, ie subclasses can't override the parent behavior - again, you can cheat by using reflection and dispatch the call yourself.

Why it doesn't work

The construct

public class Foo<T extends MyOuter> {
  public String bar() {
    return T.MyNested.aStaticMethod();
  }
}

accessing static members on a type variable, is rarely seen (demo). Method signatures are resolved at compile time, so the value of T has no chance to be read (and, even if it were, type arguments don't survive the compilation step in Java). The type searched is resolved recursively and T is replaced with its upper bound, leading to the class name XmlObject.Factory.

OTHER TIPS

How about creating an abstract method that is being called from constructor? Just like this

public abstract class Builder<T extends XmlObject> {

   abstract protected T createObject();

   @SuppressWarnings("unchecked")
   public Builder() {
     xmlObject = (T) createObject();
   }
}

and then in Time2SaveBuilder you simply implement it to return proper factory instance. That should do the trick

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top