protected UnresolvedType returnType;
protected UnresolvedType declaringType;
protected UnresolvedType[] parameterTypes;
- private final String signature;
- private String paramSignature;
+ private final String erasedSignature; // eg. (Ljava/util/Set;V)Ljava/lang/String;
+ private String paramSignature; // eg. (Ljava/util/Set<Ljava/lang/String;>;V) // no return type
// OPTIMIZE move out of the member!
private boolean reportedCantFindDeclaringType = false;
*/
private JoinPointSignatureIterator joinPointSignatures = null;
- public MemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, String name, String signature) {
+ /**
+ * Construct a MemberImpl using an erased signature for the parameters and return type (member method/ctor) or type (member field)
+ */
+ public MemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, String name, String erasedSignature) {
this.kind = kind;
this.declaringType = declaringType;
this.modifiers = modifiers;
this.name = name;
- this.signature = signature;
+ this.erasedSignature = erasedSignature;
if (kind == FIELD) {
- this.returnType = UnresolvedType.forSignature(signature);
+ this.returnType = UnresolvedType.forSignature(erasedSignature);
this.parameterTypes = UnresolvedType.NONE;
} else {
- Object[] returnAndParams = signatureToTypes(signature, false);
+ Object[] returnAndParams = signatureToTypes(erasedSignature);
this.returnType = (UnresolvedType) returnAndParams[0];
this.parameterTypes = (UnresolvedType[]) returnAndParams[1];
- // always safe not to do this ?!?
- // String oldsig=new String(signature);
- // signature = typesToSignature(returnType,parameterTypes,true);
}
}
+ /**
+ * Construct a MemberImpl using real type information for the parameters and return type (member method/ctor) or type (member field)
+ */
public MemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, UnresolvedType returnType, String name,
UnresolvedType[] parameterTypes) {
this.kind = kind;
this.name = name;
this.parameterTypes = parameterTypes;
if (kind == FIELD) {
- this.signature = returnType.getErasureSignature();
+ this.erasedSignature = returnType.getErasureSignature();
} else {
- this.signature = typesToSignature(returnType, parameterTypes, true);
+ this.erasedSignature = typesToSignature(returnType, parameterTypes, true);
+
+ // Check parameter recovery by collapsing types to the string then rebuilding them from that
+ // this will check we are capable of having WeakRefs to the parameter types
+// String nonErasedSignature = getParameterSignature()+getReturnType().getSignature();
+// Object[] returnAndParams = signatureToTypes(nonErasedSignature);
+// UnresolvedType[] recoveredParams = (UnresolvedType[]) returnAndParams[1];
+// for (int jj=0;jj<parameterTypes.length;jj++) {
+// if (!parameterTypes[jj].getSignature().equals(recoveredParams[jj].getSignature())) {
+// throw new RuntimeException(parameterTypes[jj].getSignature()+" != "+recoveredParams[jj].getSignature()+" "+paramSignature);
+// }
+// }
}
+
}
public ResolvedMember resolve(World world) {
// ---- utility methods
/**
- * returns an Object[] pair of UnresolvedType, UnresolvedType[] representing return type, argument types parsed from the JVM
- * bytecode signature of a method. Yes, this should actually return a nice statically-typed pair object, but we don't have one
- * of those.
- *
- * <blockquote>
- *
- * <pre>
- * UnresolvedType.signatureToTypes("()[Z")[0].equals(Type.forSignature("[Z"))
- * UnresolvedType.signatureToTypes("(JJ)I")[1]
- * .equals(UnresolvedType.forSignatures(new String[] {"J", "J"}))
- * </pre>
- *
- * </blockquote>
- *
- * @param signature the JVM bytecode method signature string we want to break apart
- * @return a pair of UnresolvedType, UnresolvedType[] representing the return types and parameter types.
+ * Build a signature based on the return type and parameter types. For example: "(Ljava/util/Set<Ljava/lang/String;>;)V"
+ * or "(Ljava/util/Set;)V". The latter form shows what happens when the generics are erased
*/
- // OPTIMIZE move static util methods out into a memberutils class
- public static String typesToSignature(UnresolvedType returnType, UnresolvedType[] paramTypes, boolean useRawTypes) {
- StringBuffer buf = new StringBuffer();
+ public static String typesToSignature(UnresolvedType returnType, UnresolvedType[] paramTypes, boolean eraseGenerics) {
+ StringBuilder buf = new StringBuilder();
buf.append("(");
- for (int i = 0, len = paramTypes.length; i < len; i++) {
- if (paramTypes[i].isParameterizedType() && useRawTypes) {
- buf.append(paramTypes[i].getErasureSignature());
- } else if (paramTypes[i].isTypeVariableReference() && useRawTypes) {
- buf.append(paramTypes[i].getErasureSignature());
+ for (UnresolvedType paramType: paramTypes) {
+ if (eraseGenerics && (paramType.isParameterizedType() || paramType.isTypeVariableReference())) {
+ buf.append(paramType.getErasureSignature());
} else {
- buf.append(paramTypes[i].getSignature());
+ buf.append(paramType.getSignature());
}
}
buf.append(")");
- if (returnType.isParameterizedType() && useRawTypes) {
- buf.append(returnType.getErasureSignature());
- } else if (returnType.isTypeVariableReference() && useRawTypes) {
- buf.append(returnType.getErasureSignature());
+ if (eraseGenerics && (returnType.isParameterizedType() || returnType.isTypeVariableReference())) {
+ buf.append(returnType.getErasureSignature());
} else {
buf.append(returnType.getSignature());
}
*
* </blockquote>
*
- * @param signature the JVM bytecode method signature string we want to break apart
+ * @param erasedSignature the JVM bytecode method signature string we want to break apart
* @return a pair of UnresolvedType, UnresolvedType[] representing the return types and parameter types.
*/
- private static Object[] signatureToTypes(String sig, boolean keepParameterizationInfo) {
+ private static Object[] signatureToTypes(String sig) {
boolean hasParameters = sig.charAt(1) != ')';
if (hasParameters) {
List l = new ArrayList();
} else if (c == 'T') { // assumed 'reference' to a type
// variable, so just "Tname;"
int nextSemicolon = sig.indexOf(';', start);
- String nextbit = sig.substring(start, nextSemicolon);
+ String nextbit = sig.substring(start, nextSemicolon+1);
l.add(UnresolvedType.forSignature(nextbit));
i = nextSemicolon + 1;
} else {
return field(declaring, mods, UnresolvedType.forSignature(signature), name);
}
- // public static Member field(UnresolvedType declaring, int mods, String
- // name, UnresolvedType type) {
- // return new MemberImpl(FIELD, declaring, mods, type, name,
- // UnresolvedType.NONE);
- // }
// OPTIMIZE do we need to call this? unless necessary the signatureToTypes()
- // call smacks of laziness on the behalf of the caller
- // of this method
+ // call smacks of laziness on the behalf of the caller of this method
public static MemberImpl method(UnresolvedType declaring, int mods, String name, String signature) {
- Object[] pair = signatureToTypes(signature, false);
+ Object[] pair = signatureToTypes(signature);
return method(declaring, mods, (UnresolvedType) pair[0], name, (UnresolvedType[]) pair[1]);
}
}
public static Member pointcut(UnresolvedType declaring, String name, String signature) {
- Object[] pair = signatureToTypes(signature, false);
+ Object[] pair = signatureToTypes(signature);
return pointcut(declaring, 0, (UnresolvedType) pair[0], name, (UnresolvedType[]) pair[1]);
}
public static MemberImpl method(UnresolvedType declTy, int mods, UnresolvedType rTy, String name, UnresolvedType[] paramTys) {
return new MemberImpl(
// ??? this calls <clinit> a method
- name.equals("<init>") ? CONSTRUCTOR : METHOD, declTy, mods, rTy, name, paramTys);
+ name.equals("<init>") ? CONSTRUCTOR : METHOD, declTy, mods, rTy, name, paramTys);
}
private static Member pointcut(UnresolvedType declTy, int mods, UnresolvedType rTy, String name, UnresolvedType[] paramTys) {
}
public String getSignature() {
- return signature;
+ return erasedSignature;
}
public int getArity() {
ResolvedMember[] parameterizedMethods = null;
ResolvedMember[] parameterizedFields = null;
ResolvedMember[] parameterizedPointcuts = null;
- ResolvedType[] parameterizedInterfaces = null;
+ WeakReference<ResolvedType[]> parameterizedInterfaces = new WeakReference<ResolvedType[]>(null);
Collection<Declare> parameterizedDeclares = null;
Collection parameterizedTypeMungers = null;
*/
@Override
public ResolvedType[] getDeclaredInterfaces() {
- if (parameterizedInterfaces != null) {
- return parameterizedInterfaces;
+ ResolvedType[] interfaces = parameterizedInterfaces.get();
+ if (interfaces != null) {
+ return interfaces;
}
ResolvedType[] delegateInterfaces = delegate.getDeclaredInterfaces();
if (newInterfaces != null) {
if (isParameterizedType()) {
// UnresolvedType[] paramTypes =
// getTypesForMemberParameterization();
- parameterizedInterfaces = new ResolvedType[delegateInterfaces.length];
+ interfaces = new ResolvedType[delegateInterfaces.length];
for (int i = 0; i < delegateInterfaces.length; i++) {
// We may have to sub/super set the set of parametertypes if the
// implemented interface
// needs more or less than this type does. (pr124803/pr125080)
if (delegateInterfaces[i].isParameterizedType()) {
- parameterizedInterfaces[i] = delegateInterfaces[i].parameterize(getMemberParameterizationMap()).resolve(world);
+ interfaces[i] = delegateInterfaces[i].parameterize(getMemberParameterizationMap()).resolve(world);
} else {
- parameterizedInterfaces[i] = delegateInterfaces[i];
+ interfaces[i] = delegateInterfaces[i];
}
}
- return parameterizedInterfaces;
+ parameterizedInterfaces = new WeakReference<ResolvedType[]>(interfaces);
+ return interfaces;
} else if (isRawType()) {
UnresolvedType[] paramTypes = getTypesForMemberParameterization();
- parameterizedInterfaces = new ResolvedType[delegateInterfaces.length];
- for (int i = 0; i < parameterizedInterfaces.length; i++) {
- parameterizedInterfaces[i] = delegateInterfaces[i];
- if (parameterizedInterfaces[i].isGenericType()) {
+ interfaces = new ResolvedType[delegateInterfaces.length];
+ for (int i = 0,max=interfaces.length; i < max; i++) {
+ interfaces[i] = delegateInterfaces[i];
+ if (interfaces[i].isGenericType()) {
// a generic supertype of a raw type is replaced by its raw
// equivalent
- parameterizedInterfaces[i] = parameterizedInterfaces[i].getRawType().resolve(getWorld());
- } else if (parameterizedInterfaces[i].isParameterizedType()) {
+ interfaces[i] = interfaces[i].getRawType().resolve(getWorld());
+ } else if (interfaces[i].isParameterizedType()) {
// a parameterized supertype collapses any type vars to
// their upper bounds
- UnresolvedType[] toUseForParameterization = determineThoseTypesToUse(parameterizedInterfaces[i], paramTypes);
- parameterizedInterfaces[i] = parameterizedInterfaces[i].parameterizedWith(toUseForParameterization);
+ UnresolvedType[] toUseForParameterization = determineThoseTypesToUse(interfaces[i], paramTypes);
+ interfaces[i] = interfaces[i].parameterizedWith(toUseForParameterization);
}
}
- return parameterizedInterfaces;
+ parameterizedInterfaces = new WeakReference<ResolvedType[]>(interfaces);
+ return interfaces;
}
if (delegate.isCacheable()) {
- parameterizedInterfaces = delegateInterfaces;
+ parameterizedInterfaces = new WeakReference<ResolvedType[]>(delegateInterfaces);
}
-
return delegateInterfaces;
}
private void clearParameterizationCaches() {
parameterizedFields = null;
- parameterizedInterfaces = null;
+ parameterizedInterfaces.clear();
parameterizedMethods = null;
parameterizedPointcuts = null;
superclassReference = new WeakReference<ResolvedType>(null);
annotationTypes = null;
newSuperclass = null;
newInterfaces = null;
- parameterizedInterfaces = null;
+ parameterizedInterfaces.clear();
superclassReference = new WeakReference<ResolvedType>(null);
}
newNewInterfaces[0] = newParent;
newInterfaces = newNewInterfaces;
}
- parameterizedInterfaces = null;// invalidate cached info
+ parameterizedInterfaces.clear();
}
}
}
\ No newline at end of file