I want to generate byte code for a java class only with the public or protected fields, constructors, and methods.
I am trying with the below code, but I don't know is it the correct approach?
Client code:
String sourceFileName = file.getName();
ClassReader reader = new ClassReader(file.getContents());
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
JavaStubClassAdapter adapter = new JavaStubClassAdapter(writer, sourceFileName);
reader.accept(adapter, 0);
byte[] content = writer.toByteArray();
// we can use content to print in .class file
Adapator code:
private class JavaStubClassAdapter extends ClassVisitor {
private final String sourceFileName;
/**
* @param writer
* @param sourceFileName
*/
public JavaStubClassAdapter(ClassWriter writer, String sourceFileName) {
super(Opcodes.ASM7, writer);
this.sourceFileName = sourceFileName;
}
@Override
public void visitSource(String source, String debug) {
super.visitSource(this.sourceFileName, null);
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
if (access == Opcodes.ACC_PUBLIC || access == Opcodes.ACC_PROTECTED) {
return super.visitField(access, name, descriptor, signature, value);
}
return null;
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
String[] exceptions) {
if (access == Opcodes.ACC_PUBLIC || access == Opcodes.ACC_PROTECTED) {
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
return null;
}
}
Bytecode is the instruction set of the Java Virtual Machine (JVM), and all languages that run on the JVM must eventually compile down to bytecode. Bytecode is manipulated for a variety of reasons: Program analysis: find bugs in your application.
ASM is an all purpose Java bytecode manipulation and analysis framework. It can be used to modify existing classes or to dynamically generate classes, directly in binary form.
How do I start using ASM? If you want to use ASM to generate classes from scratch, write a Java source file that is representative of the classes you want to generate, compile it(*), and then run the ASMifier on the compiled class to see the Java source code that generates this class with ASM.
ASM simply stands for ASMifier tool.
Below code work for me
Client code this method has
org.eclipse.core.resources.IFile
ClassReader reader = new ClassReader(file.getContents());
if (!isAccessPermited(reader.getAccess())) {
return new byte[0];
}
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
JavaStubClassAdapter adapter = new JavaStubClassAdapter(writer, sourceFileName);
reader.accept(adapter, 0);
return writer.toByteArray();
Helper methods
private static boolean isAccessPermited(final int access) {
boolean isEnumAcc = (access & Opcodes.ACC_ENUM) == 0 ? false : true;
boolean isPublicAcc = (access & Opcodes.ACC_PUBLIC) == 0 ? false : true;
boolean isProtectedAcc = (access & Opcodes.ACC_PROTECTED) == 0 ? false : true;
if (isPublicAcc || isProtectedAcc || isEnumAcc) {
return true;
}
return false;
}
private static boolean isFinalAccess(final int access) {
return (access & Opcodes.ACC_FINAL) != 0;
}
Adapator code
private static class JavaStubClassAdapter extends ClassVisitor {
private final String sourceFileName;
/**
* @param writer
* ClassVisitor
* @param sourceFileName
* String
*/
public JavaStubClassAdapter(ClassVisitor writer, String sourceFileName) {
super(Opcodes.ASM7, writer);
this.sourceFileName = sourceFileName;
}
@Override
public void visitSource(String source, String debug) {
super.visitSource(this.sourceFileName, null);
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
if (isAccessPermited(access)) {
switch (descriptor) {
case "Ljava/lang/String;": //$NON-NLS-1$
if (isFinalAccess(access)) {
return super.visitField(access, name, descriptor, signature, "");
}
return super.visitField(access, name, descriptor, signature, null);
case "Z": //$NON-NLS-1$
return super.visitField(access, name, descriptor, signature, Boolean.FALSE);
case "C": //$NON-NLS-1$
case "B": //$NON-NLS-1$
case "S": //$NON-NLS-1$
case "I": //$NON-NLS-1$
case "J": //$NON-NLS-1$
case "D": //$NON-NLS-1$
case "F": //$NON-NLS-1$
if (isFinalAccess(access)) {
return super.visitField(access, name, descriptor, signature, Integer.valueOf(0));
}
return super.visitField(access, name, descriptor, signature, null);
case "Ljava/lang/Object": //$NON-NLS-1$
return super.visitField(access, name, descriptor, signature, null);
default:
return super.visitField(access, name, descriptor, signature, null);
}
}
return null;
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
String[] exceptions) {
if (isAccessPermited(access)) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
return new JavaClassEmptyMethodVistor(mv, Type.getReturnType(descriptor));
}
return null;
}
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
if (isAccessPermited(access)) {
super.visitInnerClass(name, outerName, innerName, access);
}
}
}
private static class JavaClassEmptyMethodVistor extends MethodVisitor {
private final MethodVisitor visitor;
private final Type returnType;
public JavaClassEmptyMethodVistor(MethodVisitor methodVisitor, Type type) {
super(Opcodes.ASM7, methodVisitor);
this.visitor = methodVisitor;
this.returnType = type;
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
// Do nothing
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
// Do nothing
}
@Override
public void visitInsn(int opcode) {
if (returnType == Type.INT_TYPE || returnType == Type.FLOAT_TYPE
|| returnType == Type.LONG_TYPE || returnType == Type.DOUBLE_TYPE
|| returnType == Type.CHAR_TYPE || returnType == Type.BYTE_TYPE ) {
visitor.visitIntInsn(Opcodes.BIPUSH, 0);
visitor.visitInsn(Opcodes.IRETURN);
} else if (returnType == Type.BOOLEAN_TYPE) {
visitor.visitInsn(Opcodes.ICONST_0);
visitor.visitInsn(Opcodes.IRETURN);
} else if (returnType == Type.VOID_TYPE) {
visitor.visitInsn(Opcodes.RETURN);
} else {
visitor.visitInsn(Opcodes.ACONST_NULL);
visitor.visitInsn(Opcodes.ARETURN);
}
}
@Override
public void visitIincInsn(int var, int increment) {
// Do nothing
}
@Override
public void visitLineNumber(int line, Label start) {
// Do nothing
}
@Override
public void visitLabel(Label label) {
// Do nothing
}
@Override
public void visitTypeInsn(int opcode, String type) {
// Do nothing
}
@Override
public void visitJumpInsn(int opcode, Label label) {
// Do nothing
}
@Override
public void visitLdcInsn(Object value) {
// Do nothing
}
@Override
public void visitVarInsn(int opcode, int var) {
// Do nothing
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
visitor.visitMaxs(0, 0);
}
@Override
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
// Do nothing
}
@Override
public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
// Do nothing
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
// Do nothing
}
@Override
public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
// Do nothing
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With