Skip to content

Commit

Permalink
Issue: jboss-javassist#445. Add a method that can get the reference c…
Browse files Browse the repository at this point in the history
…lass name, and add the parsing of generics based on the #getRefClasses method.
  • Loading branch information
kite committed Mar 25, 2023
1 parent 700be6f commit b08992a
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 0 deletions.
37 changes: 37 additions & 0 deletions src/main/javassist/CtClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
* <p>This method may return <code>null</code>.
*
* @return a <code>Collection&lt;String&gt;</code> object.
*/
public synchronized Collection<String> 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 <code>true</code> if this object represents an interface.
Expand Down
33 changes: 33 additions & 0 deletions src/main/javassist/bytecode/ClassFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,39 @@ public final void getRefClasses(Map<String,String> classnames) {
}
}

/**
* Internal-use only.
* <code>CtClass.getAllRefClasses()</code> calls this method.
*/
public final void getAllRefClasses(Map<String, String> 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.
Expand Down
49 changes: 49 additions & 0 deletions src/main/javassist/bytecode/Descriptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>map</code>.
*
* @param map a map between replaced and substituted
* JVM class names.
* @see Descriptor#toJvmName(String)
*/
public static String renameIncludeGenerics(String desc, Map<String, String> 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 <code>map</code>.
Expand Down
22 changes: 22 additions & 0 deletions src/test/javassist/JvstTest4.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> refs
= (java.util.Collection<String>)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");
Expand Down
10 changes: 10 additions & 0 deletions src/test/test4/GetAllRef.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package test4;

import java.util.List;

enum GetAllRefEnum { A, B };

@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
Expand Down Expand Up @@ -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<GetAllRefC> foo();
}

0 comments on commit b08992a

Please sign in to comment.