Answering to a last part of question. Actually you may check if there is a correct type passed. You can obtain generic type parameter for constructor argument like this
// in your case that will give you parametrized type
// java.util.List<java.lang.Integer>
Type type = constructor.getGenericParameterTypes()[0];
ParameterizedType argumentType = (ParameterizedType) type;
// that will give you List type parameter - java.lang.Integer
Type argumentType = type[0];
That also works for fields unless list parameter not generic itself.
There is another trick. You can store generic parameter using type reference using anonymous class:
public abstract class TypeReference<T> {
private final Type type;
public TypeReference() {
if (!getClass().isAnonymousClass()) {
throw new IllegalArgumentException(getClass() + " should be anonymous");
}
final Type superClass = getClass().getGenericSuperclass();
if (!(superClass instanceof ParameterizedType)) {
throw new IllegalArgumentException("missing type parameter due to type erasure");
}
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public final Type getType() {
return this.type;
}
}
So here is very basic idea how you can achieve your goal. You may preserve generic parameter using type reference and check argument like this:
public class ObjectBuilder<T> {
List<Object> validatedArguments = new ArrayList<>();
Constructor<T> ctor = /*... */;
public void <A> addArgument(A argument
TypeReference<A> argumentType) {
int currentArgument = validatedArguments.size();
Type ctorArgumentType =
ctor.getGenericParameterTypes()[currentArgument]/* */;
Type argumentType = argumentType.getType();
// compare it carefully!
validatedArguments.add(argument);
}
public T build() {
// new instance creating ...
}
}
ObjectBuilder<TestSubject> subject = new ObjectBuilder<>();
subject.addArgument(list, new TypeReference<List<Integer>>() {})
TestSubject obj = subject.build();
, TestSubject> constructor = TestSubject::new;`
– ZhongYu Aug 16 '16 at 17:11