All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.retroweaver.RetroWeaver Maven / Gradle / Ivy

Go to download

Retroweaver is a tool, which converts Java 5 (or 6) compliant class files into Java 1.x compliant class files. The jar file retroweaver.jar contains both the class processor (which may be used at compile time) and the runtime classes. Additionally there is the jar file retroweaver-rt.jar (which contains the runtime classes only).

The newest version!
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 false.
	 */
	private boolean stripSignatures;

	/**
	 * Indicates whether the custom retroweaver attributes should be stripped. Default to false.
	 */
	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 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 fileSets = new ArrayList();

		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 weaved = new HashSet();
		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 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(new JarEntry(name));

			// writing data
			int len;
			final byte[] buf = new byte[1024];
			while ((len = dataStream.read(buf)) >= 0) {
				out.write(buf, 0, len);
			}
		}
		out.close();
		jarFile.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)
	};

	private boolean classpathChecked;
	
	private boolean isRuntimeInClassPath() {
		if (!classpathChecked) {
			try {
				Class.forName("net.sourceforge.retroweaver.runtime.java.lang.annotation.AIB");
				classpathChecked = true;
			} catch (ClassNotFoundException e) {
				listener.weavingError("Error: the retroweaver runtime must be in the classpath");
				return false;
			}			
		}
		return true;
	}

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

		if (!isRuntimeInClassPath()) {
			return false;
		}

        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);

            classVisitor = new NameTranslatorClassVisitor(classVisitor, NameTranslator.getHarmonyTranslator());

        	// 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);
        	}

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

            if (COMPACT_CONSTANTS) {
            	Set constants = new TreeSet(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 + " " + newLine
				+ " []";
	}

	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.setListener(new DefaultWeaveListener(false));
			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 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 classLiteralCalls = new HashSet();

    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, with bridge method
                compareTo(Ljava/lang/Object;)I;
            */

            // Workaround disabled so that isSynthethic() and isBridge() can be implemented
            //newAccess = access & ~ACC_SYNTHETIC & ~ACC_BRIDGE;
            newAccess = access;
            
            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;
        }

        String[] newExceptions;
        if (exceptions != null) {
        	newExceptions = new String[exceptions.length];
        	for (int i = 0; i < exceptions.length; i++) {
        		newExceptions[i] = NameTranslator.getGeneralTranslator().getClassMirrorTranslation(exceptions[i]);
        	}
        } else {
        	newExceptions = exceptions;
        }
        MethodVisitor mv = new MethodWeaver(super.visitMethod(newAccess,
                    name,
                    desc,
                    signature,
                    newExceptions));
    	
    	if (!isEnum || !"".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 (!stripAttributes) {
        	RetroWeaverAttribute a = new RetroWeaverAttribute(Weaver.getBuildNumber(), originalClassVersion);        
        	cv.visitAttribute(a);
        }

        cv.visitEnd();
    }

    /**
     * Generate the byte code equivalent to ".class"
     * 
     * @param mv method visitor to use
     * @param cls name of class
     */
    private void generateClassCall(MethodVisitor mv, String cls) {
    	/* 
    	 * generate the code equivalent to ".class"
    	 * 

			new cls[0].getClass().getComponentType()
    	 */

    	mv.visitInsn (ICONST_0);
    	mv.visitTypeInsn (ANEWARRAY, cls);    	
    	mv.visitMethodInsn (INVOKEVIRTUAL, JAVA_LANG_OBJECT, GET_CLASS_METHOD, GET_CLASS_SIGNATURE);
    	mv.visitMethodInsn (INVOKEVIRTUAL, JAVA_LANG_CLASS, GET_COMPONENT_TYPE_METHOD, GET_COMPONENT_TYPE_SIGNATURE);
    }

    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 JAVA_LANG_OBJECT = "java/lang/Object";
    private static final String GET_CLASS_METHOD = "getClass";
    private static final String GET_CLASS_SIGNATURE = "()Ljava/lang/Class;";
    private static final String GET_COMPONENT_TYPE_METHOD = "getComponentType";
    private static final String GET_COMPONENT_TYPE_SIGNATURE = "()Ljava/lang/Class;";

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

	private static final String CLASS_FIELD_DESC = "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";

	private static final String REENTRANTREADWRITELOCK_CLASS = "java/util/concurrent/locks/ReentrantReadWriteLock";
	private static final String REENTRANTREADWRITELOCK_READLOCK_CLASS = "java/util/concurrent/locks/ReentrantReadWriteLock$ReadLock";
	private static final String REENTRANTREADWRITELOCK_WRITELOCK_CLASS = "java/util/concurrent/locks/ReentrantReadWriteLock$WriteLock";
	private static final String READLOCK_METHOD = "readLock";
	private static final String WRITELOCK_METHOD = "writeLock";
	private static final String REENTRANTREADWRITELOCK_READLOCK_SIGNATURE = "()Ljava/util/concurrent/locks/ReentrantReadWriteLock$ReadLock;";
	private static final String REENTRANTREADWRITELOCK_WRITELOCK_SIGNATURE = "()Ljava/util/concurrent/locks/ReentrantReadWriteLock$WriteLock;";
	private static final String REENTRANTREADWRITELOCK_READLOCK_NEW_SIGNATURE = "()Ljava/util/concurrent/locks/Lock;";
	private static final String REENTRANTREADWRITELOCK_WRITELOCK_NEW_SIGNATURE = "()Ljava/util/concurrent/locks/Lock;";

	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;
		} else if (opcode == INVOKEVIRTUAL &&
				owner.equals(REENTRANTREADWRITELOCK_CLASS)) {
			// workaround for ReentrantReadWriteLock readLock() and writeLock() incompatible return types
			if (name.equals(READLOCK_METHOD) && desc.equals(REENTRANTREADWRITELOCK_READLOCK_SIGNATURE)) {
				super.visitMethodInsn(opcode, owner, name, REENTRANTREADWRITELOCK_READLOCK_NEW_SIGNATURE);
				super.visitTypeInsn(CHECKCAST, REENTRANTREADWRITELOCK_READLOCK_CLASS);
				return;
			} else if (name.equals(WRITELOCK_METHOD) && desc.equals(REENTRANTREADWRITELOCK_WRITELOCK_SIGNATURE)) {
				super.visitMethodInsn(opcode, owner, name, REENTRANTREADWRITELOCK_WRITELOCK_NEW_SIGNATURE);
				super.visitTypeInsn(CHECKCAST, REENTRANTREADWRITELOCK_WRITELOCK_CLASS);
				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);
    		mv.visitInsn(DUP);
    		Label nonNullLabel = new Label();
    		mv.visitJumpInsn(IFNONNULL, nonNullLabel);
    		mv.visitInsn(POP);
    		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().getClassMirrorTranslationDescriptor(s);
    		s = NameTranslator.getStringBuilderTranslator().getClassMirrorTranslationDescriptor(s);
    		s = NameTranslator.getHarmonyTranslator().getClassMirrorTranslationDescriptor(s);

    		generateClassCall(mv, s);
    		mv.visitInsn(DUP);
    		mv.visitFieldInsn(PUTSTATIC, className, fieldName, CLASS_FIELD_DESC);
    		mv.visitLabel(nonNullLabel);
    	} 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
		}
	}
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy