下面列出了怎么用org.objectweb.asm.tree.InnerClassNode的API类实例代码及写法,或者点击链接到github查看源代码。
public List<Type> getNestedTypes() {
List<Type> result = null;
List<InnerClassNode> innerClasses = node.innerClasses;
for (InnerClassNode inner: innerClasses) {
if (inner.outerName==null || !inner.outerName.equals(getName())) {
// System.out.println("SKIPPPING "+inner.name+" because outer is "+inner.outerName+" and we are looking at "+getName());
continue;
}
if (inner.name.equals(getName())) {
continue;
}
Type t = typeSystem.resolve(inner.name); // aaa/bbb/ccc/Ddd$Eee
if (result == null) {
result = new ArrayList<>();
}
result.add(t);
}
return result==null?Collections.emptyList():result;
}
public List<Type> getNestedTypes() {
if (dimensions > 0)
return Collections.emptyList();
List<Type> result = null;
List<InnerClassNode> innerClasses = node.innerClasses;
for (InnerClassNode inner : innerClasses) {
if (inner.outerName == null || !inner.outerName.equals(getName())) {
// System.out.println("SKIPPING "+inner.name+" because outer is "+inner.outerName+" and we are looking at "+getName());
continue;
}
if (inner.name.equals(getName())) {
continue;
}
Type t = typeSystem.resolve(inner.name); // aaa/bbb/ccc/Ddd$Eee
if (result == null) {
result = new ArrayList<>();
}
result.add(t);
}
return result == null ? Collections.emptyList() : result;
}
private Type[] getMemberTypes() {
if (dimensions > 0)
return new Type[0];
List<Type> result = new ArrayList<>();
List<InnerClassNode> nestMembers = node.innerClasses;
if (nestMembers != null) {
for (InnerClassNode icn : nestMembers) {
if (icn.name.startsWith(this.getName() + "$")) {
result.add(typeSystem.resolveSlashed(icn.name));
}
}
System.out.println(this.getName()
+ " has inners " + nestMembers.stream().map(f -> "oo=" + this.getDescriptor() + "::o=" + f.outerName
+ "::n=" + f.name + "::in=" + f.innerName).collect(Collectors.joining(","))
+ " >> " + result);
}
return result.toArray(new Type[0]);
}
@Nullable
static String getOuterClassName(@NonNull ClassNode classNode) {
if (classNode.outerClass != null) {
return classNode.outerClass;
}
if (classNode.innerClasses != null) {
@SuppressWarnings("unchecked")
List<InnerClassNode> innerClassNodes = (List<InnerClassNode>) classNode.innerClasses;
for (InnerClassNode innerClassNode : innerClassNodes) {
if (innerClassNode.name.equals(classNode.name)) {
return innerClassNode.outerName;
}
}
}
return null;
}
private Map<String, ClassNode> readInnerClasses(ClassNode classNode) {
Map<String, ClassNode> ret = new HashMap<>();
((List<InnerClassNode>) classNode.innerClasses).stream()
.filter(node -> node.name.matches(".*\\$[0-9]+"))
.filter(node -> node.innerName == null && node.outerName == null)
.map(node -> {
ClassNode innerClassNode = new ClassNode(Opcodes.ASM5);
try (InputStream inputStream = this.transformer.getResourceAsStream(node.name.substring(node.name.lastIndexOf('/') + 1) + ".class")) {
ClassReader reader = new ClassReader(inputStream);
reader.accept(innerClassNode, 0);
} catch (IOException e) {
throw new RuntimeException(e);
}
return innerClassNode;
}).forEach(node -> ret.put(node.name, node));
return ret;
}
public ClassNode transform(Type superClassType) {
log.info("Transforming blocking method: " + classNode.name + "." + originalAsyncMethod.name
+ originalAsyncMethod.desc);
//removeAsyncAnnotation(originalAsyncMethod);
// Create InnerClassNode for anoymous class
String asyncTaskClassName = createInnerClassName(classNode);
innerClassesOf(classNode).add(new InnerClassNode(asyncTaskClassName, null, null, (originalAsyncMethod.access & ACC_STATIC)));
// Create accessor methods
createAccessMethodsForAsyncMethod();
// Create ClassNode for anonymous class
ClassNode asyncTaskClassNode = createAnonymousClass(asyncTaskClassName, superClassType);
// Replace original method
List<MethodNode> methods = methodsOf(classNode);
methods.remove(originalAsyncMethod);
createReplacementAsyncMethod(asyncTaskClassName);
//System.out.println(BytecodeTraceUtil.toString(classNode));
return asyncTaskClassNode;
}
/** Apply a standard sort order to attributes. */
private static void sortAttributes(ClassNode n) {
n.innerClasses.sort(
Comparator.comparing((InnerClassNode x) -> x.name)
.thenComparing(x -> x.outerName)
.thenComparing(x -> x.innerName)
.thenComparing(x -> x.access));
sortAnnotations(n.visibleAnnotations);
sortAnnotations(n.invisibleAnnotations);
sortTypeAnnotations(n.visibleTypeAnnotations);
sortTypeAnnotations(n.invisibleTypeAnnotations);
for (MethodNode m : n.methods) {
sortParameterAnnotations(m.visibleParameterAnnotations);
sortParameterAnnotations(m.invisibleParameterAnnotations);
sortAnnotations(m.visibleAnnotations);
sortAnnotations(m.invisibleAnnotations);
sortTypeAnnotations(m.visibleTypeAnnotations);
sortTypeAnnotations(m.invisibleTypeAnnotations);
}
for (FieldNode f : n.fields) {
sortAnnotations(f.visibleAnnotations);
sortAnnotations(f.invisibleAnnotations);
sortAnnotations(f.visibleAnnotations);
sortAnnotations(f.invisibleAnnotations);
sortTypeAnnotations(f.visibleTypeAnnotations);
sortTypeAnnotations(f.invisibleTypeAnnotations);
}
}
/**
* For each preserved InnerClass attribute, keep any information about transitive enclosing
* classes of the inner class.
*/
private static void addInnerChain(
Map<String, InnerClassNode> infos, List<InnerClassNode> used, String i) {
while (infos.containsKey(i)) {
InnerClassNode info = infos.get(i);
used.add(info);
i = info.outerName;
}
}
private static InnerClassNode getInnerClass(ClassNode classNode, String innerClassName) {
for (InnerClassNode icn : innerClassesOf(classNode)) {
if (innerClassName.equals(icn.name)) {
return icn;
}
}
return null;
}
/**
* Read inner class definitions for the class and locate any synthetic
* inner classes so that we can add them to the passthrough set in our
* parent config.
*/
void readInnerClasses() {
for (InnerClassNode inner : this.validationClassNode.innerClasses) {
ClassInfo innerClass = ClassInfo.forName(inner.name);
if ((inner.outerName != null && inner.outerName.equals(this.classInfo.getName()))
|| inner.name.startsWith(this.validationClassNode.name + "$")) {
if (innerClass.isProbablyStatic() && innerClass.isSynthetic()) {
this.syntheticInnerClasses.add(inner.name);
} else {
this.innerClasses.add(inner.name);
}
}
}
}
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
if (name.equals(className) && outerName != null) {
// If this class is an inner class, its outer class is considered referenced automatically
addReferencedClassName(outerName);
}
innerClasses.put(name, new InnerClassNode(name, outerName, innerName, access));
super.visitInnerClass(name, outerName, innerName, access);
}
@Override
public void visitEnd() {
// If we reference inner classes, we must also reference their outer class(es).
Set<String> newSet = new HashSet<>();
for (String referencedClassName : referencedClassNames) {
newSet.add(referencedClassName);
InnerClassNode innerClassNode = innerClasses.get(referencedClassName);
while (innerClassNode != null) {
newSet.add(innerClassNode.name);
innerClassNode = innerClasses.get(innerClassNode.outerName);
}
}
referencedClassNames = newSet;
super.visitEnd();
}
private static boolean isAnonymousOrLocalClass(ClassNode node) {
InnerClassNode innerClass = getInnerClassMetadata(node);
while (innerClass != null) {
if (innerClass.outerName == null) {
return true;
}
innerClass = getInnerClassMetadata(node, innerClass.outerName);
}
return false;
}
@Nullable
private static InnerClassNode getInnerClassMetadata(ClassNode node, String className) {
for (InnerClassNode innerClass : node.innerClasses) {
if (innerClass.name.equals(className)) {
return innerClass;
}
}
return null;
}
@Override
public void visitEnd() {
innerClasses.sort(
(o1, o2) -> {
// Enclosing classes and member classes should come first, with their order preserved
boolean o1IsEnclosingOrMember = isEnclosingOrMember(o1);
boolean o2IsEnclosingOrMember = isEnclosingOrMember(o2);
if (o1IsEnclosingOrMember && o2IsEnclosingOrMember) {
// Preserve order among these
return 0;
} else if (o1IsEnclosingOrMember) {
return -1;
} else if (o2IsEnclosingOrMember) {
return 1;
}
// References to other classes get sorted.
return o1.name.compareTo(o2.name);
});
for (InnerClassNode innerClass : innerClasses) {
innerClass.accept(cv);
}
nestMembers.stream().sorted().forEach(nestMember -> cv.visitNestMember(nestMember));
super.visitEnd();
}
private boolean isEnclosingOrMember(InnerClassNode innerClass) {
if (className.equals(innerClass.name)) {
// Self!
return true;
}
if (className.equals(innerClass.outerName)) {
// Member class
return true;
}
// Enclosing class
return className.startsWith(innerClass.name + "$");
}
private void compareClasses(ClassNode inputNode, ClassNode outputNode) {
// Access is unchanged.
Assert.assertEquals(inputNode.access, outputNode.access);
// Attributes aren't in either.
Assert.assertNull(inputNode.attrs);
Assert.assertNull(outputNode.attrs);
// We expect the same number of fields but we need a deep comparison.
List<FieldNode> inputFields = inputNode.fields;
List<FieldNode> outputFields = outputNode.fields;
Assert.assertEquals(inputFields.size(), outputFields.size());
for (int i = 0; i < inputFields.size(); ++i) {
compareFields(inputFields.get(i), outputFields.get(i));
}
// Inner classes are unchanged.
List<InnerClassNode> inputInnerClasses = inputNode.innerClasses;
List<InnerClassNode> outputInnerClasses = outputNode.innerClasses;
Assert.assertEquals(inputInnerClasses.size(), outputInnerClasses.size());
for (int i = 0; i < inputInnerClasses.size(); ++i) {
// Names received user renaming - but only the classes which are strictly user-defined (not MethodHandles).
String inputName = inputInnerClasses.get(i).name;
String expectedName = mapper.mapType(inputName, this.preserveDebuggability);
Assert.assertEquals(expectedName, outputInnerClasses.get(i).name);
}
// Interfaces are unchanged.
List<String> inputInterfaces = inputNode.interfaces;
List<String> outputInterfaces = outputNode.interfaces;
Assert.assertEquals(inputInterfaces.size(), outputInterfaces.size());
for (int i = 0; i < inputInterfaces.size(); ++i) {
Assert.assertEquals(mapper.mapType(inputInterfaces.get(i), this.preserveDebuggability), outputInterfaces.get(i));
}
// Neither use any invisible annotations.
Assert.assertNull(inputNode.invisibleAnnotations);
Assert.assertNull(outputNode.invisibleAnnotations);
Assert.assertNull(inputNode.invisibleTypeAnnotations);
Assert.assertNull(outputNode.invisibleTypeAnnotations);
// We expect the same number of methods but we need a deep comparison.
List<MethodNode> inputMethods = inputNode.methods;
List<MethodNode> outputMethods = outputNode.methods;
Assert.assertEquals(inputMethods.size(), outputMethods.size());
for (int i = 0; i < inputMethods.size(); ++i) {
compareMethods(inputMethods.get(i), outputMethods.get(i));
}
Assert.assertEquals(inputNode.module, outputNode.module);
// There are now no annotations (some of these had them, before).
Assert.assertNull(outputNode.visibleAnnotations);
Assert.assertNull(outputNode.visibleTypeAnnotations);
Assert.assertEquals(PackageConstants.kUserSlashPrefix + inputNode.name, outputNode.name);
Assert.assertEquals(inputNode.outerClass, outputNode.outerClass);
Assert.assertEquals(inputNode.outerMethod, outputNode.outerMethod);
Assert.assertEquals(inputNode.outerMethodDesc, outputNode.outerMethodDesc);
Assert.assertEquals(inputNode.signature, outputNode.signature);
Assert.assertEquals(inputNode.sourceDebug, outputNode.sourceDebug);
// We expect the sourceFile to be removed.
Assert.assertNull(outputNode.sourceFile);
Assert.assertEquals(mapper.mapType(inputNode.superName, this.preserveDebuggability), outputNode.superName);
}
/**
* Remove InnerClass attributes that are no longer needed after member pruning. This requires
* visiting all descriptors and signatures in the bytecode to find references to inner classes.
*/
private static void removeUnusedInnerClassAttributes(
Map<String, InnerClassNode> infos, ClassNode n) {
Set<String> types = new HashSet<>();
{
types.add(n.name);
collectTypesFromSignature(types, n.signature);
if (n.superName != null) {
types.add(n.superName);
}
types.addAll(n.interfaces);
addTypesInAnnotations(types, n.visibleAnnotations);
addTypesInAnnotations(types, n.invisibleAnnotations);
addTypesInTypeAnnotations(types, n.visibleTypeAnnotations);
addTypesInTypeAnnotations(types, n.invisibleTypeAnnotations);
}
for (MethodNode m : n.methods) {
collectTypesFromSignature(types, m.desc);
collectTypesFromSignature(types, m.signature);
types.addAll(m.exceptions);
addTypesInAnnotations(types, m.visibleAnnotations);
addTypesInAnnotations(types, m.invisibleAnnotations);
addTypesInTypeAnnotations(types, m.visibleTypeAnnotations);
addTypesInTypeAnnotations(types, m.invisibleTypeAnnotations);
addTypesFromParameterAnnotations(types, m.visibleParameterAnnotations);
addTypesFromParameterAnnotations(types, m.invisibleParameterAnnotations);
collectTypesFromAnnotationValue(types, m.annotationDefault);
}
for (FieldNode f : n.fields) {
collectTypesFromSignature(types, f.desc);
collectTypesFromSignature(types, f.signature);
addTypesInAnnotations(types, f.visibleAnnotations);
addTypesInAnnotations(types, f.invisibleAnnotations);
addTypesInTypeAnnotations(types, f.visibleTypeAnnotations);
addTypesInTypeAnnotations(types, f.invisibleTypeAnnotations);
}
List<InnerClassNode> used = new ArrayList<>();
for (InnerClassNode i : n.innerClasses) {
if (i.outerName != null && i.outerName.equals(n.name)) {
// keep InnerClass attributes for any member classes
used.add(i);
} else if (types.contains(i.name)) {
// otherwise, keep InnerClass attributes that were referenced in class or member signatures
addInnerChain(infos, used, i.name);
}
}
addInnerChain(infos, used, n.name);
n.innerClasses = used;
}
protected PrefixedStringBuilder decompile(PrefixedStringBuilder sb, ArrayList<String> decompiledClasses, FileContainer container, ClassNode cn) {
ArrayList<String> unableToDecompile = new ArrayList<>();
decompiledClasses.add(cn.name);
sb.append(getAccessString(cn.access));
sb.append(" ");
sb.append(cn.name);
if (cn.superName != null && !cn.superName.equals("java/lang/Object")) {
sb.append(" extends ");
sb.append(cn.superName);
}
int amountOfInterfaces = cn.interfaces.size();
if (amountOfInterfaces > 0) {
sb.append(" implements ");
sb.append(cn.interfaces.get(0));
if (amountOfInterfaces > 1) {
// sb.append(",");
}
for (int i = 1; i < amountOfInterfaces; i++) {
sb.append(", ");
sb.append(cn.interfaces.get(i));
}
}
sb.append(" {");
sb.append(JDA.nl);
for (Iterator<FieldNode> it = cn.fields.iterator(); it.hasNext(); ) {
sb.append(" ");
getFieldNodeDecompiler(sb, it).decompile();
sb.append(JDA.nl);
if (!it.hasNext())
sb.append(JDA.nl);
}
for (Iterator<MethodNode> it = cn.methods.iterator(); it.hasNext(); ) {
getMethodNodeDecompiler(sb, cn, it).decompile();
if (it.hasNext())
sb.append(JDA.nl);
}
if (settings.getEntry("decompile-inner-classes").getBool())
for (InnerClassNode innerClassNode : cn.innerClasses) {
String innerClassName = innerClassNode.name;
if ((innerClassName != null) && !decompiledClasses.contains(innerClassName)) {
decompiledClasses.add(innerClassName);
ClassNode cn1 = container.loadClassFile(container.findClassfile(innerClassName));
applyFilters(cn1);
if (cn1 != null) {
sb.appendPrefix(" ");
sb.append(JDA.nl + JDA.nl);
sb = decompile(sb, decompiledClasses, container, cn1);
sb.trimPrefix(5);
sb.append(JDA.nl);
} else {
unableToDecompile.add(innerClassName);
}
}
}
if (!unableToDecompile.isEmpty()) {
sb.append("// The following inner classes couldn't be decompiled: ");
for (String s : unableToDecompile) {
sb.append(s);
sb.append(" ");
}
sb.append(JDA.nl);
}
sb.append("}");
// System.out.println("Wrote end for " + cn.name +
// " with prefix length: " + sb.prefix.length());
return sb;
}
@SuppressWarnings("unchecked")
static List<InnerClassNode> innerClassesOf(ClassNode classNode) {
return null == classNode.innerClasses ?
Collections.<InnerClassNode> emptyList() :
(List<InnerClassNode>) classNode.innerClasses;
}
protected static PrefixedStringBuilder decompile(
PrefixedStringBuilder sb, ArrayList<String> decompiledClasses,
ClassNode cn) {
ArrayList<String> unableToDecompile = new ArrayList<>();
decompiledClasses.add(cn.name);
sb.append(getAccessString(cn.access));
sb.append(" ");
sb.append(cn.name);
if (cn.superName != null && !cn.superName.equals("java/lang/Object")) {
sb.append(" extends ");
sb.append(cn.superName);
}
int amountOfInterfaces = cn.interfaces.size();
if (amountOfInterfaces > 0) {
sb.append(" implements ");
sb.append(cn.interfaces.get(0));
for (int i = 1; i < amountOfInterfaces; i++) {
sb.append(", ");
sb.append(cn.interfaces.get(i));
}
}
sb.append(" {");
sb.append(BytecodeViewer.nl);
sb.append(" ");
sb.append("<ClassVersion=" + cn.version + ">");
sb.append(BytecodeViewer.nl);
if (cn.sourceDebug != null) {
sb.append(" ");
sb.append("<SourceDebug=" + cn.sourceDebug + ">");
sb.append(BytecodeViewer.nl);
}
if (cn.sourceFile != null) {
sb.append(" ");
sb.append("<SourceFile=" + cn.sourceFile + ">");
sb.append(BytecodeViewer.nl);
}
if (cn.signature != null) {
sb.append(" ");
sb.append("<Sig=" + cn.signature + ">");
}
for (FieldNode fn : cn.fields) {
sb.append(BytecodeViewer.nl);
sb.append(" ");
FieldNodeDecompiler.decompile(sb, fn);
}
if (cn.fields.size() > 0) {
sb.append(BytecodeViewer.nl);
}
for (MethodNode mn : cn.methods) {
sb.append(BytecodeViewer.nl);
MethodNodeDecompiler.decompile(sb, mn, cn);
}
for (Object o : cn.innerClasses) {
InnerClassNode innerClassNode = (InnerClassNode) o;
String innerClassName = innerClassNode.name;
if ((innerClassName != null)
&& !decompiledClasses.contains(innerClassName)) {
decompiledClasses.add(innerClassName);
ClassNode cn1 = BytecodeViewer.getClassNode(innerClassName);
if (cn1 != null) {
sb.appendPrefix(" ");
sb.append(BytecodeViewer.nl + BytecodeViewer.nl);
sb = decompile(sb, decompiledClasses, cn1);
sb.trimPrefix(5);
sb.append(BytecodeViewer.nl);
} else {
unableToDecompile.add(innerClassName);
}
}
}
if (!unableToDecompile.isEmpty()) {
sb.append("// The following inner classes couldn't be decompiled: ");
for (String s : unableToDecompile) {
sb.append(s);
sb.append(" ");
}
sb.append(BytecodeViewer.nl);
}
if (cn.attrs != null) {
sb.append(BytecodeViewer.nl);
for (Attribute attr : cn.attrs) {
//TODO: finish attributes
sb.append(attr.type + ": ");// + attr.content.toString());
}
}
//sb.append(BytecodeViewer.nl);
sb.append("}");
// System.out.println("Wrote end for " + cn.name +
// " with prefix length: " + sb.prefix.length());
return sb;
}
@Nullable
private static InnerClassNode getInnerClassMetadata(ClassNode node) {
String name = node.name;
return getInnerClassMetadata(node, name);
}
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
innerClasses.add(new InnerClassNode(name, outerName, innerName, access));
}