/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     PARC     initial implementation 
 * ******************************************************************/

package org.aspectj.weaver;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

public class MemberImpl implements Member {

	protected MemberKind kind;
	protected int modifiers;
	protected String name;
	protected UnresolvedType declaringType;
	protected UnresolvedType returnType;
	protected UnresolvedType[] parameterTypes;
	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 boolean reportedUnresolvableMember = false;

	
All the signatures that a join point with this member as its signature has.
/** * All the signatures that a join point with this member as its signature has. */
private JoinPointSignatureIterator joinPointSignatures = null;
Construct a MemberImpl using an erased signature for the parameters and return type (member method/ctor) or type (member field)
/** * 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.erasedSignature = erasedSignature; if (kind == FIELD) { this.returnType = UnresolvedType.forSignature(erasedSignature); this.parameterTypes = UnresolvedType.NONE; } else { Object[] returnAndParams = signatureToTypes(erasedSignature); this.returnType = (UnresolvedType) returnAndParams[0]; this.parameterTypes = (UnresolvedType[]) returnAndParams[1]; } }
Construct a MemberImpl using real type information for the parameters and return type (member method/ctor) or type (member field)
/** * 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.declaringType = declaringType; this.modifiers = modifiers; this.returnType = returnType; this.name = name; this.parameterTypes = parameterTypes; if (kind == FIELD) { this.erasedSignature = returnType.getErasureSignature(); } else { 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) { return world.resolve(this); } // ---- utility methods
Build a signature based on the return type and parameter types. For example: "(Ljava/util/Set;)V" or "(Ljava/util/Set;)V". The latter form shows what happens when the generics are erased
/** * 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 */
public static String typesToSignature(UnresolvedType returnType, UnresolvedType[] paramTypes, boolean eraseGenerics) { StringBuilder buf = new StringBuilder(); buf.append("("); for (UnresolvedType paramType : paramTypes) { if (eraseGenerics) { buf.append(paramType.getErasureSignature()); } else { buf.append(paramType.getSignature()); } } buf.append(")"); if (eraseGenerics) { buf.append(returnType.getErasureSignature()); } else { buf.append(returnType.getSignature()); } return buf.toString(); }
Returns "(,...)" - unlike the other typesToSignature that also includes the return type, this one just deals with the parameter types.
/** * Returns "(<signaturesOfParamTypes>,...)" - unlike the other typesToSignature that also includes the return type, this one * just deals with the parameter types. */
public static String typesToSignature(UnresolvedType[] paramTypes) { StringBuffer buf = new StringBuffer(); buf.append("("); for (int i = 0; i < paramTypes.length; i++) { buf.append(paramTypes[i].getSignature()); } buf.append(")"); return buf.toString(); }
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.
  UnresolvedType.signatureToTypes("()[Z")[0].equals(Type.forSignature("[Z"))
  UnresolvedType.signatureToTypes("(JJ)I")[1]
     .equals(UnresolvedType.forSignatures(new String[] {"J", "J"}))
Params:
  • erasedSignature – the JVM bytecode method signature string we want to break apart
Returns:a pair of UnresolvedType, UnresolvedType[] representing the return types and parameter types.
/** * 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(&quot;()[Z&quot;)[0].equals(Type.forSignature(&quot;[Z&quot;)) * UnresolvedType.signatureToTypes(&quot;(JJ)I&quot;)[1] * .equals(UnresolvedType.forSignatures(new String[] {&quot;J&quot;, &quot;J&quot;})) * </pre> * * </blockquote> * * @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 hasParameters = sig.charAt(1) != ')'; if (hasParameters) { List<UnresolvedType> l = new ArrayList<UnresolvedType>(); int i = 1; boolean hasAnyAnglies = sig.indexOf('<') != -1; while (true) { char c = sig.charAt(i); if (c == ')') { break; // break out when the hit the ')' } int start = i; while (c == '[') { c = sig.charAt(++i); } if (c == 'L' || c == 'P') { int nextSemicolon = sig.indexOf(';', start); int firstAngly = (hasAnyAnglies ? sig.indexOf('<', start) : -1); if (!hasAnyAnglies || firstAngly == -1 || firstAngly > nextSemicolon) { i = nextSemicolon + 1; l.add(UnresolvedType.forSignature(sig.substring(start, i))); } else { // generics generics generics // Have to skip to the *correct* ';' boolean endOfSigReached = false; int posn = firstAngly; int genericDepth = 0; while (!endOfSigReached) { switch (sig.charAt(posn)) { case '<': genericDepth++; break; case '>': genericDepth--; break; case ';': if (genericDepth == 0) { endOfSigReached = true; } break; default: } posn++; } // posn now points to the correct nextSemicolon :) i = posn; l.add(UnresolvedType.forSignature(sig.substring(start, i))); } } else if (c == 'T') { // assumed 'reference' to a type // variable, so just "Tname;" int nextSemicolon = sig.indexOf(';', start); String nextbit = sig.substring(start, nextSemicolon + 1); l.add(UnresolvedType.forSignature(nextbit)); i = nextSemicolon + 1; } else { i++; l.add(UnresolvedType.forSignature(sig.substring(start, i))); } } UnresolvedType[] paramTypes = l.toArray(new UnresolvedType[l.size()]); UnresolvedType returnType = UnresolvedType.forSignature(sig.substring(i + 1, sig.length())); return new Object[] { returnType, paramTypes }; } else { UnresolvedType returnType = UnresolvedType.forSignature(sig.substring(2)); return new Object[] { returnType, UnresolvedType.NONE }; } } // ---- factory methods public static MemberImpl field(String declaring, int mods, String name, String signature) { return field(declaring, mods, UnresolvedType.forSignature(signature), name); } // OPTIMIZE do we need to call this? unless necessary the signatureToTypes() // 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); return method(declaring, mods, (UnresolvedType) pair[0], name, (UnresolvedType[]) pair[1]); } public static MemberImpl monitorEnter() { return new MemberImpl(MONITORENTER, UnresolvedType.OBJECT, Modifier.STATIC, UnresolvedType.VOID, "<lock>", UnresolvedType.ARRAY_WITH_JUST_OBJECT); } public static MemberImpl monitorExit() { return new MemberImpl(MONITOREXIT, UnresolvedType.OBJECT, Modifier.STATIC, UnresolvedType.VOID, "<unlock>", UnresolvedType.ARRAY_WITH_JUST_OBJECT); } public static Member pointcut(UnresolvedType declaring, String name, String signature) { Object[] pair = signatureToTypes(signature); return pointcut(declaring, 0, (UnresolvedType) pair[0], name, (UnresolvedType[]) pair[1]); } private static MemberImpl field(String declaring, int mods, UnresolvedType ty, String name) { return new MemberImpl(FIELD, UnresolvedType.forName(declaring), mods, ty, name, UnresolvedType.NONE); } 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); } private static Member pointcut(UnresolvedType declTy, int mods, UnresolvedType rTy, String name, UnresolvedType[] paramTys) { return new MemberImpl(POINTCUT, declTy, mods, rTy, name, paramTys); } public static ResolvedMemberImpl makeExceptionHandlerSignature(UnresolvedType inType, UnresolvedType catchType) { return new ResolvedMemberImpl(HANDLER, inType, Modifier.STATIC, "<catch>", "(" + catchType.getSignature() + ")V"); } @Override public final boolean equals(Object other) { if (!(other instanceof Member)) { return false; } Member o = (Member) other; return (getKind() == o.getKind() && getName().equals(o.getName()) && getSignature().equals(o.getSignature()) && getDeclaringType() .equals(o.getDeclaringType())); }
Returns:true if this member equals the one supplied in every respect other than the declaring type
/** * @return true if this member equals the one supplied in every respect other than the declaring type */
public final boolean equalsApartFromDeclaringType(Object other) { if (!(other instanceof Member)) { return false; } Member o = (Member) other; return (getKind() == o.getKind() && getName().equals(o.getName()) && getSignature().equals(o.getSignature())); }
Equality is checked based on the underlying signature, so the hash code of a member is based on its kind, name, signature, and declaring type. The algorithm for this was taken from page 38 of effective java.
/** * Equality is checked based on the underlying signature, so the hash code of a member is based on its kind, name, signature, * and declaring type. The algorithm for this was taken from page 38 of effective java. */
private volatile int hashCode = 0; @Override public int hashCode() { if (hashCode == 0) { int result = 17; result = 37 * result + getKind().hashCode(); result = 37 * result + getName().hashCode(); result = 37 * result + getSignature().hashCode(); result = 37 * result + getDeclaringType().hashCode(); hashCode = result; } return hashCode; } public int compareTo(Member other) { Member o = other; int i = getName().compareTo(o.getName()); if (i != 0) { return i; } return getSignature().compareTo(o.getSignature()); } @Override public String toString() { StringBuffer buf = new StringBuffer(); buf.append(returnType.getName()); buf.append(' '); if (declaringType == null) { buf.append("<NULL>"); } else { buf.append(declaringType.getName()); } buf.append('.'); buf.append(name); if (kind != FIELD) { buf.append("("); if (parameterTypes.length != 0) { buf.append(parameterTypes[0]); for (int i = 1, len = parameterTypes.length; i < len; i++) { buf.append(", "); buf.append(parameterTypes[i].getName()); } } buf.append(")"); } return buf.toString(); } public MemberKind getKind() { return kind; } public UnresolvedType getDeclaringType() { return declaringType; } public UnresolvedType getReturnType() { return returnType; } public UnresolvedType getGenericReturnType() { return getReturnType(); } public UnresolvedType[] getGenericParameterTypes() { return getParameterTypes(); } public final UnresolvedType getType() { return returnType; } public String getName() { return name; } public UnresolvedType[] getParameterTypes() { return parameterTypes; } public String getSignature() { return erasedSignature; } public int getArity() { return parameterTypes.length; } public String getParameterSignature() { if (paramSignature == null) { StringBuilder sb = new StringBuilder("("); for (UnresolvedType parameterType : parameterTypes) { sb.append(parameterType.getSignature()); } paramSignature = sb.append(")").toString(); } return paramSignature; } // OPTIMIZE see next line. Why the hell are they in here if we only know it // once resolution has occurred... // ---- things we know only with resolution public int getModifiers(World world) { ResolvedMember resolved = resolve(world); if (resolved == null) { reportDidntFindMember(world); return 0; } return resolved.getModifiers(); } public UnresolvedType[] getExceptions(World world) { ResolvedMember resolved = resolve(world); if (resolved == null) { reportDidntFindMember(world); return UnresolvedType.NONE; } return resolved.getExceptions(); } public final boolean isStatic() { return Modifier.isStatic(modifiers); } public final boolean isInterface() { return Modifier.isInterface(modifiers); } public final boolean isPrivate() { return Modifier.isPrivate(modifiers); } public boolean canBeParameterized() { return false; } public int getModifiers() { return modifiers; } public AnnotationAJ[] getAnnotations() { throw new UnsupportedOperationException("You should resolve this member '" + this + "' and call getAnnotations() on the result..."); } // ---- fields 'n' stuff public Collection<ResolvedType> getDeclaringTypes(World world) { ResolvedType myType = getDeclaringType().resolve(world); Collection<ResolvedType> ret = new HashSet<ResolvedType>(); if (kind == CONSTRUCTOR) { // this is wrong if the member doesn't exist, but that doesn't // matter ret.add(myType); } else if (Modifier.isStatic(modifiers) || kind == FIELD) { walkUpStatic(ret, myType); } else { walkUp(ret, myType); } return ret; } private boolean walkUp(Collection<ResolvedType> acc, ResolvedType curr) { if (acc.contains(curr)) { return true; } boolean b = false; for (Iterator<ResolvedType> i = curr.getDirectSupertypes(); i.hasNext();) { b |= walkUp(acc, i.next()); } if (!b && curr.isParameterizedType()) { b = walkUp(acc, curr.getGenericType()); } if (!b) { b = curr.lookupMemberNoSupers(this) != null; } if (b) { acc.add(curr); } return b; } private boolean walkUpStatic(Collection<ResolvedType> acc, ResolvedType curr) { if (curr.lookupMemberNoSupers(this) != null) { acc.add(curr); return true; } else { boolean b = false; for (Iterator<ResolvedType> i = curr.getDirectSupertypes(); i.hasNext();) { b |= walkUpStatic(acc, i.next()); } if (!b && curr.isParameterizedType()) { b = walkUpStatic(acc, curr.getGenericType()); } if (b) { acc.add(curr); } return b; } } public String[] getParameterNames(World world) { ResolvedMember resolved = resolve(world); if (resolved == null) { reportDidntFindMember(world); return null; } return resolved.getParameterNames(); }
All the signatures that a join point with this member as its signature has.
/** * All the signatures that a join point with this member as its signature has. */
public JoinPointSignatureIterator getJoinPointSignatures(World inAWorld) { if (joinPointSignatures == null) { joinPointSignatures = new JoinPointSignatureIterator(this, inAWorld); } joinPointSignatures.reset(); return joinPointSignatures; }
Raises an [Xlint:cantFindType] message if the declaring type cannot be found or an [Xlint:unresolvableMember] message if the type can be found (bug 149908)
/** * Raises an [Xlint:cantFindType] message if the declaring type cannot be found or an [Xlint:unresolvableMember] message if the * type can be found (bug 149908) */
private void reportDidntFindMember(World world) { if (reportedCantFindDeclaringType || reportedUnresolvableMember) { return; } ResolvedType rType = getDeclaringType().resolve(world); if (rType.isMissing()) { world.getLint().cantFindType.signal(WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE, rType.getName()), null); reportedCantFindDeclaringType = true; } else { world.getLint().unresolvableMember.signal(getName(), null); reportedUnresolvableMember = true; } } public void wipeJoinpointSignatures() { joinPointSignatures = null; } }