title: how to generate subclass by asm
body: <p>I searched on Google how to generate subclass by asm, there seem to be few people who are concerned about this issue. Is this demand itself not suitable? Perhaps the most common thing that asm does is to add extra code before and after the method by <code>AdviceAdapter</code>.
  I think that generating a subclass is also a very common requirement.In fact, it is not easy to do this. How to make all public or protected methods automatically override the parent class's methods, just like <code>HttpServletRequest</code>' subclass <code>HttpServletRequestWrapper</code> did.</p>
  
  <p>I use <code>org.ow2.asm:asm:6.2</code> to implement it as follow：</p>
  
  <pre><code>public class InheritMethodVisitor extends ClassVisitor {
  
  /** the return opcode for different type */
  public static final Map&lt;Type, Integer&gt; RETURN_OPCODES = new HashMap&lt;&gt;();
  /** the load opcode for different type */
  public static final Map&lt;Type, Integer&gt; LOAD_OPCODES = new HashMap&lt;&gt;();
  
  static {
      RETURN_OPCODES.put(Type.VOID_TYPE, Opcodes.RETURN);
      RETURN_OPCODES.put(Type.BOOLEAN_TYPE, Opcodes.IRETURN);
      RETURN_OPCODES.put(Type.BYTE_TYPE, Opcodes.IRETURN);
      RETURN_OPCODES.put(Type.SHORT_TYPE, Opcodes.IRETURN);
      RETURN_OPCODES.put(Type.INT_TYPE, Opcodes.IRETURN);
      RETURN_OPCODES.put(Type.LONG_TYPE, Opcodes.LRETURN);
      RETURN_OPCODES.put(Type.FLOAT_TYPE, Opcodes.FRETURN);
      RETURN_OPCODES.put(Type.DOUBLE_TYPE, Opcodes.DRETURN);
  
      LOAD_OPCODES.put(Type.BOOLEAN_TYPE, Opcodes.ILOAD);
      LOAD_OPCODES.put(Type.BYTE_TYPE, Opcodes.ILOAD);
      LOAD_OPCODES.put(Type.SHORT_TYPE, Opcodes.ILOAD);
      LOAD_OPCODES.put(Type.INT_TYPE, Opcodes.ILOAD);
      LOAD_OPCODES.put(Type.LONG_TYPE, Opcodes.LLOAD);
      LOAD_OPCODES.put(Type.FLOAT_TYPE, Opcodes.FLOAD);
      LOAD_OPCODES.put(Type.DOUBLE_TYPE, Opcodes.DLOAD);
  }
  
  
  private Class&lt;?&gt; superClass;
  private ClassVisitor cv;
  
  public InheritMethodVisitor(int api, ClassVisitor classVisitor, Class&lt;?&gt; superClass) {
      super(api);
      this.cv = classVisitor;
      this.superClass = Objects.requireNonNull(superClass);
  }
  
  @Override
  public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
      //Inherit all public or protect methods
      if (Modifier.isStatic(access) || Modifier.isPrivate(access)) return null;
      if (name.equals("&lt;init&gt;") || Modifier.isProtected(access)) access = Opcodes.ACC_PUBLIC;
  
      MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
  
      Type methodType = Type.getMethodType(descriptor);
      Type[] argumentTypes = methodType.getArgumentTypes();
  
      if (!name.equals("&lt;init&gt;")) {
          //TODO Customize what you want to do
          //System.out.println(name)
          mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(System.class), "out", "Ljava/io/PrintStream;");
          mv.visitLdcInsn(name);
          mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(PrintStream.class), "println", "(Ljava/lang/String;)V", false);
      }
  
      //load this
      mv.visitVarInsn(Opcodes.ALOAD, 0);
      //load arguments
      IntStream.range(0, argumentTypes.length).forEach(value -&gt;
              mv.visitVarInsn(LOAD_OPCODES.getOrDefault(argumentTypes[value], Opcodes.ALOAD), value + 1)
      );
  
      //invoke super.{method}()
      mv.visitMethodInsn(
              Opcodes.INVOKESPECIAL,
              Type.getInternalName(superClass),
              name,
              descriptor,
              false);
  
      //handle return
      mv.visitInsn(RETURN_OPCODES.getOrDefault(methodType.getReturnType(), Opcodes.ALOAD));
      //for ClassWriter.COMPUTE_FRAMES the max*s not required correct
      int maxLocals = argumentTypes.length + 1;
      mv.visitMaxs(maxLocals + 2, maxLocals);
      mv.visitEnd();
      return null;
  }}
  
      @Test
  public void create() throws Exception {
      //generate a subclass of AdviceAdapter to add logger info
      ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
      //generate class name
      cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "com/github/Generated",
              null, Type.getInternalName(AdviceAdapter.class), null);
      //generate overwrite methods
      new ClassReader(AdviceAdapter.class.getName())
              .accept(
                      new InheritMethodVisitor(Opcodes.ASM6, cw, AdviceAdapter.class),
                      ClassReader.EXPAND_FRAMES
              );
      //TODO AdviceAdapter.class.getSuperclass() not supported
      //end
      cw.visitEnd();
      //save to file
      byte[] bytes = cw.toByteArray();
      Files.write(Paths.get(getClass().getResource("/com/github").getPath(), "Generated.class"), bytes);
      //show use of it
      ClassReader classReader = new ClassReader(AdviceAdapter.class.getName());
      classReader.accept(
              new ClassVisitor(Opcodes.ASM6, new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES)) {
                  public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
                      MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
                      try {
                          Class&lt;?&gt; aClass = Class.forName("com.github.Generated");
                          return (MethodVisitor) aClass.getConstructors()[0].newInstance(Opcodes.ASM6, methodVisitor, access, name, descriptor);
                      } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
                          throw new IllegalStateException(e);
                      }
                  }
              },
              ClassReader.EXPAND_FRAMES
      );
  }
  </code></pre>
  
  <p>It works, but it's not very easy. In fact, I think <code>TraceClassVisitor</code> works easy.</p>