// box all the types and compute the intersection of all types
Set<JClass> s = null;
for (JType type : uniqueTypes) {
JClass cls = type.boxify();
if (s == null)
s = getAssignableTypes(cls);
else
s.retainAll(getAssignableTypes(cls));
}
// any JClass can be casted to Object, so make sure it's always there
s.add( codeModel.ref(Object.class));
// refine 's' by removing "lower" types.
// for example, if we have both java.lang.Object and
// java.io.InputStream, then we don't want to use java.lang.Object.
JClass[] raw = s.toArray(new JClass[s.size()]);
s.clear();
for (int i = 0; i < raw.length; i++) { // for each raw[i]
int j;
for (j = 0; j < raw.length; j++) { // see if raw[j] "includes" raw[i]
if (i == j)
continue;
if (raw[i].isAssignableFrom(raw[j]))
break; // raw[j] is derived from raw[i], hence j includes i.
}
if (j == raw.length)
// no other type inclueds raw[i]. remember this value.
s.add(raw[i]);
}
assert !s.isEmpty(); // since at least java.lang.Object has to be there
// we now pick the candidate for the return type
JClass result = pickOne(s);
// finally, sometimes this method is used to compute the base type of types like
// JAXBElement<A>, JAXBElement<B>, and JAXBElement<C>.
// for those inputs, at this point result=JAXBElement.
//
// here, we'll try to figure out the parameterization
// so that we can return JAXBElement<? extends D> instead of just "JAXBElement".
if(result.isParameterized())
return result;
// for each uniqueType we store the list of base type parameterization
List<List<JClass>> parameters = new ArrayList<List<JClass>>(uniqueTypes.size());
int paramLen = -1;
for (JType type : uniqueTypes) {
JClass cls = type.boxify();
JClass bp = cls.getBaseClass(result);
// if there's no parameterization in the base type,
// we won't do any better than <?>. Thus no point in trying to figure out the parameterization.
// just return the base type.
if(bp.equals(result))
return result;
assert bp.isParameterized();
List<JClass> tp = bp.getTypeParameters();
parameters.add(tp);
assert paramLen==-1 || paramLen==tp.size();
// since 'bp' always is a parameterized version of 'result', it should always
// have the same number of parameters.
paramLen = tp.size();
}
List<JClass> paramResult = new ArrayList<JClass>();
List<JClass> argList = new ArrayList<JClass>(parameters.size());
// for each type parameter compute the common base type
for( int i=0; i<paramLen; i++ ) {
argList.clear();
for (List<JClass> list : parameters)
argList.add(list.get(i));
// compute the lower bound.
JClass bound = (JClass)getCommonBaseType(codeModel,argList);
boolean allSame = true;
for (JClass a : argList)
allSame &= a.equals(bound);
if(!allSame)
bound = bound.wildcard();
paramResult.add(bound);
}
return result.narrow(paramResult);