vendredi 11 mai 2018

Creating a generic JavaBean builder

I'm trying to create a generic builder for value classes. You know those dumb classes full of getter and setters.

The goal is to be able to use it like this:

        MyValueObject myvalueObject = new GenericBuilder<MyValueObject>(MyValueObject.class)
            .with("someIntegerProperty", 12)
            .build();

Here's my attempt so far using reflection:

public class GenericBuilder<T> {
    private T bean;
    private Class<T> clazz;

    public GenericBuilder(Class<T> clazz) {
        this.clazz = clazz;

        Constructor<?> constructor = null;
        try {
            constructor = Class.forName(clazz.getCanonicalName()).getConstructor();
            bean = (T) constructor.newInstance();
        } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
            e.printStackTrace();
        }
    }

    public <S> GenericBuilder<T> with(String propertyName, S value) {
        Method method;
        try {
            method = Class.forName(clazz.getCanonicalName())
                .getMethod("set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1), Object.class);
            method.invoke(bean, (S) value);
        } catch (NoSuchMethodException | ClassNotFoundException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return this;
    }

    public T build() {
        return bean;
    }
}

However the method invocation fails with a NoSuchMethodException because the determined parameter type at runtime is Object instead of the correct type. This is due to type erasure.

I know that I can get the actual parameter type with method.getParameterTypes()[0], but I cannot use it to cast the value like this

method.invoke(bean, (method.getParameterTypes()[0]) value); //compiler error

How can I fix this?





Aucun commentaire:

Enregistrer un commentaire