SlideShare uma empresa Scribd logo
1 de 99
I Know Kung Fu – Writing Java
         Bytecode



Alexander Shopov <ash@kambanaria.org>
[ash@edge ~]$ whoami
 By day: Software Engineer at Cisco
 By night: OSS contributor
 Coordinator of Bulgarian Gnome TP

 Contacts:
 E-mail:     ash@kambanaria.org
 Jabber:     al_shopov@jabber.minus273.org
 LinkedIn: http://www.linkedin.com/in/alshopov
 Web:        Just search “al_shopov”
Please Learn And Share




License: CC-BY v3.0Creative Common
Disclaimer




My opinions, knowledge and experience!
          Not my employer's.
Plan
●   What is bytecode and how to juggle it
●   Why do it, why not do it
●   How to do it
    –   Class file structure
    –   Manipulation with ASM
●   How to consume your own dog food
    –   Classloaders
    –   Proxies
    –   Agents
What it is
●   Bytecodes are the assembler of JVM. By writing new
    bytecode sequences or changing existing ones we can
    program the JVM directly – outside of the domain of the
    Java Programming Language;
●   Lower level than writing Java - JVM assembler;
●   Much easier than writing a whole (optimizing) compiler;
●   Harder than using a compiler;
●   Similar to the Jedi Dark Side – pathway to many abilities
    some consider to be unnatural.
Why do it?
●   Makes impossible things possible &
●   Makes hard things attainable &
●   Makes long tasks shorter &
●   Makes slow things faster &
●   Makes repetition go away &
●   Makes your head blow away!!!
Common use cases
●   Program analysis – find bugs, unused code
    paths, reverse engineering, metrics, etc.
●   Program generation – compilers, stub/skeleton
    compilers, fast layers without reflection.
●   Transformation – optimize,
    deoptimize/obfuscate, aspect weaving,
    performance monitoring.
Why not do it?
●   Source stops being close to executable &
●   Executable stops being close to any source &
●   There can be better or easier ways of doing things &
●   Fewer people knowing what happens means no one
    can help you &
●   Problems will be your fault! Unit test ∀ ! &
●   You take the red pill and find out the rabbit hole goes
    deep, deep, deep… EOT
Common misuse cases
●   I write it, you maintain it.
●   Do it because it is cool or others are doing it.
●   Over engineering / over generalization.
●   Solution in a search of a problem.
●   Preferring NIH to a popular solution.
Bytecode crash course in 1-2-3

   F4




                                    Thread D
                         Thread C
              Thread B
   F3                               F3
   Thread A


   F2         F2                    F2

   F1         F1         F1         F1

   F0         F0         F0         F0
Bytecode crash course in 1-2-3
                     JVM (heap)
 0     1     2 3   4   5   6 …           Class
                                 PC
               Local variables        Method code


               F0




                                          Class
                                         Pool of
                                        constants

     Stack
Bytecode crash course in 1-2-3
●   Bytecodes retrieve things from class bytestream,
    constant pool, local variables array
●   Perform computations only on stack
●   Store temporary results in local variables array
●   Enter frame by method call
●   Return from frame with a possible result (top
    thing on stack), throw top of stack
●   JVM can also throw and unroll frames
If you need more information
●   Check my other presentation:
Lifting the Veil – Reading Java Bytecode
How to do it
●   Many ways with different pluses and minuses
●   Easiest way to write byte code – use the Java
    compiler.
    –   javac – you all know that
    –   java compiler api – since 1.6
●   But more of that – wait for the end
●   Until then…
Soot
                jDec                 CGlib
 JCF Editor               cojen
               Jiapi
                   Retroweaver
JavaAssist                            BCEL
               Tea Trove
                                jReloader
   jclasslib
                                            Roo
                       Serp
      AspectJ
                                gnu.bytecode
Soot
                jDec                                CGlib
 JCF Editor                    cojen
               Jiapi One of the older frameworks,
                      Retroweaver
JavaAssist                                          BCEL
               Tea Trove
                                       jReloader
   jclasslib
                                                       Roo
                       Serp
      AspectJ
                                        gnu.bytecode
Bytecode manipulation
●   Not constrained by Java
●   Not constrained by compiler
●   Not constrained by source availability
●   Still constrained by JVM
●   Generate or change bytecode to the limits of
    JVM
Classfile Structure, 0xcafebabe
Modifiers, name, super class, interfaces
Constant pool: numeric, string and type constants
Source file name (optional)
Enclosing class reference
Annotation*
Attribute*
Inner class*     Name
Field*           Modifiers, name, type
                 Annotation*
                 Attribute*
Method*          Modifiers, name, return and parameter types
                 Annotation*
                 Attribute*
                 Compiled code
What is ASM
●   Extremely well designed bytecode
    manipulation library
●   Modular, small and fast – pick all
●   Events based – visitor (+SAX), additionally
    has tree API (DOM like)
●   Provides a small bytecode generation variant
●   Minimal – just transformation, can stack
    transformations, no classloading
Timeline
●   1.5 – 30 Aug 2004 – up to JDK 1.6 incl.
●   2.0 – 17 May 2005
●   3.0 – 01 Nov 2006
●   4.0 – 29 Oct 2011 – framework for
    compatibility
Who uses ASM?
●   Languages and AOP tools: AspectJ,
    BeanShell, CGLIB, Clojure, Groovy, Jruby,
    Jython, Coroutines
●   Tools and frameworks: Fractal, Terracotta,
    Javeleon, JRebel
●   Persistence: OpenEJB, Oracle BerkleyDB,
    EclipseLink
●   Monitoring: WebLogic, JiP
●   Testing and code analysis: Cobertura, Eclipse
Most JDKs Use It!
●   Oracle
    –   Sun – HotSpot – JDK, OpenJDK
    –   BEA/Appeal VM – JRockit
●   IBM – J9
●   Azul – Zing
    –   $JAVA_HOME/jre/lib/rt.jar
    –   com.sun.xml.internal.ws.org.objectweb.asm
    –   com.sun.xml.internal.ws.model.WrapperBeanGenerator ⇒
        RuntimeModeler ⇒ Web Services implementation
Read and explore




 Class       Class
Reader       Visitor
Read, transform, write




  Class   Class     Class     Class
 Reader   Visitor   Visitor   Writer
I know what I am doing




 Class   Class       Class     Class     Class     Class     Class     Class
Reader   Visitor     Visitor   Visitor   Visitor   Visitor   Visitor   Writer
I believe I can fly, I believe I can
                  touch the sky…
 Class     Class     Class     Class                         Class     Class
Reader     Visitor   Visitor   Visitor                       Visitor   Writer



                     Class     Class               Class     Class     Class
                     Visitor   Visitor             Visitor   Visitor   Writer



 Class     Class               Class     Class               Class     Class
Reader     Visitor             Visitor   Visitor             Visitor   Writer



           Class               Class     Class                         Class
           Visitor             Visitor   Visitor                       Writer



 Class     Class     Class               Class               Class
Reader     Visitor   Visitor             Visitor             Visitor
Basic Pattern Of Transformation
●   Read bytestream of a class
●   Generate events from that
●   Make changes to the events
●   Receive the events and serialize to
    bytestream
●   Lather, rinse, repeat
Basic diagram of class visiting
User                         ClassVisitor

             visit
         visitSource
                                            ●   Order is important
       visitOuterClass
       visitAnnotation
                                            ●   Bold return other
                         *
        visitAttribute                          visitors
       visitInnerClass
          visitFiled
                         *                  ●   * marks repeat
        vistiMethod
          visitEnd
Basic diagram of annotation visiting
 User                     AnnotationVisitor

             visit         *
           visitEnum
                                              ●   Order is important
        visitAnnotation
          visitArray
                                              ●   Bold return other
           visitEnd                               visitors
                                              ●   * marks repeat
Basic diagram of field visiting
User                         FieldVisitor

       visitAnnotation   *
        visitAttribute
                                            ●   Order is important
          visitEnd
                                            ●   Bold return other
                                                visitors
                                            ●   * marks repeat
Basic diagram of method visiting
User                               MethodVisitor

       visitAnnotationDefault
          visitAnnotation *
                                                   ●   Order is important
   visitParameterAnnotation
            visitAttribute
                                                   ●   Bold return other
              visitCode                                visitors
             visitFrame
              visitXInsn
                               *                   ●   * marks repeat
              visitLabel
         visitTryCatchBlock
          visitLocalVariable
          visitLineNumber
              visitMaxs
              visitEnd
Our humble beginning


package org.kambanaria.writebytecode.asm;
public class Zombunny { //Зомбайо

    public Integer getVersion() {
        return Integer.valueOf(1);
    }

}
Our building blocks
public class StupidClassLoader extends ClassLoader {

    private Map<String, byte[]> bytes = new HashMap<String, byte[]>();

    public StupidClassLoader() {
        super(StupidClassLoader.class.getClassLoader());
    }

    public void provide(String className, byte[] classBytes) {
        bytes.put(className, classBytes);
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        byte[] classBytes = bytes.get(name);
        Class<?> loaded;
        if (classBytes != null) {
            loaded = defineClass(name, classBytes, 0, classBytes.length);
        } else {
            ClassLoader parent = getParent();
            if (null == parent) {
                parent = ClassLoader.getSystemClassLoader();
            }
            loaded = parent.loadClass(name);
        }
        return loaded;
    }
}
Our building blocks
public final class Utilities {
    private Utilities() { }
    public static final String CLASS_NAME = "org.kambanaria.writebytecode.asm.Zombunny";
    public static final String METHOD_NAME = "getVersion";
        public static String toClassPathResourceName(String clazz) {
        return clazz.replace('.', '/') + ".class";
    }
    public static byte[] retrieveBytesFromClassPath(String className) throws IOException {
        String path = toClassPathResourceName(className);
        InputStream is = Utilities.class.getClassLoader().getResourceAsStream(path);
        InputStream classBytes = new BufferedInputStream(is);
        return is2bytes(classBytes);
    }
    public static byte[] patch(byte[] bytes, DemoClassAdapter adapter) {
        ClassReader cr = new ClassReader(bytes);
        cr.accept(adapter, ClassReader.SKIP_FRAMES);
        return adapter.getCw().toByteArray();
    }
    public static byte[] is2bytes(InputStream is) throws IOException {
        int max = 1024 * 1024;
        byte[] bytes = new byte[max]; // 1MB
        int read = is.read(bytes); // Don't do that
        byte[] result = new byte[read];
        System.arraycopy(bytes, 0, result, 0, result.length);
        return result;
    }
    public static Object call0ArgsMethodOn(Object o, String methodName) //
            throws ReflectiveOperationException {
        Class<?> c = o.getClass();
        Method m = c.getDeclaredMethod(methodName, (Class<?>[]) null);
        m.setAccessible(true);
        return m.invoke(o, (Object[]) null);
    }
}
Our building blocks

public class DemoClassAdapter extends ClassVisitor {

    public DemoClassAdapter(ClassVisitor cv) {
        super(Opcodes.ASM4, cv);
    }

    public ClassWriter getCw() {
        return (ClassWriter) cv;
    }
}
Rename class


public class Rename extends DemoClassAdapter {

    private String suffix;

    public Rename(ClassVisitor cv, String suffix) {
        super(cv);
        this.suffix = suffix;
    }

    @Override
    public void visit(int version, int access, String name, //
            String signature, String superName, String[] interfaces) {
        cv.visit(version, access, name + suffix, signature, superName, interfaces);
    }
}
Result is as if


package org.kambanaria.writebytecode.asm;
public class ZombunnySUFFIX { //Зомбайо

    public Integer getVersion() {
        return Integer.valueOf(1);
    }

}
Add field


public class AddField extends DemoClassAdapter {
    public AddField(ClassVisitor cv) {
        super(cv);
    }
   @Override
    public void visitEnd() {
        cv.visitField(ACC_PRIVATE, "_version", //
                Type.getDescriptor(Integer.class), null, null);
        cv.visitEnd();
    }
}
Add field



public class Zombunny { //Зомбайо

    private Integer _version;

    public Integer getVersion() {
        return Integer.valueOf(1);
    }

}
Change method
public class ChangeMethod extends DemoClassAdapter {
    public ChangeMethod(ClassVisitor cv) {
        super(cv);
    }
    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, //
            String signature, String[] exceptions) {
        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
        if (Utilities.METHOD_NAME.equals(name) && "()Ljava/lang/Integer;".equals(desc)) {
            return new DemoMethodVisitor(Opcodes.ASM4, mv);
        } else {
            return mv;
        }
    }
    class DemoMethodVisitor extends MethodVisitor {

        public DemoMethodVisitor(int version, MethodVisitor mv) {
            super(version, mv);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, "org/kambanaria/writebytecode/asm/Zombunny", //
                    "_version", "Ljava/lang/Integer;");
            mv.visitInsn(ARETURN);
            mv.visitEnd();
        }
    }
}
And change method



public class Zombunny { //Зомбайо

    private Integer _version;

    public Integer getVersion() {
        return _version;
    }

}
Fix constructors
public class ManipulateConstructors extends DemoClassAdapter {
    public ManipulateConstructors(ClassVisitor cv) {
        super(cv);
    }
    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, //
            String signature, String[] exceptions) {
        if ("<init>".equals(name)) {
            MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitTypeInsn(NEW, "java/lang/Integer");
            mv.visitInsn(DUP);
            mv.visitInsn(ICONST_2);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer", "<init>", "(I)V");
            mv.visitFieldInsn(PUTFIELD, "org/kambanaria/writebytecode/asm/Zombunny", //
                     "_version", "Ljava/lang/Integer;");
            mv.visitInsn(RETURN);
            mv.visitMaxs(4, 1);
            mv.visitEnd();
            return mv;
        } else {
            return cv.visitMethod(access, name, desc, signature, exceptions);
        }
    }
    @Override
    public void visitEnd() {
        MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/Integer;)V", //
                 null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitFieldInsn(PUTFIELD, "org/kambanaria/writebytecode/asm/Zombunny", //
                 "_version", "Ljava/lang/Integer;");
        mv.visitInsn(RETURN);
        mv.visitMaxs(2, 2);
        mv.visitEnd();
        cv.visitEnd();
    }
}
And fix constructors


public class Zombunny { //Зомбайо

    private Integer _version;

    public Zombunny() {
        _version = new Integer(2);
    }

    public Zombunny(Integer version) {
        _version = version;
    }

    public Integer getVersion() {
        return _version;
    }
}
Add interface

public class AddInterface extends DemoClassAdapter {

    private static final String COMPARABLE = "java/lang/Comparable";

    public AddInterface(ClassVisitor cv) {
        super(cv);
    }

    @Override
    public void visit(int version, int access, String name, String signature,//
            String superName, String[] interfaces) {
        if (Arrays.asList(interfaces).contains(COMPARABLE)) {
            super.visit(version, access, name, signature, superName, interfaces);
        } else {
            int l = interfaces.length;
            String[] newInterfaces = new String[l + 1];
            System.arraycopy(interfaces, 0, newInterfaces, 0, l);
            newInterfaces[l] = COMPARABLE;
            super.visit(version, access, name, signature, superName, newInterfaces);
        }
    }
}
And add interface


public class Zombunny implements Comparable { //Зомбайо

    private Integer _version;

    public Zombunny() {
        _version = new Integer(2);
    }

    public Zombunny(Integer version) {
        _version = version;
    }

    public Integer getVersion() {
        return _version;
    }
}
Add interface implementation
public class AddMethod extends DemoClassAdapter {
    public AddMethod(ClassVisitor cv) {super(cv);}
    @Override
    public void visitEnd() {
        MethodVisitor compareToObject = cv.visitMethod(ACC_PUBLIC, "compareTo", //
                "(Ljava/lang/Object;)I", null, null);
        compareToObject.visitCode();
        compareToObject.visitVarInsn(ALOAD, 1);
        compareToObject.visitTypeInsn(INSTANCEOF, "org/kambanaria/writebytecode/asm/Zombunny");
        Label lbl0 = new Label();
        compareToObject.visitJumpInsn(IFNE, lbl0);
        compareToObject.visitTypeInsn(NEW, "java/lang/ClassCastException");
        compareToObject.visitInsn(DUP);
        compareToObject.visitMethodInsn(INVOKESPECIAL, "java/lang/ClassCastException", //
                "<init>", "()V");
        compareToObject.visitInsn(ATHROW);
        compareToObject.visitLabel(lbl0);
        compareToObject.visitVarInsn(ALOAD, 0);
        compareToObject.visitVarInsn(ALOAD, 1);
        compareToObject.visitTypeInsn(CHECKCAST, "org/kambanaria/writebytecode/asm/Zombunny");
        compareToObject.visitMethodInsn(INVOKEVIRTUAL, "org/kambanaria/writebytecode/asm/Zombunny", //
                "compareTo", "(Lorg/kambanaria/writebytecode/asm/Zombunny;)I");
        compareToObject.visitInsn(IRETURN);
        compareToObject.visitMaxs(2, 2);
        compareToObject.visitEnd();
        MethodVisitor compareToZombunny = cv.visitMethod(ACC_PUBLIC, "compareTo", //
                "(Lorg/kambanaria/writebytecode/asm/Zombunny;)I", null, null);
        compareToZombunny.visitCode();
        compareToZombunny.visitVarInsn(ALOAD, 0);
        compareToZombunny.visitFieldInsn(GETFIELD, "org/kambanaria/writebytecode/asm/Zombunny", //
                "_version", "Ljava/lang/Integer;");
        compareToZombunny.visitVarInsn(ALOAD, 1);
        compareToZombunny.visitFieldInsn(GETFIELD, "org/kambanaria/writebytecode/asm/Zombunny", //
                "_version", "Ljava/lang/Integer;");
        compareToZombunny.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", //
                "(Ljava/lang/Integer;)I");
        compareToZombunny.visitInsn(IRETURN);
        compareToZombunny.visitMaxs(2, 2);
        compareToZombunny.visitEnd();
        cv.visitEnd();
    }
}
And add interface

public class Zombunny implements Comparable { //Зомбайо

    private Integer _version;

    public Zombunny() {
        _version = new Integer(2);
    }

    public Zombunny(Integer version) {
        _version = version;
    }

    public Integer getVersion() {
        return _version;
    }

    public int compareTo(Object o) {
        if (o instanceof Zombunny) {
            return compareTo((Zombunny) o);
        } else {
            throw new ClassCastException();
        }
    }

    public int compareTo(Zombunny o) {
        return _version.compareTo(o._version);
    }
}
The class we get method from



package org.kambanaria.writebytecode.asm;

public class Version {

    private Integer _version;

    public Version(Integer version) {
        _version = version;
    }

    public Integer getVersion() {
        return _version;
    }

    @Override
    public String toString() {
        return "Version: " + _version;
    }
}
Chimerization
public class Chimerize extends DemoClassAdapter {

    protected ClassNode twig;
    protected MethodNode nm;
    private static final String TWIG_NAME = "org.kambanaria.writebytecode.asm.Version";
    public Chimerize(ClassVisitor cv) throws IOException {
        super(cv);
        ClassReader rdr = new ClassReader(TWIG_NAME);
        twig = new ClassNode();
        rdr.accept(twig, 0);
        for (Object o : twig.methods) {
            MethodNode method = (MethodNode) o;
            if (method.name.equals("toString")) {
                // Guess what is missing?
                nm = method;
            }
        }
    }
    @Override
    public void visitEnd() {
        MethodVisitor chimeric =cv.visitMethod(nm.access, nm.name, nm.desc,
                nm.signature, null);
        nm.instructions.resetLabels();
        Remapper remapper = new Remapper() {
            @Override
            public String map(String name) {
                return name.replace("Version", "Zombunny");
            }
        };
        nm.accept(new RemappingMethodAdapter(nm.access, nm.desc, chimeric, remapper));
        cv.visitEnd();
    }
}
Finally
public class Zombunny implements Comparable { //Зомбайо
    private Integer _version;
    public Zombunny() {
        _version = new Integer(2);
    }
    public Zombunny(Integer version) {
        _version = version;
    }
    public Integer getVersion() {
        return _version;
    }
    public int compareTo(Object o) {
        if (o instanceof Zombunny) {
            return compareTo((Zombunny) o);
        } else {
            throw new ClassCastException();
        }
    }
    public int compareTo(Zombunny o) {
        return _version.compareTo(o._version);
    }
    @Override
    public String toString(){
         return "Version: " + _version;
    }
}
Peek at test construction chain


public class ChimerizeTest {
    Comparable sut;
    @Before
    public void setUp() throws IOException, ReflectiveOperationException {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES + //
                ClassWriter.COMPUTE_MAXS);
        ClassVisitor cv = new AddField(new ManipulateConstructors( //
                new AddMethod(new AddInterface(new Chimerize(cw)))));
        ClassReader rdr = new ClassReader(Utilities.CLASS_NAME);
        rdr.accept(cv, 0);
        byte[] newClassBytes = cw.toByteArray();
        StupidClassLoader ldr = new StupidClassLoader();
        ldr.provide(Utilities.CLASS_NAME, newClassBytes);
        Class<?> newClass = ldr.loadClass(Utilities.CLASS_NAME);
        Constructor<?> constructor = newClass.getDeclaredConstructor(Integer.class);
        sut = (Comparable) constructor.newInstance(new Integer(42));
    }
}
Utilities
●   Type
●   Generate the visitors with: Asmfier
    –   java -classpath asm.jar:asm-util.jar:OUR_CP 
         org.objectweb.asm.util.ASMifier CLASS
●   TraceClassVisitor
●   CheckClassAdapter
Additional APIs
●   org.objectweb.asm.commons – commonly
    needed adaptors
●   org.objectweb.asm.xml – bridge to SAX 2.0,
    manipulate via XSLT, XQuery
●   org.objectweb.asm.tree – deserialize to tree
Classloaders
●   Dynamically load software components for
    Java platform
●   Lazy – loaded on demand, as late as possible
●   Type-safe linkage – must not violate type
    safety, no runtime checks
●   User-defined extensibility – normal, user
    controlled objects
●   Multiple communicating namespaces – types
    determined by class name and classloader
Classloader Chain




  Bootstrap CL        Extension CL           System CL
                                                              Application   Programmer
primordial, native    jre/lib/ext/*.jar    $CLASSPATH
                                                              classloader   classloader
    jre/lib/*.jar    -Djava.ext.dirs      -Djava.class.path
Classloader Hierarchy

                                                              Application   Programmer
                                                              classloader   classloader



  Bootstrap CL        Extension CL           System CL
                                                              Application   Programmer
primordial, native    jre/lib/ext/*.jar    $CLASSPATH
                                                              classloader   classloader
    jre/lib/*.jar    -Djava.ext.dirs      -Djava.class.path



                                                              Application   Programmer
                                                              classloader   classloader
Enterprise Classloader Hierarchy

                                                                            Programmer
                                                              Application   classloader
                                                              classloader   Programmer
                                                                            classloader

                                                                            Programmer
  Bootstrap CL        Extension CL           System CL                      classloader
                                                              Application
primordial, native    jre/lib/ext/*.jar    $CLASSPATH
                                                              classloader   Programmer
    jre/lib/*.jar    -Djava.ext.dirs      -Djava.class.path
                                                                            classloader
                                                                            Programmer
                                                              Application   classloader
                                                              classloader   Programmer
                                                                            classloader
Class Loader API

public abstract class ClassLoader {
    protected ClassLoader(ClassLoader parent);
    protected ClassLoader();

    protected Class<?> loadClass(String name, boolean resolve);
    protected Class<?> findClass(String name);
    protected final Class<?> defineClass(String name, byte[] b,
                                         int off, int len);
    protected final void resolveClass(Class<?> c);

    public URL getResource(String name);
    public Enumeration<URL> getResources(String name);

    public final MyClassLoader getParent();

    public   void   setDefaultAssertionStatus(boolean);
    public   void   setPackageAssertionStatus(String packageName,boolean enabled);
    public   void   setClassAssertionStatus(String className, boolean enabled);
    public   void   clearAssertionStatus();
}
When are class loaded?
●   Statically:
    –   Instance creation: new Integer(42);
    –   Reference to static field or method: System.out;
●   Dynamically:
    –   Class.forName("java.lang.HashMap");
    –   Class.forName("java.lang.HashMap",
                       boolean initialize,
                       ClassLoader loader);
Delegating Classloaders – Standard
Plugin or Web Classloaders
OSGI & others




 OMG!!!
Type Compatibility
●   A classloader can see and use (with exact
    type) instances of classes loaded by the
    ancestral chain and the classloader itself
●   Instances of classes loaded by sibling or
    descendant classloaders are invisible, they
    are just java.lang.Object
        Object a;
        "SomeClass".equals(a.getClass().getName());
        a instanceof Object;
        (SomeClass)a -> ClassCastException
●   Use reflection
Proxies
●   Dynamic proxy acts as a pass through/router
    to the real object
    –   runtime implementations of interfaces
    –   public, final and not abstract
    –   extend java.lang.reflect.Proxy
●   Proxy’s behaviour is determined by an
    implementation of
    java.lang.reflect.InvocationHandler
Square peg in a non square hole




      Some object
                    Some interface
Fit it with an InvocationHandler
                         Proxy




                         Object




public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
}
public class MyInvocationHandler implements InvocationHandler {
  private Object delegate;
  public MyInvocationHandler(Object... params) {
      delegate = makeDelegate();
  }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    Class<?>[] types = method.getParameterTypes();
    Method m = reachMethod(methodName, types);
    Object result;
    try {
        result = m.invoke(delegate, args);
    } catch (InvocationTargetException e) {
        throw e.getCause();
    }
    return result;
  }

    private static Method reachMethod(String name, Class<?>... parTypes) {
      Method m = null;
      /* Logic to determine method */
      return m;
    }

    private static Object makeDelegate(Object... params) {
      /* Produce real object instead */
      return new Object();
    }
}
Java agents
●   Package java.lang.instrument - allow Java
    programming language agents to instrument
    programs running on the JVM.
●   java ... -javaagent:jarpath[=options]
●   Manifest attributes
●   byte[] -> byte[]
Almost Real Example
Action takes place here
A planet, an icy atmosphere
This country
Outsources to this country
They deliver cheaper than the world,
  faster than the speed of thought
The entrepreneurial spirit of that
           country
Makes them sell the software to this
            country
Where it fails spectacularly while
clearly working in the other two ones
Investigation takes place
Finds the culprit

SimpleDateFormat frmt =
      new SimpleDateFormat("E MM/dd/yyyy");




SimpleDateFormat
publicSimpleDateFormat(String pattern)
Constructs a SimpleDateFormat using the
given pattern and the default date format
symbols for the default locale.
Note: This constructor may not support all
Locales. For full coverage, use the factory
methods in the DateFormat class.
Parameters:
pattern - the pattern describing the date and
time format
Throws:
NullPointerException - if the given pattern
                        is null
IllegalArgumentException - if the given pattern
                            is invalid
Could this have been avoided?
                                                                           Hindi
                                                                       (300×106, 4th)
                                                                         Shukravār




LANG=de_DE.UTF-8   java   -jar   SimpleDateFormat.jar   Freitag 11/16/2012
LANG=en_US.UTF-8   java   -jar   SimpleDateFormat.jar   Friday 11/16/2012
LANG=hi_IN.UTF-8   java   -jar   SimpleDateFormat.jar   शुकवार ११/१६/२०१२
LANG=bn_IN.UTF-8   java   -jar   SimpleDateFormat.jar   Friday 11/16/2012
LANG=bg_BG.UTF-8   java   -jar   SimpleDateFormat.jar   Петък 11/16/2012




                                                                          Bengali
                                                                       (200×106, 7th)
                                                                          শুক্রার
                                                                              ্রব
                                                                         Shukrobar
En Use
Lo glis
  ca h
    le
          India proposes:
USA retransmits:


        Use
      English
       Locale
Germany says:


   No!
USA try in German:


      Verwenden
         Sie
       Englische
        Locale
Germany says:


   Nein!
USA try manners:


      Bitte?
Germany says:


   NEIN!
USA checks what they said with
      Google translate:
mv.visitMethodInsn(INVOKESPECIAL, "java/text/SimpleDateFormat", //
                "<init>", "(Ljava/lang/String;)V");




mv.visitFieldInsn(GETSTATIC, "java/util/Locale", //
                "US", "Ljava/util/Locale;");
mv.visitMethodInsn(INVOKESPECIAL, "java/text/SimpleDateFormat", //
                "<init>", "(Ljava/lang/String;Ljava/util/Locale;)V");
Compiler API
import java.util.Random;
public class I {
    public boolean singOutOfTune() {
        return new Random().nextBoolean();
    }
}
import java.util.Random;
public class I {
    public boolean singOutOfTune() {
        return new Random().nextBoolean();
    }
}

public class You {
    public static String DID = "StandUp&WalkOutOnMe";
    public static String DIDNOT = "LendMeAnEar";
    public String wouldDo(boolean iF) {
        return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar";
    }
}
import java.util.Random;
public class I {
    public boolean singOutOfTune() {
        return new Random().nextBoolean();
    }
}

public class You {
    public static String DID = "StandUp&WalkOutOnMe";
    public static String DIDNOT = "LendMeAnEar";
    public String wouldDo(boolean iF) {
        return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar";
    }
}


public class ExistingClassesTest {
    @Test
    public void test1000times() {
        int times = 1000;
        do {
             boolean didI;
            I i = new I();
            You you = new You();
            String what = you.wouldDo(didI = i.singOutOfTune());
             assertEquals(what, didI ? You.DID : You.DIDNOT);
        } while (--times > 0);

    }
}
import java.util.Random;
public class I {
    public boolean singOutOfTune() {
        return new Random().nextBoolean();
    }
}

public class You {
    public static String DID = "StandUp&WalkOutOnMe";
    public static String DIDNOT = "LendMeAnEar";
    public String wouldDo(boolean iF) {
        return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar";
    }
}


public class ExistingClassesTest {
    @Test
    public void test1000times() {
        int times = 1000;
        do {
             boolean didI;
            I i = new I();
            You you = new You();
            String what = you.wouldDo(didI = i.singOutOfTune());
             assertEquals(what, didI ? You.DID : You.DIDNOT);
        } while (--times > 0);
        // What would you do if I sang out of tune ? The Beatles
    }
}
public class SourceStrings {
    private SourceStrings() }
    public final static String I = "                                         "
            + "import java.util.Random;                                      "
            + "public class I {                                              "
            + "    public boolean singOutOfTune() {                          "
            + "        return new Random().nextBoolean();                    "
            + "    }                                                         "
            + "}                                                             ";
    public final static String YOU = "                                       "
            + "public class You {                                            "
            + "    public static String DID = "StandUp&WalkOutOnMe";       "
            + "    public static String DIDNOT = "LendMeAnEar";            "
            + "    public String wouldDo(boolean iF) {                       "
            + "        return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar";"
            + "    }                                                         "
            + "}                                                             ";
}




class StringSourceCodeObject extends SimpleJavaFileObject {

   final String _source;

   public StringSourceCodeObject(String fqName, String source) {
       super(URI.create("string:///" + fqName.replaceAll(".", "/") //
               + Kind.SOURCE.extension), Kind.SOURCE);
       _source = source;
   }

   @Override
   public CharSequence getCharContent(boolean ignoreEncodingErrors) {
       return _source;
   }
public class CompilerAPI {
    public static void main(String args[]) throws Exception {

        /* Creating dynamic java source code file object */
        JavaFileObject iObject = new StringSourceCodeObject("I", SourceStrings.I);
        JavaFileObject youObject = new StringSourceCodeObject("You", SourceStrings.YOU);
        JavaFileObject jfObjects[] = new JavaFileObject[]{iObject, youObject};
        /* Units to compile */
        Iterable<JavaFileObject> units = Arrays.asList(jfObjects);
        /* Instantiating the java compiler */
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        /* Get compiler file manager to show what to read. */
        // (DEFAULT LISTENER, Locale.getDefault(), Charset.defaultCharset() )
        JavaFileManager manager = compiler.getStandardFileManager(null, null, null);
        /* Compilation options - here: place in target directory */
        String[] compileOptions = new String[]{"-d", "target/classes"};
        Iterable<String> options = Arrays.asList(compileOptions);
        /* Diagnostic placeholder */
        DiagnosticCollector<JavaFileObject> sink = new DiagnosticCollector<JavaFileObject>();
        /* 1st null: where to write (default), 2nd null: no annotations processed */
        CompilationTask task = compiler.getTask(null, manager, sink, options, null, units);
        /* Go, go, go */
        boolean status = task.call();
        if (!status) {
            for (Diagnostic<? extends JavaFileObject> d : sink.getDiagnostics()) {
                System.err.format("Error on line %d in %s", d.getLineNumber(), d);
            }
        }
        manager.close();// TRY to close the file manager
    }
}
public class CompilerAPITest {
    Object i;
    Object you;
    @BeforeClass
    public static void setUpClass() throws Exception {
         CompilerAPI.main(null);
    }
    @Before
    public void setUp() throws ReflectiveOperationException {
         i = Class.forName("I").newInstance();
         you = Class.forName("You").newInstance();
    }
    @After
    public void tearDown() {
         i = null;
         you = null;
    }
   @Test
    public void testMain() throws Exception {
         assertEquals(i.getClass().getName(), "I");
         assertEquals(you.getClass().getName(), "You");
         Method m1 = i.getClass().getMethod("singOutOfTune", (Class<?>[]) null);
         Object didI = m1.invoke(i, (Object[]) null);

        for (Method m2 : you.getClass().getMethods()) {
            if ("wouldDo".equals(m2.getName())) {
                Class<?>[] args = m2.getParameterTypes();
                if (1 == args.length && args[0].isAssignableFrom(boolean.class)) {
                    System.out.println("m2.invoke(you, didI)");
                    return;
                }
            }
        }
        fail("We did not find our method!");
    }
Some Links
●   Code:
    https://github.com/alshopov/WriteBytecode
●   Presentation:
    The presentation is to be improved.

Mais conteúdo relacionado

Mais procurados

What is new and cool j2se & java
What is new and cool j2se & javaWhat is new and cool j2se & java
What is new and cool j2se & java
Eugene Bogaart
 
Tew4 Yatce presentation
Tew4 Yatce presentationTew4 Yatce presentation
Tew4 Yatce presentation
UENISHI Kota
 
javascript teach
javascript teachjavascript teach
javascript teach
guest3732fa
 

Mais procurados (20)

Understanding the Dalvik bytecode with the Dedexer tool
Understanding the Dalvik bytecode with the Dedexer toolUnderstanding the Dalvik bytecode with the Dedexer tool
Understanding the Dalvik bytecode with the Dedexer tool
 
Dancing with dalvik
Dancing with dalvikDancing with dalvik
Dancing with dalvik
 
Introduction to Ruby
Introduction to RubyIntroduction to Ruby
Introduction to Ruby
 
What is new and cool j2se & java
What is new and cool j2se & javaWhat is new and cool j2se & java
What is new and cool j2se & java
 
NDK Primer (Wearable DevCon 2014)
NDK Primer (Wearable DevCon 2014)NDK Primer (Wearable DevCon 2014)
NDK Primer (Wearable DevCon 2014)
 
A bridge between php and ruby
A bridge between php and ruby A bridge between php and ruby
A bridge between php and ruby
 
Groovy Up Your Code
Groovy Up Your CodeGroovy Up Your Code
Groovy Up Your Code
 
不深不淺,帶你認識 LLVM (Found LLVM in your life)
不深不淺,帶你認識 LLVM (Found LLVM in your life)不深不淺,帶你認識 LLVM (Found LLVM in your life)
不深不淺,帶你認識 LLVM (Found LLVM in your life)
 
Ruby Presentation - Beamer
Ruby Presentation - BeamerRuby Presentation - Beamer
Ruby Presentation - Beamer
 
TypeProf for IDE: Enrich Development Experience without Annotations
TypeProf for IDE: Enrich Development Experience without AnnotationsTypeProf for IDE: Enrich Development Experience without Annotations
TypeProf for IDE: Enrich Development Experience without Annotations
 
Handling inline assembly in Clang and LLVM
Handling inline assembly in Clang and LLVMHandling inline assembly in Clang and LLVM
Handling inline assembly in Clang and LLVM
 
Mirah Talk for Boulder Ruby Group
Mirah Talk for Boulder Ruby GroupMirah Talk for Boulder Ruby Group
Mirah Talk for Boulder Ruby Group
 
Ruby
RubyRuby
Ruby
 
Type Profiler: Ambitious Type Inference for Ruby 3
Type Profiler: Ambitious Type Inference for Ruby 3Type Profiler: Ambitious Type Inference for Ruby 3
Type Profiler: Ambitious Type Inference for Ruby 3
 
NDK Primer (AnDevCon Boston 2014)
NDK Primer (AnDevCon Boston 2014)NDK Primer (AnDevCon Boston 2014)
NDK Primer (AnDevCon Boston 2014)
 
Tew4 Yatce presentation
Tew4 Yatce presentationTew4 Yatce presentation
Tew4 Yatce presentation
 
TEW4 Yatce deprecated slides
TEW4 Yatce deprecated slidesTEW4 Yatce deprecated slides
TEW4 Yatce deprecated slides
 
Quick Intro To JRuby
Quick Intro To JRubyQuick Intro To JRuby
Quick Intro To JRuby
 
Ruby On Rails pizza training
Ruby On Rails pizza trainingRuby On Rails pizza training
Ruby On Rails pizza training
 
javascript teach
javascript teachjavascript teach
javascript teach
 

Destaque

Mastering Java Bytecode - JAX.de 2012
Mastering Java Bytecode - JAX.de 2012Mastering Java Bytecode - JAX.de 2012
Mastering Java Bytecode - JAX.de 2012
Anton Arhipov
 
Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011
Anton Arhipov
 
Mastering java bytecode with ASM - GeeCON 2012
Mastering java bytecode with ASM - GeeCON 2012Mastering java bytecode with ASM - GeeCON 2012
Mastering java bytecode with ASM - GeeCON 2012
Anton Arhipov
 

Destaque (9)

Working with Bytecode
Working with BytecodeWorking with Bytecode
Working with Bytecode
 
Mastering Java Bytecode - JAX.de 2012
Mastering Java Bytecode - JAX.de 2012Mastering Java Bytecode - JAX.de 2012
Mastering Java Bytecode - JAX.de 2012
 
Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011
 
Beyond the Final Frontier of jQuery Selectors
Beyond the Final Frontier of jQuery SelectorsBeyond the Final Frontier of jQuery Selectors
Beyond the Final Frontier of jQuery Selectors
 
Oracle's Take On NoSQL
Oracle's Take On NoSQLOracle's Take On NoSQL
Oracle's Take On NoSQL
 
Bytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASMBytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASM
 
Mastering java bytecode with ASM - GeeCON 2012
Mastering java bytecode with ASM - GeeCON 2012Mastering java bytecode with ASM - GeeCON 2012
Mastering java bytecode with ASM - GeeCON 2012
 
Caching in HTTP
Caching in HTTPCaching in HTTP
Caching in HTTP
 
Platforms as Contracts
Platforms as ContractsPlatforms as Contracts
Platforms as Contracts
 

Semelhante a I Know Kung Fu - Juggling Java Bytecode

Ola Bini Evolving The Java Platform
Ola Bini Evolving The Java PlatformOla Bini Evolving The Java Platform
Ola Bini Evolving The Java Platform
deimos
 
Javascriptbootcamp
JavascriptbootcampJavascriptbootcamp
Javascriptbootcamp
oscon2007
 
Tutorial visitor
Tutorial visitorTutorial visitor
Tutorial visitor
Wei Wang
 
Ola Bini J Ruby Power On The Jvm
Ola Bini J Ruby Power On The JvmOla Bini J Ruby Power On The Jvm
Ola Bini J Ruby Power On The Jvm
deimos
 
Byteman and The Jokre, Sanne Grinovero (JBoss by RedHat)
Byteman and The Jokre, Sanne Grinovero (JBoss by RedHat)Byteman and The Jokre, Sanne Grinovero (JBoss by RedHat)
Byteman and The Jokre, Sanne Grinovero (JBoss by RedHat)
OpenBlend society
 
J Ruby Power On The Jvm
J Ruby Power On The JvmJ Ruby Power On The Jvm
J Ruby Power On The Jvm
QConLondon2008
 

Semelhante a I Know Kung Fu - Juggling Java Bytecode (20)

Ola Bini Evolving The Java Platform
Ola Bini Evolving The Java PlatformOla Bini Evolving The Java Platform
Ola Bini Evolving The Java Platform
 
Scala e xchange 2013 haoyi li on metascala a tiny diy jvm
Scala e xchange 2013 haoyi li on metascala a tiny diy jvmScala e xchange 2013 haoyi li on metascala a tiny diy jvm
Scala e xchange 2013 haoyi li on metascala a tiny diy jvm
 
Euruko 2012 - JRuby
Euruko 2012 - JRubyEuruko 2012 - JRuby
Euruko 2012 - JRuby
 
Javascriptbootcamp
JavascriptbootcampJavascriptbootcamp
Javascriptbootcamp
 
JRuby - The Perfect Alternative
JRuby - The Perfect AlternativeJRuby - The Perfect Alternative
JRuby - The Perfect Alternative
 
Expert JavaScript Programming
Expert JavaScript ProgrammingExpert JavaScript Programming
Expert JavaScript Programming
 
Unsafe Java
Unsafe JavaUnsafe Java
Unsafe Java
 
Tutorial visitor
Tutorial visitorTutorial visitor
Tutorial visitor
 
Polyglot and Functional Programming (OSCON 2012)
Polyglot and Functional Programming (OSCON 2012)Polyglot and Functional Programming (OSCON 2012)
Polyglot and Functional Programming (OSCON 2012)
 
Ola Bini J Ruby Power On The Jvm
Ola Bini J Ruby Power On The JvmOla Bini J Ruby Power On The Jvm
Ola Bini J Ruby Power On The Jvm
 
Aloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRubyAloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRuby
 
JRuby: The Hard Parts
JRuby: The Hard PartsJRuby: The Hard Parts
JRuby: The Hard Parts
 
Byteman and The Jokre, Sanne Grinovero (JBoss by RedHat)
Byteman and The Jokre, Sanne Grinovero (JBoss by RedHat)Byteman and The Jokre, Sanne Grinovero (JBoss by RedHat)
Byteman and The Jokre, Sanne Grinovero (JBoss by RedHat)
 
J Ruby Power On The Jvm
J Ruby Power On The JvmJ Ruby Power On The Jvm
J Ruby Power On The Jvm
 
2008-12 OJUG JCR Demo
2008-12 OJUG JCR Demo2008-12 OJUG JCR Demo
2008-12 OJUG JCR Demo
 
Learn To Code: Introduction to java
Learn To Code: Introduction to javaLearn To Code: Introduction to java
Learn To Code: Introduction to java
 
Core Java Training
Core Java TrainingCore Java Training
Core Java Training
 
JavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for DummiesJavaOne 2011 - JVM Bytecode for Dummies
JavaOne 2011 - JVM Bytecode for Dummies
 
JVM: A Platform for Multiple Languages
JVM: A Platform for Multiple LanguagesJVM: A Platform for Multiple Languages
JVM: A Platform for Multiple Languages
 
Presentation on java
Presentation  on  javaPresentation  on  java
Presentation on java
 

Último

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 

Último (20)

Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 

I Know Kung Fu - Juggling Java Bytecode

  • 1. I Know Kung Fu – Writing Java Bytecode Alexander Shopov <ash@kambanaria.org>
  • 2. [ash@edge ~]$ whoami By day: Software Engineer at Cisco By night: OSS contributor Coordinator of Bulgarian Gnome TP Contacts: E-mail: ash@kambanaria.org Jabber: al_shopov@jabber.minus273.org LinkedIn: http://www.linkedin.com/in/alshopov Web: Just search “al_shopov”
  • 3. Please Learn And Share License: CC-BY v3.0Creative Common
  • 4. Disclaimer My opinions, knowledge and experience! Not my employer's.
  • 5. Plan ● What is bytecode and how to juggle it ● Why do it, why not do it ● How to do it – Class file structure – Manipulation with ASM ● How to consume your own dog food – Classloaders – Proxies – Agents
  • 6. What it is ● Bytecodes are the assembler of JVM. By writing new bytecode sequences or changing existing ones we can program the JVM directly – outside of the domain of the Java Programming Language; ● Lower level than writing Java - JVM assembler; ● Much easier than writing a whole (optimizing) compiler; ● Harder than using a compiler; ● Similar to the Jedi Dark Side – pathway to many abilities some consider to be unnatural.
  • 7. Why do it? ● Makes impossible things possible & ● Makes hard things attainable & ● Makes long tasks shorter & ● Makes slow things faster & ● Makes repetition go away & ● Makes your head blow away!!!
  • 8. Common use cases ● Program analysis – find bugs, unused code paths, reverse engineering, metrics, etc. ● Program generation – compilers, stub/skeleton compilers, fast layers without reflection. ● Transformation – optimize, deoptimize/obfuscate, aspect weaving, performance monitoring.
  • 9. Why not do it? ● Source stops being close to executable & ● Executable stops being close to any source & ● There can be better or easier ways of doing things & ● Fewer people knowing what happens means no one can help you & ● Problems will be your fault! Unit test ∀ ! & ● You take the red pill and find out the rabbit hole goes deep, deep, deep… EOT
  • 10. Common misuse cases ● I write it, you maintain it. ● Do it because it is cool or others are doing it. ● Over engineering / over generalization. ● Solution in a search of a problem. ● Preferring NIH to a popular solution.
  • 11. Bytecode crash course in 1-2-3 F4 Thread D Thread C Thread B F3 F3 Thread A F2 F2 F2 F1 F1 F1 F1 F0 F0 F0 F0
  • 12. Bytecode crash course in 1-2-3 JVM (heap) 0 1 2 3 4 5 6 … Class PC Local variables Method code F0 Class Pool of constants Stack
  • 13. Bytecode crash course in 1-2-3 ● Bytecodes retrieve things from class bytestream, constant pool, local variables array ● Perform computations only on stack ● Store temporary results in local variables array ● Enter frame by method call ● Return from frame with a possible result (top thing on stack), throw top of stack ● JVM can also throw and unroll frames
  • 14. If you need more information ● Check my other presentation: Lifting the Veil – Reading Java Bytecode
  • 15. How to do it ● Many ways with different pluses and minuses ● Easiest way to write byte code – use the Java compiler. – javac – you all know that – java compiler api – since 1.6 ● But more of that – wait for the end ● Until then…
  • 16. Soot jDec CGlib JCF Editor cojen Jiapi Retroweaver JavaAssist BCEL Tea Trove jReloader jclasslib Roo Serp AspectJ gnu.bytecode
  • 17. Soot jDec CGlib JCF Editor cojen Jiapi One of the older frameworks, Retroweaver JavaAssist BCEL Tea Trove jReloader jclasslib Roo Serp AspectJ gnu.bytecode
  • 18. Bytecode manipulation ● Not constrained by Java ● Not constrained by compiler ● Not constrained by source availability ● Still constrained by JVM ● Generate or change bytecode to the limits of JVM
  • 19. Classfile Structure, 0xcafebabe Modifiers, name, super class, interfaces Constant pool: numeric, string and type constants Source file name (optional) Enclosing class reference Annotation* Attribute* Inner class* Name Field* Modifiers, name, type Annotation* Attribute* Method* Modifiers, name, return and parameter types Annotation* Attribute* Compiled code
  • 20. What is ASM ● Extremely well designed bytecode manipulation library ● Modular, small and fast – pick all ● Events based – visitor (+SAX), additionally has tree API (DOM like) ● Provides a small bytecode generation variant ● Minimal – just transformation, can stack transformations, no classloading
  • 21. Timeline ● 1.5 – 30 Aug 2004 – up to JDK 1.6 incl. ● 2.0 – 17 May 2005 ● 3.0 – 01 Nov 2006 ● 4.0 – 29 Oct 2011 – framework for compatibility
  • 22. Who uses ASM? ● Languages and AOP tools: AspectJ, BeanShell, CGLIB, Clojure, Groovy, Jruby, Jython, Coroutines ● Tools and frameworks: Fractal, Terracotta, Javeleon, JRebel ● Persistence: OpenEJB, Oracle BerkleyDB, EclipseLink ● Monitoring: WebLogic, JiP ● Testing and code analysis: Cobertura, Eclipse
  • 23. Most JDKs Use It! ● Oracle – Sun – HotSpot – JDK, OpenJDK – BEA/Appeal VM – JRockit ● IBM – J9 ● Azul – Zing – $JAVA_HOME/jre/lib/rt.jar – com.sun.xml.internal.ws.org.objectweb.asm – com.sun.xml.internal.ws.model.WrapperBeanGenerator ⇒ RuntimeModeler ⇒ Web Services implementation
  • 24. Read and explore Class Class Reader Visitor
  • 25. Read, transform, write Class Class Class Class Reader Visitor Visitor Writer
  • 26. I know what I am doing Class Class Class Class Class Class Class Class Reader Visitor Visitor Visitor Visitor Visitor Visitor Writer
  • 27. I believe I can fly, I believe I can touch the sky… Class Class Class Class Class Class Reader Visitor Visitor Visitor Visitor Writer Class Class Class Class Class Visitor Visitor Visitor Visitor Writer Class Class Class Class Class Class Reader Visitor Visitor Visitor Visitor Writer Class Class Class Class Visitor Visitor Visitor Writer Class Class Class Class Class Reader Visitor Visitor Visitor Visitor
  • 28. Basic Pattern Of Transformation ● Read bytestream of a class ● Generate events from that ● Make changes to the events ● Receive the events and serialize to bytestream ● Lather, rinse, repeat
  • 29. Basic diagram of class visiting User ClassVisitor visit visitSource ● Order is important visitOuterClass visitAnnotation ● Bold return other * visitAttribute visitors visitInnerClass visitFiled * ● * marks repeat vistiMethod visitEnd
  • 30. Basic diagram of annotation visiting User AnnotationVisitor visit * visitEnum ● Order is important visitAnnotation visitArray ● Bold return other visitEnd visitors ● * marks repeat
  • 31. Basic diagram of field visiting User FieldVisitor visitAnnotation * visitAttribute ● Order is important visitEnd ● Bold return other visitors ● * marks repeat
  • 32. Basic diagram of method visiting User MethodVisitor visitAnnotationDefault visitAnnotation * ● Order is important visitParameterAnnotation visitAttribute ● Bold return other visitCode visitors visitFrame visitXInsn * ● * marks repeat visitLabel visitTryCatchBlock visitLocalVariable visitLineNumber visitMaxs visitEnd
  • 33. Our humble beginning package org.kambanaria.writebytecode.asm; public class Zombunny { //Зомбайо public Integer getVersion() { return Integer.valueOf(1); } }
  • 34. Our building blocks public class StupidClassLoader extends ClassLoader { private Map<String, byte[]> bytes = new HashMap<String, byte[]>(); public StupidClassLoader() { super(StupidClassLoader.class.getClassLoader()); } public void provide(String className, byte[] classBytes) { bytes.put(className, classBytes); } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { byte[] classBytes = bytes.get(name); Class<?> loaded; if (classBytes != null) { loaded = defineClass(name, classBytes, 0, classBytes.length); } else { ClassLoader parent = getParent(); if (null == parent) { parent = ClassLoader.getSystemClassLoader(); } loaded = parent.loadClass(name); } return loaded; } }
  • 35. Our building blocks public final class Utilities { private Utilities() { } public static final String CLASS_NAME = "org.kambanaria.writebytecode.asm.Zombunny"; public static final String METHOD_NAME = "getVersion"; public static String toClassPathResourceName(String clazz) { return clazz.replace('.', '/') + ".class"; } public static byte[] retrieveBytesFromClassPath(String className) throws IOException { String path = toClassPathResourceName(className); InputStream is = Utilities.class.getClassLoader().getResourceAsStream(path); InputStream classBytes = new BufferedInputStream(is); return is2bytes(classBytes); } public static byte[] patch(byte[] bytes, DemoClassAdapter adapter) { ClassReader cr = new ClassReader(bytes); cr.accept(adapter, ClassReader.SKIP_FRAMES); return adapter.getCw().toByteArray(); } public static byte[] is2bytes(InputStream is) throws IOException { int max = 1024 * 1024; byte[] bytes = new byte[max]; // 1MB int read = is.read(bytes); // Don't do that byte[] result = new byte[read]; System.arraycopy(bytes, 0, result, 0, result.length); return result; } public static Object call0ArgsMethodOn(Object o, String methodName) // throws ReflectiveOperationException { Class<?> c = o.getClass(); Method m = c.getDeclaredMethod(methodName, (Class<?>[]) null); m.setAccessible(true); return m.invoke(o, (Object[]) null); } }
  • 36. Our building blocks public class DemoClassAdapter extends ClassVisitor { public DemoClassAdapter(ClassVisitor cv) { super(Opcodes.ASM4, cv); } public ClassWriter getCw() { return (ClassWriter) cv; } }
  • 37. Rename class public class Rename extends DemoClassAdapter { private String suffix; public Rename(ClassVisitor cv, String suffix) { super(cv); this.suffix = suffix; } @Override public void visit(int version, int access, String name, // String signature, String superName, String[] interfaces) { cv.visit(version, access, name + suffix, signature, superName, interfaces); } }
  • 38. Result is as if package org.kambanaria.writebytecode.asm; public class ZombunnySUFFIX { //Зомбайо public Integer getVersion() { return Integer.valueOf(1); } }
  • 39. Add field public class AddField extends DemoClassAdapter { public AddField(ClassVisitor cv) { super(cv); } @Override public void visitEnd() { cv.visitField(ACC_PRIVATE, "_version", // Type.getDescriptor(Integer.class), null, null); cv.visitEnd(); } }
  • 40. Add field public class Zombunny { //Зомбайо private Integer _version; public Integer getVersion() { return Integer.valueOf(1); } }
  • 41. Change method public class ChangeMethod extends DemoClassAdapter { public ChangeMethod(ClassVisitor cv) { super(cv); } @Override public MethodVisitor visitMethod(int access, String name, String desc, // String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); if (Utilities.METHOD_NAME.equals(name) && "()Ljava/lang/Integer;".equals(desc)) { return new DemoMethodVisitor(Opcodes.ASM4, mv); } else { return mv; } } class DemoMethodVisitor extends MethodVisitor { public DemoMethodVisitor(int version, MethodVisitor mv) { super(version, mv); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "org/kambanaria/writebytecode/asm/Zombunny", // "_version", "Ljava/lang/Integer;"); mv.visitInsn(ARETURN); mv.visitEnd(); } } }
  • 42. And change method public class Zombunny { //Зомбайо private Integer _version; public Integer getVersion() { return _version; } }
  • 43. Fix constructors public class ManipulateConstructors extends DemoClassAdapter { public ManipulateConstructors(ClassVisitor cv) { super(cv); } @Override public MethodVisitor visitMethod(int access, String name, String desc, // String signature, String[] exceptions) { if ("<init>".equals(name)) { MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); mv.visitVarInsn(ALOAD, 0); mv.visitTypeInsn(NEW, "java/lang/Integer"); mv.visitInsn(DUP); mv.visitInsn(ICONST_2); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer", "<init>", "(I)V"); mv.visitFieldInsn(PUTFIELD, "org/kambanaria/writebytecode/asm/Zombunny", // "_version", "Ljava/lang/Integer;"); mv.visitInsn(RETURN); mv.visitMaxs(4, 1); mv.visitEnd(); return mv; } else { return cv.visitMethod(access, name, desc, signature, exceptions); } } @Override public void visitEnd() { MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/Integer;)V", // null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(PUTFIELD, "org/kambanaria/writebytecode/asm/Zombunny", // "_version", "Ljava/lang/Integer;"); mv.visitInsn(RETURN); mv.visitMaxs(2, 2); mv.visitEnd(); cv.visitEnd(); } }
  • 44. And fix constructors public class Zombunny { //Зомбайо private Integer _version; public Zombunny() { _version = new Integer(2); } public Zombunny(Integer version) { _version = version; } public Integer getVersion() { return _version; } }
  • 45. Add interface public class AddInterface extends DemoClassAdapter { private static final String COMPARABLE = "java/lang/Comparable"; public AddInterface(ClassVisitor cv) { super(cv); } @Override public void visit(int version, int access, String name, String signature,// String superName, String[] interfaces) { if (Arrays.asList(interfaces).contains(COMPARABLE)) { super.visit(version, access, name, signature, superName, interfaces); } else { int l = interfaces.length; String[] newInterfaces = new String[l + 1]; System.arraycopy(interfaces, 0, newInterfaces, 0, l); newInterfaces[l] = COMPARABLE; super.visit(version, access, name, signature, superName, newInterfaces); } } }
  • 46. And add interface public class Zombunny implements Comparable { //Зомбайо private Integer _version; public Zombunny() { _version = new Integer(2); } public Zombunny(Integer version) { _version = version; } public Integer getVersion() { return _version; } }
  • 47. Add interface implementation public class AddMethod extends DemoClassAdapter { public AddMethod(ClassVisitor cv) {super(cv);} @Override public void visitEnd() { MethodVisitor compareToObject = cv.visitMethod(ACC_PUBLIC, "compareTo", // "(Ljava/lang/Object;)I", null, null); compareToObject.visitCode(); compareToObject.visitVarInsn(ALOAD, 1); compareToObject.visitTypeInsn(INSTANCEOF, "org/kambanaria/writebytecode/asm/Zombunny"); Label lbl0 = new Label(); compareToObject.visitJumpInsn(IFNE, lbl0); compareToObject.visitTypeInsn(NEW, "java/lang/ClassCastException"); compareToObject.visitInsn(DUP); compareToObject.visitMethodInsn(INVOKESPECIAL, "java/lang/ClassCastException", // "<init>", "()V"); compareToObject.visitInsn(ATHROW); compareToObject.visitLabel(lbl0); compareToObject.visitVarInsn(ALOAD, 0); compareToObject.visitVarInsn(ALOAD, 1); compareToObject.visitTypeInsn(CHECKCAST, "org/kambanaria/writebytecode/asm/Zombunny"); compareToObject.visitMethodInsn(INVOKEVIRTUAL, "org/kambanaria/writebytecode/asm/Zombunny", // "compareTo", "(Lorg/kambanaria/writebytecode/asm/Zombunny;)I"); compareToObject.visitInsn(IRETURN); compareToObject.visitMaxs(2, 2); compareToObject.visitEnd(); MethodVisitor compareToZombunny = cv.visitMethod(ACC_PUBLIC, "compareTo", // "(Lorg/kambanaria/writebytecode/asm/Zombunny;)I", null, null); compareToZombunny.visitCode(); compareToZombunny.visitVarInsn(ALOAD, 0); compareToZombunny.visitFieldInsn(GETFIELD, "org/kambanaria/writebytecode/asm/Zombunny", // "_version", "Ljava/lang/Integer;"); compareToZombunny.visitVarInsn(ALOAD, 1); compareToZombunny.visitFieldInsn(GETFIELD, "org/kambanaria/writebytecode/asm/Zombunny", // "_version", "Ljava/lang/Integer;"); compareToZombunny.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", // "(Ljava/lang/Integer;)I"); compareToZombunny.visitInsn(IRETURN); compareToZombunny.visitMaxs(2, 2); compareToZombunny.visitEnd(); cv.visitEnd(); } }
  • 48. And add interface public class Zombunny implements Comparable { //Зомбайо private Integer _version; public Zombunny() { _version = new Integer(2); } public Zombunny(Integer version) { _version = version; } public Integer getVersion() { return _version; } public int compareTo(Object o) { if (o instanceof Zombunny) { return compareTo((Zombunny) o); } else { throw new ClassCastException(); } } public int compareTo(Zombunny o) { return _version.compareTo(o._version); } }
  • 49. The class we get method from package org.kambanaria.writebytecode.asm; public class Version { private Integer _version; public Version(Integer version) { _version = version; } public Integer getVersion() { return _version; } @Override public String toString() { return "Version: " + _version; } }
  • 50. Chimerization public class Chimerize extends DemoClassAdapter { protected ClassNode twig; protected MethodNode nm; private static final String TWIG_NAME = "org.kambanaria.writebytecode.asm.Version"; public Chimerize(ClassVisitor cv) throws IOException { super(cv); ClassReader rdr = new ClassReader(TWIG_NAME); twig = new ClassNode(); rdr.accept(twig, 0); for (Object o : twig.methods) { MethodNode method = (MethodNode) o; if (method.name.equals("toString")) { // Guess what is missing? nm = method; } } } @Override public void visitEnd() { MethodVisitor chimeric =cv.visitMethod(nm.access, nm.name, nm.desc, nm.signature, null); nm.instructions.resetLabels(); Remapper remapper = new Remapper() { @Override public String map(String name) { return name.replace("Version", "Zombunny"); } }; nm.accept(new RemappingMethodAdapter(nm.access, nm.desc, chimeric, remapper)); cv.visitEnd(); } }
  • 51. Finally public class Zombunny implements Comparable { //Зомбайо private Integer _version; public Zombunny() { _version = new Integer(2); } public Zombunny(Integer version) { _version = version; } public Integer getVersion() { return _version; } public int compareTo(Object o) { if (o instanceof Zombunny) { return compareTo((Zombunny) o); } else { throw new ClassCastException(); } } public int compareTo(Zombunny o) { return _version.compareTo(o._version); } @Override public String toString(){ return "Version: " + _version; } }
  • 52. Peek at test construction chain public class ChimerizeTest { Comparable sut; @Before public void setUp() throws IOException, ReflectiveOperationException { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES + // ClassWriter.COMPUTE_MAXS); ClassVisitor cv = new AddField(new ManipulateConstructors( // new AddMethod(new AddInterface(new Chimerize(cw))))); ClassReader rdr = new ClassReader(Utilities.CLASS_NAME); rdr.accept(cv, 0); byte[] newClassBytes = cw.toByteArray(); StupidClassLoader ldr = new StupidClassLoader(); ldr.provide(Utilities.CLASS_NAME, newClassBytes); Class<?> newClass = ldr.loadClass(Utilities.CLASS_NAME); Constructor<?> constructor = newClass.getDeclaredConstructor(Integer.class); sut = (Comparable) constructor.newInstance(new Integer(42)); } }
  • 53. Utilities ● Type ● Generate the visitors with: Asmfier – java -classpath asm.jar:asm-util.jar:OUR_CP org.objectweb.asm.util.ASMifier CLASS ● TraceClassVisitor ● CheckClassAdapter
  • 54. Additional APIs ● org.objectweb.asm.commons – commonly needed adaptors ● org.objectweb.asm.xml – bridge to SAX 2.0, manipulate via XSLT, XQuery ● org.objectweb.asm.tree – deserialize to tree
  • 55. Classloaders ● Dynamically load software components for Java platform ● Lazy – loaded on demand, as late as possible ● Type-safe linkage – must not violate type safety, no runtime checks ● User-defined extensibility – normal, user controlled objects ● Multiple communicating namespaces – types determined by class name and classloader
  • 56. Classloader Chain Bootstrap CL Extension CL System CL Application Programmer primordial, native jre/lib/ext/*.jar $CLASSPATH classloader classloader jre/lib/*.jar -Djava.ext.dirs -Djava.class.path
  • 57. Classloader Hierarchy Application Programmer classloader classloader Bootstrap CL Extension CL System CL Application Programmer primordial, native jre/lib/ext/*.jar $CLASSPATH classloader classloader jre/lib/*.jar -Djava.ext.dirs -Djava.class.path Application Programmer classloader classloader
  • 58. Enterprise Classloader Hierarchy Programmer Application classloader classloader Programmer classloader Programmer Bootstrap CL Extension CL System CL classloader Application primordial, native jre/lib/ext/*.jar $CLASSPATH classloader Programmer jre/lib/*.jar -Djava.ext.dirs -Djava.class.path classloader Programmer Application classloader classloader Programmer classloader
  • 59. Class Loader API public abstract class ClassLoader { protected ClassLoader(ClassLoader parent); protected ClassLoader(); protected Class<?> loadClass(String name, boolean resolve); protected Class<?> findClass(String name); protected final Class<?> defineClass(String name, byte[] b, int off, int len); protected final void resolveClass(Class<?> c); public URL getResource(String name); public Enumeration<URL> getResources(String name); public final MyClassLoader getParent(); public void setDefaultAssertionStatus(boolean); public void setPackageAssertionStatus(String packageName,boolean enabled); public void setClassAssertionStatus(String className, boolean enabled); public void clearAssertionStatus(); }
  • 60. When are class loaded? ● Statically: – Instance creation: new Integer(42); – Reference to static field or method: System.out; ● Dynamically: – Class.forName("java.lang.HashMap"); – Class.forName("java.lang.HashMap", boolean initialize, ClassLoader loader);
  • 62. Plugin or Web Classloaders
  • 63. OSGI & others OMG!!!
  • 64. Type Compatibility ● A classloader can see and use (with exact type) instances of classes loaded by the ancestral chain and the classloader itself ● Instances of classes loaded by sibling or descendant classloaders are invisible, they are just java.lang.Object Object a; "SomeClass".equals(a.getClass().getName()); a instanceof Object; (SomeClass)a -> ClassCastException ● Use reflection
  • 65. Proxies ● Dynamic proxy acts as a pass through/router to the real object – runtime implementations of interfaces – public, final and not abstract – extend java.lang.reflect.Proxy ● Proxy’s behaviour is determined by an implementation of java.lang.reflect.InvocationHandler
  • 66. Square peg in a non square hole Some object Some interface
  • 67. Fit it with an InvocationHandler Proxy Object public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
  • 68. public class MyInvocationHandler implements InvocationHandler { private Object delegate; public MyInvocationHandler(Object... params) { delegate = makeDelegate(); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); Class<?>[] types = method.getParameterTypes(); Method m = reachMethod(methodName, types); Object result; try { result = m.invoke(delegate, args); } catch (InvocationTargetException e) { throw e.getCause(); } return result; } private static Method reachMethod(String name, Class<?>... parTypes) { Method m = null; /* Logic to determine method */ return m; } private static Object makeDelegate(Object... params) { /* Produce real object instead */ return new Object(); } }
  • 69. Java agents ● Package java.lang.instrument - allow Java programming language agents to instrument programs running on the JVM. ● java ... -javaagent:jarpath[=options] ● Manifest attributes ● byte[] -> byte[]
  • 72. A planet, an icy atmosphere
  • 75. They deliver cheaper than the world, faster than the speed of thought
  • 76. The entrepreneurial spirit of that country
  • 77. Makes them sell the software to this country
  • 78. Where it fails spectacularly while clearly working in the other two ones
  • 80. Finds the culprit SimpleDateFormat frmt = new SimpleDateFormat("E MM/dd/yyyy"); SimpleDateFormat publicSimpleDateFormat(String pattern) Constructs a SimpleDateFormat using the given pattern and the default date format symbols for the default locale. Note: This constructor may not support all Locales. For full coverage, use the factory methods in the DateFormat class. Parameters: pattern - the pattern describing the date and time format Throws: NullPointerException - if the given pattern is null IllegalArgumentException - if the given pattern is invalid
  • 81. Could this have been avoided? Hindi (300×106, 4th) Shukravār LANG=de_DE.UTF-8 java -jar SimpleDateFormat.jar Freitag 11/16/2012 LANG=en_US.UTF-8 java -jar SimpleDateFormat.jar Friday 11/16/2012 LANG=hi_IN.UTF-8 java -jar SimpleDateFormat.jar शुकवार ११/१६/२०१२ LANG=bn_IN.UTF-8 java -jar SimpleDateFormat.jar Friday 11/16/2012 LANG=bg_BG.UTF-8 java -jar SimpleDateFormat.jar Петък 11/16/2012 Bengali (200×106, 7th) শুক্রার ্রব Shukrobar
  • 82. En Use Lo glis ca h le India proposes:
  • 83. USA retransmits: Use English Locale
  • 85. USA try in German: Verwenden Sie Englische Locale
  • 86. Germany says: Nein!
  • 88. Germany says: NEIN!
  • 89. USA checks what they said with Google translate:
  • 90. mv.visitMethodInsn(INVOKESPECIAL, "java/text/SimpleDateFormat", // "<init>", "(Ljava/lang/String;)V"); mv.visitFieldInsn(GETSTATIC, "java/util/Locale", // "US", "Ljava/util/Locale;"); mv.visitMethodInsn(INVOKESPECIAL, "java/text/SimpleDateFormat", // "<init>", "(Ljava/lang/String;Ljava/util/Locale;)V");
  • 92. import java.util.Random; public class I { public boolean singOutOfTune() { return new Random().nextBoolean(); } }
  • 93. import java.util.Random; public class I { public boolean singOutOfTune() { return new Random().nextBoolean(); } } public class You { public static String DID = "StandUp&WalkOutOnMe"; public static String DIDNOT = "LendMeAnEar"; public String wouldDo(boolean iF) { return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar"; } }
  • 94. import java.util.Random; public class I { public boolean singOutOfTune() { return new Random().nextBoolean(); } } public class You { public static String DID = "StandUp&WalkOutOnMe"; public static String DIDNOT = "LendMeAnEar"; public String wouldDo(boolean iF) { return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar"; } } public class ExistingClassesTest { @Test public void test1000times() { int times = 1000; do { boolean didI; I i = new I(); You you = new You(); String what = you.wouldDo(didI = i.singOutOfTune()); assertEquals(what, didI ? You.DID : You.DIDNOT); } while (--times > 0); } }
  • 95. import java.util.Random; public class I { public boolean singOutOfTune() { return new Random().nextBoolean(); } } public class You { public static String DID = "StandUp&WalkOutOnMe"; public static String DIDNOT = "LendMeAnEar"; public String wouldDo(boolean iF) { return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar"; } } public class ExistingClassesTest { @Test public void test1000times() { int times = 1000; do { boolean didI; I i = new I(); You you = new You(); String what = you.wouldDo(didI = i.singOutOfTune()); assertEquals(what, didI ? You.DID : You.DIDNOT); } while (--times > 0); // What would you do if I sang out of tune ? The Beatles } }
  • 96. public class SourceStrings { private SourceStrings() } public final static String I = " " + "import java.util.Random; " + "public class I { " + " public boolean singOutOfTune() { " + " return new Random().nextBoolean(); " + " } " + "} "; public final static String YOU = " " + "public class You { " + " public static String DID = "StandUp&WalkOutOnMe"; " + " public static String DIDNOT = "LendMeAnEar"; " + " public String wouldDo(boolean iF) { " + " return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar";" + " } " + "} "; } class StringSourceCodeObject extends SimpleJavaFileObject { final String _source; public StringSourceCodeObject(String fqName, String source) { super(URI.create("string:///" + fqName.replaceAll(".", "/") // + Kind.SOURCE.extension), Kind.SOURCE); _source = source; } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return _source; }
  • 97. public class CompilerAPI { public static void main(String args[]) throws Exception { /* Creating dynamic java source code file object */ JavaFileObject iObject = new StringSourceCodeObject("I", SourceStrings.I); JavaFileObject youObject = new StringSourceCodeObject("You", SourceStrings.YOU); JavaFileObject jfObjects[] = new JavaFileObject[]{iObject, youObject}; /* Units to compile */ Iterable<JavaFileObject> units = Arrays.asList(jfObjects); /* Instantiating the java compiler */ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); /* Get compiler file manager to show what to read. */ // (DEFAULT LISTENER, Locale.getDefault(), Charset.defaultCharset() ) JavaFileManager manager = compiler.getStandardFileManager(null, null, null); /* Compilation options - here: place in target directory */ String[] compileOptions = new String[]{"-d", "target/classes"}; Iterable<String> options = Arrays.asList(compileOptions); /* Diagnostic placeholder */ DiagnosticCollector<JavaFileObject> sink = new DiagnosticCollector<JavaFileObject>(); /* 1st null: where to write (default), 2nd null: no annotations processed */ CompilationTask task = compiler.getTask(null, manager, sink, options, null, units); /* Go, go, go */ boolean status = task.call(); if (!status) { for (Diagnostic<? extends JavaFileObject> d : sink.getDiagnostics()) { System.err.format("Error on line %d in %s", d.getLineNumber(), d); } } manager.close();// TRY to close the file manager } }
  • 98. public class CompilerAPITest { Object i; Object you; @BeforeClass public static void setUpClass() throws Exception { CompilerAPI.main(null); } @Before public void setUp() throws ReflectiveOperationException { i = Class.forName("I").newInstance(); you = Class.forName("You").newInstance(); } @After public void tearDown() { i = null; you = null; } @Test public void testMain() throws Exception { assertEquals(i.getClass().getName(), "I"); assertEquals(you.getClass().getName(), "You"); Method m1 = i.getClass().getMethod("singOutOfTune", (Class<?>[]) null); Object didI = m1.invoke(i, (Object[]) null); for (Method m2 : you.getClass().getMethods()) { if ("wouldDo".equals(m2.getName())) { Class<?>[] args = m2.getParameterTypes(); if (1 == args.length && args[0].isAssignableFrom(boolean.class)) { System.out.println("m2.invoke(you, didI)"); return; } } } fail("We did not find our method!"); }
  • 99. Some Links ● Code: https://github.com/alshopov/WriteBytecode ● Presentation: The presentation is to be improved.