package pt.ist.fenixframework.atomic; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.IOException; import static java.io.File.separatorChar; import org.objectweb.asm.*; import org.objectweb.asm.tree.*; import static org.objectweb.asm.Opcodes.*; public final class GenerateAtomicInstance { private static final String ATOMIC_INSTANCE = "pt/ist/fenixframework/atomic/AtomicInstance"; private GenerateAtomicInstance() { } public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Syntax: GenerateAtomicInstance <save-path>"); System.exit(-1); } start(new File(args[0])); } public static void start(File buildDir) throws IOException { InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("pt/ist/fenixframework/Atomic.class"); ClassReader cr = new ClassReader(is); ClassNode cNode = new ClassNode(); cr.accept(cNode, 0); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_6, ACC_PUBLIC | ACC_FINAL, ATOMIC_INSTANCE, null, "java/lang/Object", new String[] { "pt/ist/fenixframework/Atomic" }); cw.visitSource("Atomic Instance Class", null); // Generate fields for (MethodNode annotationElems : cNode.methods) { cw.visitField(ACC_PRIVATE | ACC_FINAL, annotationElems.name, getReturnTypeDescriptor(annotationElems), null, null); } // Generate constructor { StringBuffer ctorDescriptor = new StringBuffer("("); for (MethodNode annotationElems : cNode.methods) ctorDescriptor.append(getReturnTypeDescriptor(annotationElems)); ctorDescriptor.append(")V"); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", ctorDescriptor.toString(), null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); int localsPos = 0; for (MethodNode annotationElems : cNode.methods) { Type t = Type.getReturnType(annotationElems.desc); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(t.getOpcode(ILOAD), localsPos+1); mv.visitFieldInsn(PUTFIELD, ATOMIC_INSTANCE, annotationElems.name, t.getDescriptor()); localsPos += t.getSize(); } mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } // Generate getters for (MethodNode annotationElems : cNode.methods) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, annotationElems.name, annotationElems.desc, null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, ATOMIC_INSTANCE, annotationElems.name, getReturnTypeDescriptor(annotationElems)); mv.visitInsn(Type.getReturnType(annotationElems.desc).getOpcode(IRETURN)); mv.visitMaxs(0, 0); mv.visitEnd(); } // Generate annotationType() method { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "annotationType", "()Ljava/lang/Class;", "()Ljava/lang/Class<+Ljava/lang/annotation/Annotation;>;", null); mv.visitCode(); mv.visitLdcInsn(Type.getType(pt.ist.fenixframework.Atomic.class)); mv.visitInsn(ARETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } // Write Class FileOutputStream fos = null; try { File parentDir = new File(buildDir, "pt" + separatorChar + "ist" + separatorChar + "fenixframework" + separatorChar + "atomic" + separatorChar); if (!parentDir.exists() && !parentDir.mkdirs()) { throw new IOException("Could not create required directory: " + parentDir); } File f = new File(parentDir, "AtomicInstance.class"); fos = new FileOutputStream(f); fos.write(cw.toByteArray()); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { } } } } private static String getReturnTypeDescriptor(MethodNode mNode) { return Type.getReturnType(mNode.desc).getDescriptor(); } }