diff --git a/src/main/javassist/CtClass.java b/src/main/javassist/CtClass.java index 8880b1f6..dec20de6 100644 --- a/src/main/javassist/CtClass.java +++ b/src/main/javassist/CtClass.java @@ -550,6 +550,43 @@ public void fix(String name) {} return null; } + /** + * Returns a collection of the names of all the classes + * referenced in this class. + * This reference contains a reference to the generic. + * If you wish to exclude generics,see this method{@link CtClass#getRefClasses()} + * That collection includes the name of this class. + * + *

This method may return null. + * + * @return a Collection<String> object. + */ + public synchronized Collection getAllRefClasses() { + ClassFile cf = getClassFile2(); + if (cf != null) { + ClassMap cm = new ClassMap() { + /** default serialVersionUID */ + private static final long serialVersionUID = 1L; + @Override + public String put(String oldname, String newname) { + return put0(oldname, newname); + } + @Override + public String get(Object jvmClassName) { + String n = toJavaName((String)jvmClassName); + put0(n, n); + return null; + } + + @Override + public void fix(String name) {} + }; + cf.getAllRefClasses(cm); + return cm.values(); + } + return null; + } + /** * Determines whether this object represents a class or an interface. * It returns true if this object represents an interface. diff --git a/src/main/javassist/bytecode/ClassFile.java b/src/main/javassist/bytecode/ClassFile.java index 5e7475a6..96e27ada 100644 --- a/src/main/javassist/bytecode/ClassFile.java +++ b/src/main/javassist/bytecode/ClassFile.java @@ -522,6 +522,39 @@ public final void getRefClasses(Map classnames) { } } + /** + * Internal-use only. + * CtClass.getAllRefClasses() calls this method. + */ + public final void getAllRefClasses(Map classnames) { + constPool.renameClass(classnames); + + AttributeInfo.getRefClasses(attributes, classnames); + for (MethodInfo minfo : methods) { + String genericDesc = getGenericDesc(minfo); + if (genericDesc != null) + Descriptor.renameIncludeGenerics(genericDesc, classnames); + else + Descriptor.rename(minfo.getDescriptor(), classnames); + AttributeInfo.getRefClasses(minfo.getAttributes(), classnames); + } + + for (FieldInfo finfo : fields) { + String desc = finfo.getDescriptor(); + Descriptor.rename(desc, classnames); + AttributeInfo.getRefClasses(finfo.getAttributes(), classnames); + } + } + + /** + * Returns the generic signature + */ + private String getGenericDesc(MethodInfo methodInfo) { + SignatureAttribute sa + = (SignatureAttribute) methodInfo.getAttribute(SignatureAttribute.tag); + return sa == null ? null : sa.getSignature(); + } + /** * Returns the names of the interfaces implemented by the class. * The returned array is read only. diff --git a/src/main/javassist/bytecode/Descriptor.java b/src/main/javassist/bytecode/Descriptor.java index 4e4fd863..a6491148 100644 --- a/src/main/javassist/bytecode/Descriptor.java +++ b/src/main/javassist/bytecode/Descriptor.java @@ -188,6 +188,55 @@ else if (desc.startsWith(oldname, j + 1) return newdesc.toString(); } + /** + * Substitutes class names and generics in the given descriptor string + * according to the given map. + * + * @param map a map between replaced and substituted + * JVM class names. + * @see Descriptor#toJvmName(String) + */ + public static String renameIncludeGenerics(String desc, Map map) { + if (map == null) + return desc; + + StringBuilder newdesc = new StringBuilder(); + int head = 0; + int i = 0; + for (; ; ) { + int j = desc.indexOf('L', i); + if (j < 0) + break; + + int x = desc.indexOf('<', j); + int y = desc.indexOf(';', j); + if (x == y) + break; + int k = x == -1 ? y : 0; + if (k == 0) + k = Math.min(x,y); + + i = k + 1; + String name = desc.substring(j + 1, k); + String name2 = map.get(name); + if (name2 != null) { + newdesc.append(desc.substring(head, j)); + newdesc.append('L'); + newdesc.append(name2); + newdesc.append(';'); + head = i; + } + } + + if (head == 0) + return desc; + int len = desc.length(); + if (head < len) + newdesc.append(desc.substring(head, len)); + + return newdesc.toString(); + } + /** * Substitutes class names in the given descriptor string * according to the given map. diff --git a/src/test/javassist/JvstTest4.java b/src/test/javassist/JvstTest4.java index 259451b9..cbc4ae25 100644 --- a/src/test/javassist/JvstTest4.java +++ b/src/test/javassist/JvstTest4.java @@ -481,6 +481,28 @@ public void testGetAllRefC() throws Exception { } } + public void testGetAllRefD() throws Exception { + CtClass cc = sloader.get("test4.GetAllRefD"); + HashSet set = new HashSet(); + set.add("java.lang.Object"); + set.add("java.lang.String"); + set.add("test4.GetAllRefC"); + set.add("test4.GetAllRefAnno"); + set.add("test4.GetAllRefEnum"); + set.add("test4.GetAllRefAnnoC"); + set.add("test4.GetAllRefAnnoC2"); + set.add("test4.GetAllRefAnnoC3"); + set.add("test4.GetAllRefAnnoC4"); + set.add("java.util.List"); + set.add("test4.GetAllRefD"); + java.util.Collection refs + = (java.util.Collection)cc.getAllRefClasses(); + assertEquals(set.size(), refs.size()); + for (String s: refs) { + assertTrue(set.contains(s)); + } + } + public void testGetAllRefInner() throws Exception { HashSet set = new HashSet(); set.add("java.lang.Object"); diff --git a/src/test/test4/GetAllRef.java b/src/test/test4/GetAllRef.java index c19bfabd..e5244555 100644 --- a/src/test/test4/GetAllRef.java +++ b/src/test/test4/GetAllRef.java @@ -1,5 +1,7 @@ package test4; +import java.util.List; + enum GetAllRefEnum { A, B }; @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @@ -31,3 +33,11 @@ void bar(@GetAllRefAnnoC3 int i, int j, @GetAllRefAnnoC void foo() {} @GetAllRefAnnoC2 int value; } + +@GetAllRefAnno(getA = GetAllRefEnum.A, getC = String.class) +interface GetAllRefD { + void bar(@GetAllRefAnnoC3 int i, int j, + @GetAllRefAnnoC2 @GetAllRefAnnoC4 boolean b); + @GetAllRefAnnoC + List foo(); +}