Type curT = t;
// do not allow usage of Tuple as type
if (curT instanceof Class<?> && ((Class<?>) curT).equals(Tuple.class)) {
throw new InvalidTypesException(
"Usage of class Tuple as a type is not allowed. Use a concrete subclass (e.g. Tuple1, Tuple2, etc.) instead.");
}
// go up the hierarchy until we reach immediate child of Tuple (with or without generics)
// collect the types while moving up for a later top-down
while (!(curT instanceof ParameterizedType && ((Class<?>) ((ParameterizedType) curT).getRawType()).getSuperclass().equals(
Tuple.class))
&& !(curT instanceof Class<?> && ((Class<?>) curT).getSuperclass().equals(Tuple.class))) {
typeHierarchy.add(curT);
// parameterized type
if (curT instanceof ParameterizedType) {
curT = ((Class<?>) ((ParameterizedType) curT).getRawType()).getGenericSuperclass();
}
// class
else {
curT = ((Class<?>) curT).getGenericSuperclass();
}
}
// check if immediate child of Tuple has generics
if (curT instanceof Class<?>) {
throw new InvalidTypesException("Tuple needs to be parameterized by using generics.");
}
ParameterizedType tupleChild = (ParameterizedType) curT;
Type[] subtypes = new Type[tupleChild.getActualTypeArguments().length];
// materialize possible type variables
for (int i = 0; i < subtypes.length; i++) {
// materialize immediate TypeVariables
if (tupleChild.getActualTypeArguments()[i] instanceof TypeVariable<?>) {
subtypes[i] = materializeTypeVariable(typeHierarchy, (TypeVariable<?>) tupleChild.getActualTypeArguments()[i]);
}
// class or parameterized type
else {
subtypes[i] = tupleChild.getActualTypeArguments()[i];
}
}
TypeInformation<?>[] tupleSubTypes = new TypeInformation<?>[subtypes.length];
for (int i = 0; i < subtypes.length; i++) {
// sub type could not be determined with materializing
// try to derive the type info of the TypeVariable from the immediate base child input as a last attempt
if (subtypes[i] instanceof TypeVariable<?>) {
tupleSubTypes[i] = createTypeInfoFromInputs((TypeVariable<?>) subtypes[i], typeHierarchy, in1Type, in2Type);
// variable could not be determined
if (tupleSubTypes[i] == null) {
throw new InvalidTypesException("Type of TypeVariable '" + ((TypeVariable<?>) subtypes[i]).getName() + "' in '"
+ ((TypeVariable<?>) subtypes[i]).getGenericDeclaration()
+ "' could not be determined. This is most likely a type erasure problem. "
+ "The type extraction currently supports types with generic variables only in cases where "
+ "all variables in the return type can be deduced from the input type(s).");
}
} else {
tupleSubTypes[i] = createTypeInfoWithTypeHierarchy(new ArrayList<Type>(typeHierarchy), subtypes[i], in1Type, in2Type);
}
}
Class<?> tAsClass = null;
if (t instanceof Class<?>) {
tAsClass = (Class<?>) t;
} else if (t instanceof ParameterizedType) {
tAsClass = (Class<? extends Tuple>) ((ParameterizedType) t).getRawType();
}
Preconditions.checkNotNull(tAsClass, "t has a unexpected type");
// check if the class we assumed to be a Tuple so far is actually a pojo because it contains additional fields.
// check for additional fields.
int fieldCount = countFieldsInClass(tAsClass);
if(fieldCount != tupleSubTypes.length) {
// the class is not a real tuple because it contains additional fields. treat as a pojo
return (TypeInformation<OUT>) analyzePojo(tAsClass, new ArrayList<Type>(), null); // the typeHierarchy here should be sufficient, even though it stops at the Tuple.class.
}
return new TupleTypeInfo(tAsClass, tupleSubTypes);
}
// type depends on another type
// e.g. class MyMapper<E> extends MapFunction<String, E>
else if (t instanceof TypeVariable) {
Type typeVar = materializeTypeVariable(typeHierarchy, (TypeVariable<?>) t);
if (!(typeVar instanceof TypeVariable)) {
return createTypeInfoWithTypeHierarchy(typeHierarchy, typeVar, in1Type, in2Type);
}
// try to derive the type info of the TypeVariable from the immediate base child input as a last attempt
else {
TypeInformation<OUT> typeInfo = (TypeInformation<OUT>) createTypeInfoFromInputs((TypeVariable<?>) t, typeHierarchy, in1Type, in2Type);
if (typeInfo != null) {
return typeInfo;
} else {
throw new InvalidTypesException("Type of TypeVariable '" + ((TypeVariable<?>) t).getName() + "' in '"
+ ((TypeVariable<?>) t).getGenericDeclaration() + "' could not be determined. This is most likely a type erasure problem. "
+ "The type extraction currently supports types with generic variables only in cases where "
+ "all variables in the return type can be deduced from the input type(s).");
}
}
}
// arrays with generics
else if (t instanceof GenericArrayType) {
GenericArrayType genericArray = (GenericArrayType) t;
Type componentType = genericArray.getGenericComponentType();
// due to a Java 6 bug, it is possible that the JVM classifies e.g. String[] or int[] as GenericArrayType instead of Class
if (componentType instanceof Class) {
Class<?> componentClass = (Class<?>) componentType;
String className;
// for int[], double[] etc.
if(componentClass.isPrimitive()) {
className = encodePrimitiveClass(componentClass);
}
// for String[], Integer[] etc.
else {
className = "L" + componentClass.getName() + ";";
}
Class<OUT> classArray = null;
try {
classArray = (Class<OUT>) Class.forName("[" + className);
} catch (ClassNotFoundException e) {
throw new InvalidTypesException("Could not convert GenericArrayType to Class.");
}
return getForClass(classArray);
}
TypeInformation<?> componentInfo = createTypeInfoWithTypeHierarchy(typeHierarchy, genericArray.getGenericComponentType(),
in1Type, in2Type);
return ObjectArrayTypeInfo.getInfoFor(t, componentInfo);
}
// objects with generics are treated as raw type
else if (t instanceof ParameterizedType) { //TODO
return privateGetForClass((Class<OUT>) ((ParameterizedType) t).getRawType(), typeHierarchy, (ParameterizedType) t);
}
// no tuple, no TypeVariable, no generic type
else if (t instanceof Class) {
return privateGetForClass((Class<OUT>) t, new ArrayList<Type>());
}
throw new InvalidTypesException("Type Information could not be created.");
}