private static void writeGenericsBounds( StringBuffer ret, GenericsType type, boolean writeInterfaceMarker) { if (type.getUpperBounds() != null) { ClassNode[] bounds = type.getUpperBounds(); for (int i = 0; i < bounds.length; i++) { writeGenericsBoundType(ret, bounds[i], writeInterfaceMarker); } } else if (type.getLowerBound() != null) { writeGenericsBoundType(ret, type.getLowerBound(), writeInterfaceMarker); } else { writeGenericsBoundType(ret, type.getType(), writeInterfaceMarker); } }
/** * Given a parameterized type and a generic type information, aligns actual type parameters. For * example, if a class uses generic type * * <pre><T,U,V></pre> * * (redirectGenericTypes), is used with actual type parameters * * <pre><java.lang.String, U,V></pre> * * , then a class or interface using generic types * * <pre><T,V></pre> * * will be aligned to * * <pre><java.lang.String,V></pre> * * @param redirectGenericTypes the type arguments or the redirect class node * @param parameterizedTypes the actual type arguments used on this class node * @param alignmentTarget the generic type arguments to which we want to align to * @return aligned type arguments */ public static GenericsType[] alignGenericTypes( final GenericsType[] redirectGenericTypes, final GenericsType[] parameterizedTypes, final GenericsType[] alignmentTarget) { if (alignmentTarget == null) return EMPTY_GENERICS_ARRAY; if (parameterizedTypes == null || parameterizedTypes.length == 0) return alignmentTarget; GenericsType[] generics = new GenericsType[alignmentTarget.length]; for (int i = 0, scgtLength = alignmentTarget.length; i < scgtLength; i++) { final GenericsType currentTarget = alignmentTarget[i]; GenericsType match = null; if (redirectGenericTypes != null) { for (int j = 0; j < redirectGenericTypes.length && match == null; j++) { GenericsType redirectGenericType = redirectGenericTypes[j]; if (redirectGenericType.isCompatibleWith(currentTarget.getType())) { if (currentTarget.isPlaceholder() && redirectGenericType.isPlaceholder() && !currentTarget.getName().equals(redirectGenericType.getName())) { // check if there's a potential better match boolean skip = false; for (int k = j + 1; k < redirectGenericTypes.length && !skip; k++) { GenericsType ogt = redirectGenericTypes[k]; if (ogt.isPlaceholder() && ogt.isCompatibleWith(currentTarget.getType()) && ogt.getName().equals(currentTarget.getName())) { skip = true; } } if (skip) continue; } match = parameterizedTypes[j]; if (currentTarget.isWildcard()) { // if alignment target is a wildcard type // then we must make best effort to return a parameterized // wildcard ClassNode lower = currentTarget.getLowerBound() != null ? match.getType() : null; ClassNode[] currentUpper = currentTarget.getUpperBounds(); ClassNode[] upper = currentUpper != null ? new ClassNode[currentUpper.length] : null; if (upper != null) { for (int k = 0; k < upper.length; k++) { upper[k] = currentUpper[k].isGenericsPlaceHolder() ? match.getType() : currentUpper[k]; } } match = new GenericsType(ClassHelper.makeWithoutCaching("?"), upper, lower); match.setWildcard(true); } } } } if (match == null) { match = currentTarget; } generics[i] = match; } return generics; }
/** * This exists to avoid a recursive definition of toString. The default toString in GenericsType * calls ClassNode.toString(), which calls GenericsType.toString(), etc. * * @param genericsType * @param showRedirect * @return the string representing the generic type */ private String genericTypeAsString(GenericsType genericsType, boolean showRedirect) { String ret = genericsType.getName(); if (genericsType.getUpperBounds() != null) { ret += " extends "; for (int i = 0; i < genericsType.getUpperBounds().length; i++) { ClassNode classNode = genericsType.getUpperBounds()[i]; if (classNode.equals(this)) { ret += classNode.getName(); } else { ret += classNode.toString(showRedirect); } if (i + 1 < genericsType.getUpperBounds().length) ret += " & "; } } else if (genericsType.getLowerBound() != null) { ClassNode classNode = genericsType.getLowerBound(); if (classNode.equals(this)) { ret += " super " + classNode.getName(); } else { ret += " super " + classNode; } } return ret; }