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<?>) {
Type varContent = materializeTypeVariable(typeHierarchy, (TypeVariable<?>) tupleChild.getActualTypeArguments()[i]);
// variable could not be materialized
if (varContent == null) {
// add the TypeVariable as subtype for step in next section
subtypes[i] = tupleChild.getActualTypeArguments()[i];
} else {
// add class or parameterized type
subtypes[i] = varContent;
}
}
// 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<?>) {
ParameterizedType immediateBaseChild = (ParameterizedType) typeHierarchy.get(typeHierarchy.size() - 1);
tupleSubTypes[i] = createTypeInfoWithImmediateBaseChildInput(immediateBaseChild, (TypeVariable<?>) subtypes[i],
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);
}
}
// TODO: Check that type that extends Tuple does not have additional fields.
// Right now, these fields are not be serialized by the TupleSerializer.
// We might want to add an ExtendedTupleSerializer for that.
if (t instanceof Class<?>) {
return new TupleTypeInfo(((Class<? extends Tuple>) t), tupleSubTypes);
} else if (t instanceof ParameterizedType) {
return new TupleTypeInfo(((Class<? extends Tuple>) ((ParameterizedType) t).getRawType()), 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 != null) {
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 {
ParameterizedType immediateBaseChild = (ParameterizedType) typeHierarchy.get(typeHierarchy.size() - 1);
TypeInformation<OUT> typeInfo = (TypeInformation<OUT>) createTypeInfoWithImmediateBaseChildInput(immediateBaseChild,
(TypeVariable<?>) t, 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
// (due to a Java 6 bug, it is possible that BasicArrayTypes also get classified as ObjectArrayTypes
// since the JVM classifies e.g. String[] as GenericArrayType instead of Class)
else if (t instanceof GenericArrayType) {
GenericArrayType genericArray = (GenericArrayType) t;
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) {
return getForClass((Class<OUT>) ((ParameterizedType) t).getRawType());
}
// no tuple, no TypeVariable, no generic type
else if (t instanceof Class) {
return getForClass((Class<OUT>) t);
}
throw new InvalidTypesException("Type Information could not be created.");
}