Package net.sourceforge.retroweaver

Source Code of net.sourceforge.retroweaver.DefaultWeaveListener

package net.sourceforge.retroweaver;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;

import net.sourceforge.retroweaver.event.WeaveListener;
import net.sourceforge.retroweaver.optimizer.ClassConstantsCollector;
import net.sourceforge.retroweaver.optimizer.Constant;
import net.sourceforge.retroweaver.optimizer.ConstantComparator;
import net.sourceforge.retroweaver.optimizer.ConstantPool;
import net.sourceforge.retroweaver.translator.NameSpace;
import net.sourceforge.retroweaver.translator.NameTranslator;
import net.sourceforge.retroweaver.translator.NameTranslatorClassVisitor;
import net.sourceforge.retroweaver.translator.TranslatorException;

import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

/**
* A bytecode enhancer that translates Java 1.5 class files into Java 1.4 class
* files. The enhancer performs primarily two tasks: 1) Reverses changes made to
* the class file format in 1.5 to the former 1.4 format. 2) Replaces compiler
* generated calls into the new 1.5 runtime with calls into RetroWeaver's
* replacement runtime.
*/
public class RetroWeaver {

  private final int target;

  private boolean lazy;

  /**
   * Indicates whether the generic signatures should be stripped. Default to <code>false</code>.
   */
  private boolean stripSignatures;

  /**
   * Indicates whether the custom retroweaver attributes should be stripped. Default to <code>false</code>.
   */
  private boolean stripAttributes;

  private int weavedClassCount;

  private WeaveListener listener;

  private RefVerifier verifier;

  private static final String newLine = System.getProperty("line.separator");

  public RetroWeaver(int target) {
    this.target = target;
  }

  protected static final FileFilter classFilter = new FileFilter() {
    public boolean accept(File f) {
      return f.getName().endsWith(".class");
    }
  };

  protected static final FileFilter subdirFilter = new FileFilter() {
    public boolean accept(File f) {
      return f.isDirectory();
    }
  };

  protected static void buildFileSets(ArrayList<File[]> fileSets, File path) {
    File[] files = path.listFiles(classFilter);
    if (files != null) {
      fileSets.add(files);
    }

    File[] subdirs = path.listFiles(subdirFilter);
    if (subdirs != null) {
      for (File subdir : subdirs) {
        buildFileSets(fileSets, subdir);
      }
    }
  }

  private void displayStartMessage(int n) {
    if (n > 0) {
      listener.weavingStarted("Processing " + n + (n == 1?" class":" classes"));
    }
  }

  private void displayEndMessage() {
    if (weavedClassCount > 0) {
      listener.weavingCompleted(Integer.toString(weavedClassCount) + (weavedClassCount == 1?" class":" classes") + " weaved.");
    }
  }

  public void weave(File path) throws IOException {
    ArrayList<File[]> fileSets = new ArrayList<File[]>();

    buildFileSets(fileSets, path);

    int n = 0;
    for (File[] set : fileSets) {
      n += set.length;
    }
    displayStartMessage(n);

    for (int i = 0; i < fileSets.size(); i++) {
      for (File file : fileSets.get(i)) {
        String sourcePath = file.getCanonicalPath();
        weave(sourcePath, null);
      }
    }
    displayEndMessage();

    if (verifier != null) {
      verifier.verifyFiles();
      verifier.displaySummary();
    }
  }

  public void weave(File[] baseDirs, String[][] fileSets, File outputDir)
      throws IOException {
    int n = 0;
    for (String[] set : fileSets) {
      n += set.length;
    }
    displayStartMessage(n);

    Set<String> weaved = new HashSet<String>();
    for (int i = 0; i < fileSets.length; i++) {
      for (String fileName : fileSets[i]) {
        File file = new File(baseDirs[i], fileName);
        String sourcePath = file.getCanonicalPath();
        String outputPath = null;
        if (outputDir != null) {
          outputPath = new File(outputDir, fileName)
              .getCanonicalPath();
        }
        // Weave it unless already weaved.
        if (!weaved.contains(sourcePath)) {
          weave(sourcePath, outputPath);
          weaved.add(sourcePath);
        }
      }
    }
    displayEndMessage();

    if (verifier != null) {
      verifier.verifyFiles();
      verifier.displaySummary();
    }
  }

  public void weaveJarFile(String sourceJarFileName, String destJarFileName)
      throws IOException {
    JarFile jarFile = new JarFile(sourceJarFileName);
    ArrayList<JarEntry> entries = Collections.list(jarFile.entries());

    OutputStream os = new FileOutputStream(destJarFileName);
    JarOutputStream out = new JarOutputStream(os);

    int n = 0;
    for (JarEntry entry : entries) {
      if (entry.getName().endsWith(".class")) {
        n++;
      }
    }
    displayStartMessage(n);

    for (JarEntry entry : entries) {
      String name = entry.getName();
      InputStream dataStream = null;
      if (name.endsWith(".class")) {
        // weave class
        InputStream is = jarFile.getInputStream(entry);
        ByteArrayOutputStream classStream = new ByteArrayOutputStream();
        if (weave(is, name, classStream)) {
          // class file was modified
          weavedClassCount++;

          dataStream = new ByteArrayInputStream(classStream
              .toByteArray());

          // create new entry
          entry = new JarEntry(name);
          recordFileForVerifier(name);
        }
      }

      if (dataStream == null) {
        // not a class file or class wasn't no
        dataStream = jarFile.getInputStream(entry);
      }
      // writing entry
      out.putNextEntry(entry);

      // writing data
      int len;
      final byte[] buf = new byte[1024];
      while ((len = dataStream.read(buf)) >= 0) {
        out.write(buf, 0, len);
      }
    }
    out.close();

    displayEndMessage();

    if (verifier != null) {
      verifier.verifyJarFile(destJarFileName);
      verifier.displaySummary();
    }
  }

  public void weave(String sourcePath, String outputPath) throws IOException {
    InputStream is = new FileInputStream(sourcePath);
    try {
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      if (weave(is, sourcePath, bos)) {
        // new class was generated
        weavedClassCount++;

        String path;

        if (outputPath == null) {
          path = sourcePath;
        } else {
          path = outputPath;
          // create parent dir if necessary
          File parentDir = new File(path).getParentFile();
          if (parentDir != null) {
            parentDir.mkdirs();
          }
        }
        FileOutputStream fos = new FileOutputStream(path);
        fos.write(bos.toByteArray());
        fos.close();
       
        recordFileForVerifier(path);
      } else {
        // We're lazy and the class already has the target version.

        if (outputPath == null) {
          // weaving in place
          return;
        }

        File dir = new File(outputPath).getParentFile();
        if (dir != null) {
          dir.mkdirs();
        }

        File sf = new File(sourcePath);
        File of = new File(outputPath);

        if (!of.isFile()
            || !of.getCanonicalPath().equals(sf.getCanonicalPath())) {
          // Target doesn't exist or is different from source so copy
          // the file and transfer utime.
          FileInputStream fis = new FileInputStream(sf);
          byte[] bytes = new byte[(int) sf.length()];
          fis.read(bytes);
          fis.close();
          FileOutputStream fos = new FileOutputStream(of);
          fos.write(bytes);
          fos.close();
          of.setLastModified(sf.lastModified());
        }
      }
    } finally {
      try {
        is.close();
      } catch (IOException e) { // NOPMD by xlv
      }
    }
  }

  private void recordFileForVerifier(String fileName) {
    if (verifier != null) {
      verifier.addClass(fileName);
    }
  }

  private static final boolean COMPACT_CONSTANTS = true;

  protected static final Attribute[] CUSTOM_ATTRIBUTES = {
    new RetroWeaverAttribute(Weaver.getBuildNumber(), Weaver.VERSION_1_5)
  };

  protected boolean weave(InputStream sourceStream, String fileName, ByteArrayOutputStream bos)
      throws IOException {

        ClassReader cr = new ClassReader(sourceStream);
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

        try {
          // chain class visitors
          ClassVisitor classVisitor = cw;
          ConstantPool cp;
            if (COMPACT_CONSTANTS) {
                cp = new ConstantPool();
                classVisitor = new ClassConstantsCollector(classVisitor, cp);
            }
            classVisitor = new NameTranslatorClassVisitor(classVisitor, NameTranslator.getGeneralTranslator());
          classVisitor = new ClassWeaver(classVisitor,
                        lazy, stripAttributes, target, listener);
         
          // StringBuilder translation will be done before general weaving and
          // mirror translation: trimToSize() calls will be processed correctly
          // and no need to do translations in general weaving process
            classVisitor = new NameTranslatorClassVisitor(classVisitor, NameTranslator.getStringBuilderTranslator());

          if (stripSignatures) {
            classVisitor = new SignatureStripper(classVisitor);
          }

          classVisitor = new AnnotationWeaver(classVisitor);

          cr.accept(classVisitor, CUSTOM_ATTRIBUTES, ClassReader.EXPAND_FRAMES);       

            if (COMPACT_CONSTANTS) {
              Set<Constant> constants = new TreeSet<Constant>(new ConstantComparator());
              constants.addAll(cp.values());

              cr = new ClassReader(cw.toByteArray());
                cw = new ClassWriter(0);
                for(Constant c: constants) {
                  c.write(cw);
                }
                cr.accept(cw, 0);
            }

          bos.write(cw.toByteArray());
          return true;
        } catch (TranslatorException te) {
          listener.weavingError(te.getMessage());
          return false;
        } catch (LazyException e) {
          return false;
        }
   }

  public void setListener(WeaveListener listener) {
    this.listener = listener;
  }

  public void setLazy(boolean lazy) {
    this.lazy = lazy;
  }

  public void setVerifier(RefVerifier verifier) {
    this.verifier = verifier;
  }

  public static String getUsage() {
    return "Usage: RetroWeaver " + newLine + " <source path>" + newLine
        + " [<output path>]";
  }

  public static void main(String[] args) {

    if (args.length < 1) {
      System.out.println(getUsage()); // NOPMD by xlv
      return;
    }

    String sourcePath = args[0];
    String outputPath = null;

    if (args.length > 1) {
      outputPath = args[1];
    }

    try {
      RetroWeaver weaver = new RetroWeaver(Weaver.VERSION_1_4);
      weaver.weave(sourcePath, outputPath);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * @param stripSignatures The stripSignatures to set.
   */
  public void setStripSignatures(boolean stripSignatures) {
    this.stripSignatures = stripSignatures;
  }

  /**
   * @param stripAttributes the stripAttributes to set
   */
  public void setStripAttributes(boolean stripAttributes) {
    this.stripAttributes = stripAttributes;
  }
 
  public void addNameSpaces(List<NameSpace> nameSpaces) {
    NameTranslator translator = NameTranslator.getGeneralTranslator();
    for(NameSpace n: nameSpaces) {
      translator.addNameSpace(n);
    }
  }

}

class LazyException extends RuntimeException {
}

class ClassWeaver extends ClassAdapter implements Opcodes {

    private final boolean lazy;
    private final boolean stripAttributes;
    private final int target;
    private int originalClassVersion;
    private final WeaveListener listener;

    private String className;

    private boolean isEnum;
    private boolean isInterface;

    private final Set<String> classLiteralCalls = new HashSet<String>();

    public ClassWeaver(final ClassVisitor cv, boolean lazy, boolean stripAttributes, int target, WeaveListener listener) {
        super(cv);
        this.lazy = lazy;
        this.stripAttributes = stripAttributes;
        this.target = target;
        this.listener = listener;
    }

    public void visit(
        final int version,
        final int access,
        final String name,
        final String signature,
        final String superName,
        final String[] interfaces)
    {
      if (lazy && (version <= target)) {
          // abort all visitors
        throw new LazyException();
      }

    if (listener != null) {
      listener.weavingPath(name);
    }

    className = name;
        isEnum = superName != null && superName.equals("java/lang/Enum");
        isInterface = (access & ACC_INTERFACE) == ACC_INTERFACE;
        originalClassVersion = version;

        cv.visit(target, // Changes the format of the class file from 1.5 to the target value.
                access,
                name,
                signature,
                superName,
                interfaces);
    }

    public void visitInnerClass(
        final String name,
        final String outerName,
        final String innerName,
        final int access)
    {
        cv.visitInnerClass(name, outerName, innerName, access);
    }

    public FieldVisitor visitField(
        final int access,
        final String name,
        final String desc,
        final String signature,
        final Object value)
    {
        return cv.visitField(access, name, desc, signature, value);
    }

    public MethodVisitor visitMethod(
        final int access,
        final String name,
        final String desc,
        final String signature,
        final String[] exceptions)
    {
        int newAccess;
        if ((access&(ACC_SYNTHETIC|ACC_BRIDGE)) == (ACC_SYNTHETIC|ACC_BRIDGE)) {
            /*
            bridge methods for generic create problems with RMIC code in 1.4.
            It's a known bug with 1.4, see SUN's bug database at:
                http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4811083
                http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5035300

            Problem found when implementing Comparable<E>, with bridge method
                compareTo(Ljava/lang/Object;)I;
            */
            newAccess = access & ~ACC_SYNTHETIC & ~ACC_BRIDGE;
           
            if (name.equals(APPEND_METHOD) &&
                (desc.equals(APPENDABLE_APPEND_SIGNATURE1) ||
                desc.equals(APPENDABLE_APPEND_SIGNATURE2) ||
                desc.equals(APPENDABLE_APPEND_SIGNATURE3))) {
              /* remove bridge methods for Appendable, see Writer test case */
              return null;
            }
        } else {
            newAccess = access;
        }

        MethodVisitor mv = new MethodWeaver(super.visitMethod(newAccess,
                    name,
                    desc,
                    signature,
                    exceptions));
     
      if (!isEnum || !"<clinit>".equals(name)) {
        return mv;
      }

      return new EnumMethodWeaver(mv);
    }

    public void visitAttribute(final Attribute attr) {
      if (attr instanceof RetroWeaverAttribute) {
        // make sure the original version is kept if class file
        // is weaved more than once
        RetroWeaverAttribute ra = (RetroWeaverAttribute) attr;
        originalClassVersion = ra.getOriginalClassVersion();
      } else {
        cv.visitAttribute(attr);
      }
    }

    public void visitEnd() {
        if (isEnum) {
          cv.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL + ACC_SYNTHETIC,
              SERIAL_ID_FIELD,
              SERIAL_ID_SIGNATURE,
              null, new Long(0L));
        }
        if (!classLiteralCalls.isEmpty()) {
        // generate synthetic fields and class$ method
        for(String fieldName: classLiteralCalls) {
          FieldVisitor fv = visitField(ACC_STATIC + ACC_SYNTHETIC + ACC_FINAL
              + (isInterface?ACC_PUBLIC:ACC_PRIVATE),
                fieldName,
                CLASS_FIELD_DESC,
                null, null);
          fv.visitEnd();
        }

        if (!isInterface) {
          // "class$" method
          String exceptionTable[] = { JAVA_LANG_NOCLASSDEFFOUNDERROR };
          MethodVisitor mv = cv.visitMethod(ACC_STATIC+ACC_SYNTHETIC,
                            CLASS_METHOD,
                            CLASS_SIGNATURE,
                            null, exceptionTable);
 
          mv.visitCode();

              mv.visitVarInsn(ALOAD, 0);
              generateClassCall(mv);
              mv.visitInsn(ARETURN);
     
              mv.visitMaxs(0, 0);
              mv.visitEnd();
        }
      }

        if (!stripAttributes) {
          RetroWeaverAttribute a = new RetroWeaverAttribute(Weaver.getBuildNumber(), originalClassVersion);       
          cv.visitAttribute(a);
        }

        cv.visitEnd();
    }

    /**
     * Generate the byte code equivalent to ".class"
     *
     * Note: assumes the class name is already on the stack
     *
     * @param mv method visitor to use
     */
    private void generateClassCall(MethodVisitor mv) {
      /*
       * generate the code equivalent to ".class"
       *

         try {
           c = Class.forName(name);
      } catch (ClassNotFoundException e) {
        NoClassDefFoundError t = new NoClassDefFoundError(e.getMessage());
        try {
          t.initCause(e); // only works with 1.4+
        } catch (NoSuchMethodError nsm) {
        }
        throw t;
      }
       */
      Label start1 = new Label();
      Label end1 = new Label();
      Label handler1 = new Label();
      mv.visitTryCatchBlock(start1, end1, handler1, JAVA_LANG_CLASSNOTFOUNDEXCEPTION);
      Label start2 = new Label();
      Label end2 = new Label();
      Label handler2 = new Label();
      mv.visitTryCatchBlock(start2, end2, handler2, JAVA_LANG_NOSUCHMETHODERROR);

      mv.visitLabel(start1);
      mv.visitMethodInsn(INVOKESTATIC, JAVA_LANG_CLASS, FOR_NAME_METHOD, FOR_NAME_SIGNATURE);
      mv.visitVarInsn(ASTORE, 1);
      mv.visitLabel(end1);
      Label gotoLabel1 = new Label();
      mv.visitJumpInsn(GOTO, gotoLabel1);

      mv.visitLabel(handler1);
      mv.visitVarInsn(ASTORE, 2);
      mv.visitTypeInsn(NEW, JAVA_LANG_NOCLASSDEFFOUNDERROR);
      mv.visitInsn(DUP);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_CLASSNOTFOUNDEXCEPTION, GET_MESSAGE_METHOD, GET_MESSAGE_SIGNATURE);
      mv.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_NOCLASSDEFFOUNDERROR, INIT_METHOD, JAVA_LANG_NOCLASSDEFFOUNDERROR_INIT_SIGNATURE);
      mv.visitVarInsn(ASTORE, 3);

      mv.visitLabel(start2);
      mv.visitVarInsn(ALOAD, 3);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_NOCLASSDEFFOUNDERROR, INIT_CAUSE_METHOD, INIT_CAUSE_SIGNATURE);
      mv.visitInsn(POP);
      mv.visitLabel(end2);
      Label gotoLabel2 = new Label();
      mv.visitJumpInsn(GOTO, gotoLabel2);

      mv.visitLabel(handler2);
      mv.visitVarInsn(ASTORE, 4);

      mv.visitLabel(gotoLabel2);
      mv.visitVarInsn(ALOAD, 3);
      mv.visitInsn(ATHROW);
      mv.visitLabel(gotoLabel1);
      mv.visitVarInsn(ALOAD, 1);
    }

    private class EnumMethodWeaver extends MethodAdapter implements Opcodes {
      public EnumMethodWeaver(final MethodVisitor mv) {
        super(mv);
      }

        public void visitInsn(final int opcode) {
          if (opcode == RETURN) {
              // add call to setEnumValues(Object[] values, Class c)

              String owner = className.replace('.', '/');
              String fullName = 'L' + owner + ';';
              Type t = Type.getType(fullName);

              mv.visitMethodInsn(INVOKESTATIC, owner, "values", "()[" + fullName);
              mv.visitLdcInsn(t);
              mv.visitMethodInsn( INVOKESTATIC, RETROWEAVER_ENUM,
                  "setEnumValues", "([Ljava/lang/Object;Ljava/lang/Class;)V" );
          }
            mv.visitInsn(opcode);
        }

    }

    private static final String JAVA_LANG_CLASS = "java/lang/Class";
    private static final String FOR_NAME_METHOD = "forName";
    private static final String FOR_NAME_SIGNATURE = "(Ljava/lang/String;)Ljava/lang/Class;";

    private static final String SERIAL_ID_FIELD = "serialVersionUID";
    private static final String SERIAL_ID_SIGNATURE = "J";

    private static final String JAVA_LANG_NOCLASSDEFFOUNDERROR = "java/lang/NoClassDefFoundError";
    private static final String INIT_METHOD = "<init>";
    private static final String JAVA_LANG_NOCLASSDEFFOUNDERROR_INIT_SIGNATURE = "(Ljava/lang/String;)V";
    private static final String INIT_CAUSE_METHOD = "initCause";
    private static final String INIT_CAUSE_SIGNATURE = "(Ljava/lang/Throwable;)Ljava/lang/Throwable;";
   
    private static final String JAVA_LANG_CLASSNOTFOUNDEXCEPTION = "java/lang/ClassNotFoundException";
    private static final String GET_MESSAGE_METHOD = "getMessage";   
    private static final String GET_MESSAGE_SIGNATURE = "()Ljava/lang/String;";

    private static final String JAVA_LANG_NOSUCHMETHODERROR = "java/lang/NoSuchMethodError";

  private static final String CLASS_FIELD_DESC = "Ljava/lang/Class;";
  private static final String CLASS_METHOD = "class$";
  private static final String CLASS_SIGNATURE = "(Ljava/lang/String;)Ljava/lang/Class;";

  private static final String ITERABLE_CLASS = "java/lang/Iterable";
  private static final String ITERATOR_METHOD = "iterator";
  private static final String ITERATOR_SIGNATURE = "()Ljava/util/Iterator;";
  private static final String ITERABLE_METHODS_CLASS = "net/sourceforge/retroweaver/runtime/java/lang/Iterable_";
  private static final String ITERABLE_METHODS_ITERATOR_SIGNATURE = "(Ljava/lang/Object;)Ljava/util/Iterator;";

  private static final String APPEND_METHOD = "append";
  private static final String APPENDABLE_APPEND_SIGNATURE1 = "(C)Ljava/lang/Appendable;";
  private static final String APPENDABLE_APPEND_SIGNATURE2 = "(Ljava/lang/CharSequence;II)Ljava/lang/Appendable;";
  private static final String APPENDABLE_APPEND_SIGNATURE3 = "(Ljava/lang/CharSequence;)Ljava/lang/Appendable;";

  private static final String RETROWEAVER_ENUM = "net/sourceforge/retroweaver/runtime/java/lang/Enum";

  class MethodWeaver extends MethodAdapter implements Opcodes {
   
  public MethodWeaver(final MethodVisitor mv) {
    super(mv);
  }

    public void visitMethodInsn(
        final int opcode,
        final String owner,
        final String name,
        final String desc)
    {
      if (opcode == INVOKEINTERFACE &&
            owner.equals(ITERABLE_CLASS) &&
            name.equals(ITERATOR_METHOD) &&
            desc.equals(ITERATOR_SIGNATURE)) {
        super.visitMethodInsn(INVOKESTATIC,
            ITERABLE_METHODS_CLASS,
            ITERATOR_METHOD,
            ITERABLE_METHODS_ITERATOR_SIGNATURE);
        return;
    }

      // not a special case, use default implementation
      super.visitMethodInsn(opcode, owner, name, desc);
  }


    public void visitLdcInsn(final Object cst) {
      if (cst instanceof Type) {
        /**
         * Fix class literals. The 1.5 VM has had its ldc* instructions updated so
         * that it knows how to deal with CONSTANT_Class in addition to the other
         * types. So, we have to search for uses of ldc* that point to a
         * CONSTANT_Class and replace them with synthetic field access the way
         * it was generated in 1.4.
         */

        // LDC or LDC_W with a class as argument

        Type t = (Type) cst;
        String fieldName = getClassLiteralFieldName(t);

        classLiteralCalls.add(fieldName);

        mv.visitFieldInsn(GETSTATIC, className, fieldName, CLASS_FIELD_DESC);
        Label nonNullLabel = new Label();
        mv.visitJumpInsn(IFNONNULL, nonNullLabel);
        String s;
        if (t.getSort() == Type.OBJECT) {
          s = t.getInternalName();
        } else {
          s = t.getDescriptor();
        }
       
        /* convert retroweaver runtime classes:
         *     Enum into net.sourceforge.retroweaver.runtime.Enum_
         *    concurrent classes into their backport equivalent
         *    ...
         */
        s = NameTranslator.getGeneralTranslator().getClassMirrorTranslation(s);
        s = NameTranslator.getStringBuilderTranslator().getClassMirrorTranslation(s);

        mv.visitLdcInsn(s.replace('/', '.'));
        if (isInterface) {
          /* synthethic methods cannot be generated in interfaces so the byte
           * code has to be inlined for each call to ".class"
           */
          generateClassCall(mv);
        } else {
          mv.visitMethodInsn(INVOKESTATIC, className, CLASS_METHOD, CLASS_SIGNATURE);
        }
        mv.visitInsn(DUP);
        mv.visitFieldInsn(PUTSTATIC, className, fieldName, CLASS_FIELD_DESC);
        Label endLabel = new Label();
        mv.visitJumpInsn(GOTO, endLabel);
        mv.visitLabel(nonNullLabel);
        mv.visitFieldInsn(GETSTATIC, className, fieldName, CLASS_FIELD_DESC);
        mv.visitLabel(endLabel);

      } else {
        super.visitLdcInsn(cst);
      }
    }

    private String getClassLiteralFieldName(Type type) {
      String fieldName;
      if (type.getSort() == Type.ARRAY) {
        fieldName = "array" + type.getDescriptor().replace('[', '$');
        if (fieldName.charAt(fieldName.length()-1) == ';') {
          fieldName = fieldName.substring(0, fieldName.length()-1);
        }
      } else {
        fieldName = "class$" + type.getInternalName();
      }
      fieldName = fieldName.replace('/', '$');

      return fieldName;
    }

}

}

class DefaultWeaveListener implements WeaveListener {

  private final boolean verbose;

  DefaultWeaveListener(boolean verbose) {
    this.verbose = verbose;
  }

  public void weavingStarted(String msg) {
    System.out.println("[RetroWeaver] " + msg); // NOPMD by xlv
  }

  public void weavingCompleted(String msg) {
    System.out.println("[RetroWeaver] " + msg); // NOPMD by xlv
  }

  public void weavingError(String msg) {
    System.out.println("[RetroWeaver] " + msg); // NOPMD by xlv
  }

  public void weavingPath(String sourcePath) {
    if (verbose) {
      System.out.println("[RetroWeaver] Weaving " + sourcePath); // NOPMD by xlv
    }
  }
}
TOP

Related Classes of net.sourceforge.retroweaver.DefaultWeaveListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
amples of org.objectweb.asm.Type">org.objectweb.asm.Type
  • java.util.LinkedList
  • java.util.ListIterator
  • java.util.Iterator
  • java.util.LinkedHashMap
  • TOP
    Copyright © 2018 www.massapi.com. All rights reserved.
    All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.