• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content

Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Like this presentation? Why not share!

Java bytecode and classes

on

  • 4,672 views

 

Statistics

Views

Total Views
4,672
Views on SlideShare
4,672
Embed Views
0

Actions

Likes
7
Downloads
138
Comments
1

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

11 of 1 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Java bytecode and classes Java bytecode and classes Presentation Transcript

    • Playing with Java Classes and Bytecode
      What is a Class?
      How it is loaded and used?
      How to write a Java program that writes itself at runtime?
      YoavAbrahami
      Wix.com
    • Java Classloading
      Why do we care?
      Because if we’re gonna write code at runtime, we’d better know how to load and use it…
      Because we don’t really understand classes
      So… what identifies a class?
      Its name
      Its package
      Its classloader
      It means that
      We can have multiple instances of a class loaded at the same time
      Two instances of the same class from different classloaders are not compatible and not assignable
      Static variables are static only in the context of a classloader, not globally as we’re always told
    • Java Classloading
      So what is this classloader?
      A Java class (subclass of java.lang.ClassLoader), responsible for loading other classes used by the JVM
      Classloaders are arranged as a tree
      Bootstrap classloader
      Loads the Java system
      jre/lib/resources.jar – series of resource files
      jre/lib/rt.jar – the java.*, javax.*, etc packages
      jre/lib/sunrsasign.jar
      jre/lib/jsse.jar – secure socket extension
      jre/lib/jce.jar – Java cryptography extension
      jre/lib/charsets.jar
      jre/classes
      The important stuff is in rt.jar – the base Java classes
      Bootstrap classloader
      Ext classloader
      Application/ System classloader
    • Java Classloading
      Commandline Java App
      Tomcat (6)
      Bootstrap classloader
      Ext classloader
      Application/ System classloader
      Application/ System classloader
      Common classloader
      WAR 1
      classloader
      WAR 2
      classloader
    • Java Classloading
      Commandline Java App
      Tomcat (6)
      Bootstrap classloader
      Loads onlybootstrap.jar and tomcat-juli.jar
      Ext classloader
      Application/ System classloader
      Loads Tomcat commons library jars
      Loads the Application Jars from the classpath
      Application/ System classloader
      Common classloader
      Loads jars in the webapp lib directory
      WAR 1
      classloader
      WAR 2
      classloader
    • Lets talk business
      Ok, we understand classes. Where is the cool stuff?
    • What we’re gonna talk about
      Aspect Oriented Programming
      Java Proxy
      Spring Aspects
      AspectJ Aspects
      Doing the really cool stuff
      The bootstrap classloader
      The javaagent and class instrumentation
      Writing bytecode at runtime
      All in context of when I’ve had to use them
    • The Java Proxy
      What does it do?
      Allows implementing one or more interfaces dynamically
      When do we use it?
      Generic implementation of an interface – such as in the case of a client calling a service. The client uses an interface with a generic implementation that marshals the method calls to whatever “on-the-wire” format. For instance, creating a SOAP client on the fly using an interface and WSDL
      Simplistic AOP – to catch method calls, perform some pre/post/around logic and delegate the call to the real implementation. Can be used for transaction handling, logging, etc.
      Limitations
      Only supports Java interfaces
      Intercepts only calls to the proxy instance. Direct calls to the delegate will not be intercepted (for instance, a call from one delegate method to another)
    • The Java Proxy
      Example code
      public interface SomeInterface{
      public void doSomething();
      public void doAnotherThing(String name);
      }
      Object p = Proxy.newProxyInstance(this.getClass().getClassLoader(),
      new Class<?>[]{SomeInterface.class},new InvocationHandler() {
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
      System.out.println("invoking method:" + method.getName());
      if (args!= null)
      for (Object arg: args)
      System.out.println(" arg: " + arg);
      return null;
      }
      });
      SomeInterface s = (SomeInterface)p;
      s.doSomething();
      s.doAnotherThing("hello");
    • Spring AOP
      What does it do?
      Allows intercepting method calls to Spring beans, with or without an interface
      Simpler code compared to the Java Proxy
      Based on the proxy model – Spring BeanFactory returns a proxy to the real bean
      Supports choosing the methods to intercept using AspectJ selectors
      Aspects are written using the AspectJ Java syntax
      When do we use it?
      AOP on Spring beans
      Transaction handling, logging, security handling – anything AOP is good for
      Limitations
      Only supports Spring beans
      Intercepts only calls to the proxy instance. Direct calls to the delegate will not be intercepted (for instance, a call from one delegate method to another)
      Supports only a subset of AspectJ selectors
    • Spring AOP
      Configuring Spring AOP
      Example Aspect
      Activating the Aspect
      Using Spring component scan, by adding the @Component annotation on the aspect
      Using Spring Beans XML
      <aop:aspectj-autoproxy/>
      @Aspect
      public class ExampleAspect{
      @Around("@annotation(com.experiments.RequireLogin)")
      public Object around(ProceedingJoinPointjoinPoint) throws Throwable
      {
      ...
      }
      }
      <bean class="com.experiments.ExampleAspect"/>
    • AspectJ
      What does it do?
      Allows intercepting any JoinPoint such as method calls, exceptions, etc.
      Supports writing aspects using Java or AspectJ syntax
      Modifies the actual class bytecode
      Supports choosing the methods to intercept using AspectJ selectors
      Modify existing classes, adding methods, members and super-interfaces to them
      Weaves aspects on load time or compile time
      When do we use it?
      AOP on any Java class
      Transaction handling, logging, security – anything AOP is good for
      Introduce compiler-like coding rules
      Limitations
      For compile-time weaving – replaces the standard Java Compiler
      For load-time weaving – requires elaborate JVM configuration
    • AspectJ
      Configuration options
      Compile-time weaving
      Load-time weaving
      Load-time weaving with Spring
      Dependencies
      aspectjrt.jar must be in the classpath
      Configuring AspectJ load-time weaving with Spring
      Simple, isn’t it?
      Well, not so simple…
      <aop:aspectj-autoproxy/>
      <context:load-time-weaver/>
    • AspectJ
      Need to include META-INF/aop.xml
      declares the aspects for load-time weaving and the target packages to weave into
      <!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
      <aspectj>
      <weaver>
      <!-- only any class from the com.experiments package -->
      <include within="com.experiments..*"/>
      </weaver>
      <aspects>
      <!-- weave in just this aspect -->
      <aspect name="com.experiments.ExampleAspect"/>
      </aspects>
      </aspectj>
    • AspectJ
      Per-platform configuration for class instrumentation
      Command line & JUnit applications – using the -javaagent to load instrumentation jars
      -javaagent:spring-instrument-<version>.jar -javaagent:aspectjweaver-<version>.jar
      Maven running JUnit – using the maven-surefire-plugin, passing it the javaagentargs
      Note the two javaagentparams must be at the same line
      Tomcat 6 –
      spring-instrument-tomcat-<version>.jar has to be copied to the Tomcat lib directory
      The webapp must have a context.xml file in WEB-INFcontent.xml, with the minimum content
      There are alternative locations for the context file. This is the location I find easiest to use.
      <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-plugin</artifactId>
      <version>2.6</version>
      <configuration>
      <forkMode>once</forkMode>
      <argLine> -javaagent:"${settings.localRepository}/org/springframework/spring- instrument/${org.springframework.version}/spring-instrument-
      ${org.springframework.version}.jar" -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/
      ${org.aspectj.version}/aspectjweaver-${org.aspectj.version}.jar" </argLine>
      <useSystemClassLoader>true</useSystemClassLoader>
      </configuration>
      </plugin>
      <Context path="/">
      <Loader loaderClass="org.springframework.instrument.classloading.tomcat.
      TomcatInstrumentableClassLoader"/>
      </Context>
    • Aspectj 101
      As long as we’re talking about aspects…
    • AOP 101 – AspectJ Style
      Aspect – a concern that cuts across multiple classes. Examples are logging, transaction handling, security, etc.
      Join Point – a point during the execution of a program. Examples are when
      A method is executed
      A method is called
      A constructor is executed
      A constructor is called
      An exception handler is executed
      An advice is executed
      Static initialization is executed
      Initialization and pre-initialization of an object
      Advice – an action taken by the aspect at a particular pointcut. Types of advice:
      Before, after returning, after throwing, after finally, around
      Pointcut – a selector of Join Points using predicates. An advice is associated with a pointcut expression and runs on any point matched by the pointcut
    • AOP 101 – AspectJ Style
      More on pointcuts
      Pointcuts are query expressions on the code
      May be joined using the and (‘&&’), or (‘||’) or not (‘!’) operators
      Some pointcut predicates
      execution(…) – when a particular method body executes
      call(…) – when a method is called
      handler(….) – when a particular exception handler executes
      this(…) – when the currently executing object is of a certain type
      target(…) – when the target object is of type
      args(…) – when the method arguments match a certain type
      within(…) – when the executing code belongs to a certain class
      cflow(…) – when the program flow is in a certain method call (the method is a parent in the stack)
      @annotation(…) – methods annotated with a certain annotation
      @target(…) – when the target executing object has a certain annotation
      @args(…) – when the runtime type of an argument has a certain annotation
      @within(…) – limits to pointcuts within a class that has a certain annotation
      bean(…) – a spring bean name
    • AOP 101 – AspectJ Style
      More on pointcuts
      Pointcuts are query expressions on the code
      May be joined using the and (‘&&’), or (‘||’) or not (‘!’) operators
      Some pointcut predicates
      execution(…) – when a particular method body executes
      call(…) – when a method is called
      handler(….) – when a particular exception handler executes
      this(…) – when the currently executing object is of a certain type
      target(…) – when the target object is of type
      args(…) – when the method arguments match a certain type
      within(…) – when the executing code belongs to a certain class
      cflow(…) – when the program flow is in a certain method call (the method is a parent in the stack)
      @annotation(…) – methods annotated with a certain annotation
      @target(…) – when the target executing object has a certain annotation
      @args(…) – when the runtime type of an argument has a certain annotation
      @within(…) – limits to pointcuts within a class that has a certain annotation
      bean(…) – a spring bean name
      Not Supported by Spring AOP
      Only Spring AOP
    • AOP 101 – AspectJ Style
      Some examples
      execution (int *())
      JoinPoints that are integer-returning method executions that do not take parameters
      @annotation(com.example.Log) && execution(* *(..))
      JoinPoints that are executions of methods annotated with the @Log annotation, regardless of the method return type, class, name or parameters
      call(public * *(..))
      Call to any public method
      !this(Point) && call(int*(..))
      Any call to a method returning an integer when the executing object is of any type other than Point
      cflow(P) && cflow(Q)
      All JoinPointthat are both in the control flow of P and in the control flow of Q
    • AOP 101 – AspectJ Style
      Coding Aspects using AspectJ Java Syntax
      The AspectJ syntax
      @Aspect
      public class MyAspect{
      @Pointcut("within(com.springsource..*)")
      public void inSpring() {}
      @Pointcut("@Annotation(java.lang.Deprecated)")
      public void inDepracated() {}
      @Pointcut("inSpring() && inDepracated()")
      public void deprecatedInSpring() {}
      @Before("deprecatedInSpring()")
      public void pointcutRef() {
      ...
      }
      @Before("within(com.springsource..*) && @Annotation(java.lang.Deprecated)")
      public void pointcutInplace() {
      ...
      }
      }
      aspect A {
      pointcutfooPC(): execution(void Test.foo());
      pointcutgooPC(): execution(void Test.goo());
      pointcutprintPC(): call(void java.io.PrintStream.println(String));
      before(): cflow(fooPC()) && cflow(gooPC()) && printPC() && !within(A) {
      System.out.println("should occur");
      }
      }
    • AOP 101 – AspectJ Style
      Adding code to existing classes using aspects (Inter-type declarations)
      Adding implemented interfaces
      Changing the superclass of a class
      Adding methods to a class
      Adding members to a class
      Implement Mix-ins in Java
      Using Join Points to raise custom compiler errors or warnings
      Privileged aspects
      Can access private, package and protected members of classes, bypassing the java member visibility constraints
    • AOP 101 – AspectJ Style
      Example of an aspect modifying a class
      public class Point {
      intx, y;
      public void setX(intx) { this.x= x; }
      public void setY(inty) { this.y= y; }
      public static void main(String[] args) {
      Point p = new Point();
      p.setX(3);
      p.setY(333);
      }
      }
      aspect PointAssertions {
      private booleanPoint.assertX(intx) { return (x <= 100 && x >= 0); }
      private booleanPoint.assertY(inty) { return (y <= 100 && y >= 0); }
      before(Point p, intx): target(p) && args(x) && call(void setX(int)) {
      if (!p.assertX(x)) {
      System.out.println("Illegal value for x");
      return;
      }
      }
      before(Point p, inty): target(p) && args(y) && call(void setY(int)) {
      if (!p.assertY(y)) {
      System.out.println("Illegal value for y");
      return;
      }
      }
      }
    • Back to the cool stuff
    • The bootstrap classloader
      What does it do?
      Allows replacing Java system classes
      Bypasses all Java security policies set by SecurityManager
      When do we use it?
      Meddling with the core Java APIs
      Terracotta uses it to replace the Java HashMap class with a distributed cache implementation
      Limitations
      Classes loaded by the bootstrap classloader can’t load classes that are not included in the bootstrap classpath
      Usage
      With the Java command line options
      –bootclasspath: - list of jars to use instead of the standard list
      –bootclasspath/a: - list of jars to append to the standard list
      –bootclasspath/p: - list of jars to prepend to the standard list
    • Javaagentand Instrument
      What does it do?
      Allows instrumenting / transforming / changing a class as it is loaded
      When do we use it?
      AspectJ uses it for load-time weaving
      To modify classes as we load them
      Limitations
      Works on the class file bytes – requires intimate knowledge of the class file structure
      Not very useful without a framework like AspectJ, BCEL, cglib, etc.
      Usage
      Using the –javaagent command line option to introduce an Agent jar
      The Agent jar has to have a premain method
      publicstaticvoidpremain(String agentArguments, Instrumentation instrumentation)
      The Instrumentation class allows to redefine a class, add & remove transformers, and re-transform a class.
      ClassFileTransformer has one method to transform a class file bytes (as byte[]).
    • Writing Bytecode
      What does it do?
      Write new classes or modify existing classes at runtime
      Load the new/modified classes
      Instantiate them
      Use them as any other Java class
      When do we use it?
      Implementing Proxies on any class – Spring AOP and Hibernate do just that
      Hibernate uses bytecode manipulations of classes to introduce mechanisms for lazy-loading of members
      My own experience
      Performance – when a mapping library (in my case XML to objects) was too slow due to excessive use of reflection, coding simple mapping classes proved much faster
      Adaptor for Beans – a reporting framework used reflection on beans to read the field definitions from a JavaObjectdatasource. When adapting a Java query interface that returns map-like objects, we had to generate wrapper classes adapting the map to the beans the framework expected.
    • Writing Bytecode
      Limitations
      Hard to use
      Generated bytecode cannot be debugged normally – there’s no source code 
      BCEL – I’ve found using BCEL to be the easiest
      BCEL is included with JRE 1.6
      In package com.sun.org.apache.bcel
      However, the JRE version didn’t work for me
      Eventually, I’ve used the Apache version – BCEL 5.2
      Guidelines
      Keep the generated code small. Use helper methods / superclasses whenever you can. Remember, you can debug helper classes or superclasses, but you can’t debug generated bytecode
      Classes can be generated at build-time or runtime. I’ve found runtime generation simpler to use
      Use class generation-by-example
    • Writing Bytecode
      Code generation or bytecode generation?
      Code generation
      Performed at build-time - inputs to the generation process must be available at build time
      Easier to debug
      Tends to clutter the project source code
      Code-generation code tends to be longer than bytecode-generation code
      Hard to get the build right – separation of generated code from actual code
      Bytecode generation
      Performed at runtime – inputs to the generation process can be resolved at runtime
      Requires a higher skill level
      More complex to debug
      At the philosophical level
      If it can be generated, it’s not code!
      We’re just configuring the JVM, not coding
    • Writing Bytecode
      Class generation-by-example
      Write an example class of what you want to generate
      Compile it
      Run org.apache.bcel.util.BCELifier. It generates a factory class that generates your example class bytecode
      Modify the generated factory class so that it generates the bytecode for the classes you want
      Use a bytecode verifier to verify the generated classes
      Decompile generated files and verify method logic. I recommend that you set the "annotate" option so you can see the bytecode instruction as comments.
      BCEL also provides a tool to generate HTML documentation for your example class bytecode
      Class loading
      Code a new subclass of ClassLoader
      Use the defineClass (protected) method to define the new generated class
      Remember to link your classloader to a parent classloader
    • Writing Bytecode
      Example – mapping objects from type A to type B
      Using a superclass helper
      public abstract class BaseMapper{
      protected Object a;
      protected Object b;
      public BaseMapper(Object a, Object b) {
      this.a= a;
      this.b= b;
      }
      public abstract Object mapToB(Object a);
      public abstract Object mapToA(Object b);
      }
      The example class
      public class ExampleMappedClassextends BaseMapper{
      public ExampleMappedClass(Person person, PersonDTOpersonDTO) {
      super(person, personDTO);
      }
      @Override
      public PersonDTOmapToB(Object a) {
      Person person= (Person)a;
      PersonDTOpersonDTO= new PersonDTO();
      personDTO.name = person.name;
      personDTO.lastName= person.lastName;
      personDTO.id = Integer.toString(person.id);
      return personDTO;
      }
      @Override public Person mapToA(Object b) {
      PersonDTOpersonDTO= (PersonDTO)b;
      Person person= new Person();
      person.name = personDTO.name;
      person.lastName= personDTO.lastName;
      person.id = Integer.parseInt(personDTO.id);
      return person;
      }
      }
    • Writing Bytecode
      Running BCELifier on the class
      BCELifier has a main method, accepting one parameter – the class name
      The created factory class
      Defining the class and the class members
      public class ExampleMappedClassCreatorimplements Constants {
      private InstructionFactory _factory;
      private ConstantPoolGen _cp;
      private ClassGen _cg;
      public ExampleMappedClassCreator() {
      _cg = new ClassGen("com.experiments.ExampleMappedClass","com.experiments.BaseMapper",
      "ExampleMappedClass.java", ACC_PUBLIC | ACC_SUPER, new String[] { });
      _cp= _cg.getConstantPool();
      _factory = new InstructionFactory(_cg, _cp);
      }
      public void create(OutputStreamout) throwsIOException{
      createMethod_0();
      createMethod_1();
      createMethod_2();
      createMethod_3();
      createMethod_4();
      _cg.getJavaClass().dump(out);
      }
      ...
    • Writing Bytecode
      Creating the Factory class (continued)
      Creating the constructor
      Which generates bytecode for the constructor
      private void createMethod_0() {
      InstructionListil= new InstructionList();
      MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, new Type[] {
      new ObjectType("com.experiments.Person"),
      new ObjectType("com.experiments.PersonDTO") },
      new String[] { "arg0", "arg1" },
      "<init>", "com.experiments.ExampleMappedClass", il, _cp);
      InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0));
      il.append(_factory.createLoad(Type.OBJECT, 1));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createInvoke("com.experiments.BaseMapper", "<init>",
      Type.VOID, new Type[] { Type.OBJECT, Type.OBJECT}, Constants.INVOKESPECIAL));
      InstructionHandle ih_6 = il.append(_factory.createReturn(Type.VOID));
      method.setMaxStack();
      method.setMaxLocals();
      _cg.addMethod(method.getMethod());
      il.dispose();
      }
      public ExampleMappedClass(Person person, PersonDTOpersonDTO) {
      super(person, personDTO);
      }
    • public PersonDTOmapToB(Object a) {
      Person person= (Person)a;
      PersonDTOpersonDTO= new PersonDTO();
      personDTO.name = person.name;
      personDTO.lastName= person.lastName;
      personDTO.id = Integer.toString(person.id);
      return personDTO;
      }
      private void createMethod_1() {
      InstructionListil= new InstructionList();
      MethodGen method = new MethodGen(ACC_1PUBLIC, new ObjectType("com.experiments.PersonDTO"),
      new Type[] { Type.OBJECT}, new String[] { "arg0" },"mapToB", "com.experiments.ExampleMappedClass", il, _cp);
      InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 1));
      il.append(_factory.createCheckCast(new ObjectType("com.experiments.Person")));
      il.append(_factory.createStore(Type.OBJECT, 2));
      InstructionHandle ih_5 = il.append(_factory.createNew("com.experiments.PersonDTO"));
      il.append(InstructionConstants.DUP);
      il.append(_factory.createInvoke("com.experiments.PersonDTO", "<init>", Type.VOID, Type.NO_ARGS,
      Constants.INVOKESPECIAL));
      il.append(_factory.createStore(Type.OBJECT, 3));
      InstructionHandle ih_13 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "name", Type.STRING, Constants.GETFIELD));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "name", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_21 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "lastName", Type.STRING, Constants.GETFIELD));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "lastName", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_29 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "id", Type.INT, Constants.GETFIELD));
      il.append(_factory.createInvoke("java.lang.Integer", "toString", Type.STRING, new Type[] { Type.INT },
      Constants.INVOKESTATIC));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "id", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_40 = il.append(_factory.createLoad(Type.OBJECT, 3));
      InstructionHandle ih_41 = il.append(_factory.createReturn(Type.OBJECT));
      method.setMaxStack();
      method.setMaxLocals();
      _cg.addMethod(method.getMethod());
      il.dispose();
      }
      Writing Bytecode
      Creating the Factory class (continued)
      Creating the mapToB method
    • public PersonDTOmapToB(Object a) {
      Person person= (Person)a;
      PersonDTOpersonDTO= new PersonDTO();
      personDTO.name = person.name;
      personDTO.lastName= person.lastName;
      personDTO.id = Integer.toString(person.id);
      return personDTO;
      }
      Writing Bytecode
      Creating the Factory class (continued)
      Creating the mapToB method
      public
      Return type
      private void createMethod_1() {
      InstructionListil= new InstructionList();
      MethodGen method = new MethodGen(ACC_1PUBLIC, new ObjectType("com.experiments.PersonDTO"),
      new Type[] { Type.OBJECT}, new String[] { "arg0" },"mapToB", "com.experiments.ExampleMappedClass", il, _cp);
      InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 1));
      il.append(_factory.createCheckCast(new ObjectType("com.experiments.Person")));
      il.append(_factory.createStore(Type.OBJECT, 2));
      InstructionHandle ih_5 = il.append(_factory.createNew("com.experiments.PersonDTO"));
      il.append(InstructionConstants.DUP);
      il.append(_factory.createInvoke("com.experiments.PersonDTO", "<init>", Type.VOID, Type.NO_ARGS,
      Constants.INVOKESPECIAL));
      il.append(_factory.createStore(Type.OBJECT, 3));
      InstructionHandle ih_13 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "name", Type.STRING, Constants.GETFIELD));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "name", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_21 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "lastName", Type.STRING, Constants.GETFIELD));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "lastName", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_29 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "id", Type.INT, Constants.GETFIELD));
      il.append(_factory.createInvoke("java.lang.Integer", "toString", Type.STRING, new Type[] { Type.INT },
      Constants.INVOKESTATIC));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "id", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_40 = il.append(_factory.createLoad(Type.OBJECT, 3));
      InstructionHandle ih_41 = il.append(_factory.createReturn(Type.OBJECT));
      method.setMaxStack();
      method.setMaxLocals();
      _cg.addMethod(method.getMethod());
      il.dispose();
      }
      Input arguments
      Input argument names
      Method name
      Class name
    • public PersonDTOmapToB(Object a) {
      Person person= (Person)a;
      PersonDTOpersonDTO= new PersonDTO();
      personDTO.name = person.name;
      personDTO.lastName= person.lastName;
      personDTO.id = Integer.toString(person.id);
      return personDTO;
      }
      private void createMethod_1() {
      InstructionListil= new InstructionList();
      MethodGen method = new MethodGen(ACC_1PUBLIC, new ObjectType("com.experiments.PersonDTO"),
      new Type[] { Type.OBJECT}, new String[] { "arg0" },"mapToB", "com.experiments.ExampleMappedClass", il, _cp);
      InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 1));
      il.append(_factory.createCheckCast(new ObjectType("com.experiments.Person")));
      il.append(_factory.createStore(Type.OBJECT, 2));
      InstructionHandle ih_5 = il.append(_factory.createNew("com.experiments.PersonDTO"));
      il.append(InstructionConstants.DUP);
      il.append(_factory.createInvoke("com.experiments.PersonDTO", "<init>", Type.VOID, Type.NO_ARGS,
      Constants.INVOKESPECIAL));
      il.append(_factory.createStore(Type.OBJECT, 3));
      InstructionHandle ih_13 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "name", Type.STRING, Constants.GETFIELD));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "name", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_21 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "lastName", Type.STRING, Constants.GETFIELD));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "lastName", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_29 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "id", Type.INT, Constants.GETFIELD));
      il.append(_factory.createInvoke("java.lang.Integer", "toString", Type.STRING, new Type[] { Type.INT },
      Constants.INVOKESTATIC));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "id", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_40 = il.append(_factory.createLoad(Type.OBJECT, 3));
      InstructionHandle ih_41 = il.append(_factory.createReturn(Type.OBJECT));
      method.setMaxStack();
      method.setMaxLocals();
      _cg.addMethod(method.getMethod());
      il.dispose();
      }
      Writing Bytecode
      Creating the Factory class (continued)
      Creating the mapToB method
      Take Object 1 – the a parameter
      (Object 0 is this)
      Cast it to Person
      Store the result as Object 2
    • public PersonDTOmapToB(Object a) {
      Person person= (Person)a;
      PersonDTOpersonDTO= new PersonDTO();
      personDTO.name = person.name;
      personDTO.lastName= person.lastName;
      personDTO.id = Integer.toString(person.id);
      return personDTO;
      }
      private void createMethod_1() {
      InstructionListil= new InstructionList();
      MethodGen method = new MethodGen(ACC_1PUBLIC, new ObjectType("com.experiments.PersonDTO"),
      new Type[] { Type.OBJECT}, new String[] { "arg0" },"mapToB", "com.experiments.ExampleMappedClass", il, _cp);
      InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 1));
      il.append(_factory.createCheckCast(new ObjectType("com.experiments.Person")));
      il.append(_factory.createStore(Type.OBJECT, 2));
      InstructionHandle ih_5 = il.append(_factory.createNew("com.experiments.PersonDTO"));
      il.append(InstructionConstants.DUP);
      il.append(_factory.createInvoke("com.experiments.PersonDTO", "<init>", Type.VOID, Type.NO_ARGS,
      Constants.INVOKESPECIAL));
      il.append(_factory.createStore(Type.OBJECT, 3));
      InstructionHandle ih_13 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "name", Type.STRING, Constants.GETFIELD));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "name", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_21 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "lastName", Type.STRING, Constants.GETFIELD));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "lastName", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_29 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "id", Type.INT, Constants.GETFIELD));
      il.append(_factory.createInvoke("java.lang.Integer", "toString", Type.STRING, new Type[] { Type.INT },
      Constants.INVOKESTATIC));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "id", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_40 = il.append(_factory.createLoad(Type.OBJECT, 3));
      InstructionHandle ih_41 = il.append(_factory.createReturn(Type.OBJECT));
      method.setMaxStack();
      method.setMaxLocals();
      _cg.addMethod(method.getMethod());
      il.dispose();
      }
      Writing Bytecode
      Creating the Factory class (continued)
      Creating the mapToB method
      Create new PersonDTO
      Invoke the personDTO constructor
      Store the result as Object 3
    • public PersonDTOmapToB(Object a) {
      Person person= (Person)a;
      PersonDTOpersonDTO= new PersonDTO();
      personDTO.name = person.name;
      personDTO.lastName= person.lastName;
      personDTO.id = Integer.toString(person.id);
      return personDTO;
      }
      private void createMethod_1() {
      InstructionListil= new InstructionList();
      MethodGen method = new MethodGen(ACC_1PUBLIC, new ObjectType("com.experiments.PersonDTO"),
      new Type[] { Type.OBJECT}, new String[] { "arg0" },"mapToB", "com.experiments.ExampleMappedClass", il, _cp);
      InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 1));
      il.append(_factory.createCheckCast(new ObjectType("com.experiments.Person")));
      il.append(_factory.createStore(Type.OBJECT, 2));
      InstructionHandle ih_5 = il.append(_factory.createNew("com.experiments.PersonDTO"));
      il.append(InstructionConstants.DUP);
      il.append(_factory.createInvoke("com.experiments.PersonDTO", "<init>", Type.VOID, Type.NO_ARGS,
      Constants.INVOKESPECIAL));
      il.append(_factory.createStore(Type.OBJECT, 3));
      InstructionHandle ih_13 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "name", Type.STRING, Constants.GETFIELD));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "name", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_21 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "lastName", Type.STRING, Constants.GETFIELD));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "lastName", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_29 = il.append(_factory.createLoad(Type.OBJECT, 3));
      il.append(_factory.createLoad(Type.OBJECT, 2));
      il.append(_factory.createFieldAccess("com.experiments.Person", "id", Type.INT, Constants.GETFIELD));
      il.append(_factory.createInvoke("java.lang.Integer", "toString", Type.STRING, new Type[] { Type.INT },
      Constants.INVOKESTATIC));
      il.append(_factory.createFieldAccess("com.experiments.PersonDTO", "id", Type.STRING, Constants.PUTFIELD));
      InstructionHandle ih_40 = il.append(_factory.createLoad(Type.OBJECT, 3));
      InstructionHandle ih_41 = il.append(_factory.createReturn(Type.OBJECT));
      method.setMaxStack();
      method.setMaxLocals();
      _cg.addMethod(method.getMethod());
      il.dispose();
      }
      Writing Bytecode
      Creating the Factory class (continued)
      Creating the mapToB method
      Load object 3 to the stack - Person
      Load object 2 to the stack - PersonDTO
      Read the name field from object 2 to the stack
      Pop the stack, writing the value to the name property of object 3
    • Writing Bytecode
      Creating the Factory class (continued)
      Creating the mapToB method – we got a second mapToB method
      The first has signature PersonDTOmapToB(Object)
      The second has signature Object mapToB(Object)
      The second overrides the superclass mapToB method and calls the first
      Narrowing the return type of mapToB was apparently not a good idea, given that generated classes loaded at runtime do not benefit from the narrowed type constraint
      private void createMethod_4() {
      InstructionListil= new InstructionList();
      MethodGen method = new MethodGen(ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC, Type.OBJECT,
      new Type[] { Type.OBJECT},new String[] { "arg0" }, "mapToB",
      "com.experiments.ExampleMappedClass", il, _cp);
      InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0));
      il.append(_factory.createLoad(Type.OBJECT, 1));
      il.append(_factory.createInvoke("com.experiments.ExampleMappedClass", "mapToB",
      new ObjectType("com.experiments.PersonDTO"), new Type[] { Type.OBJECT}, Constants.INVOKEVIRTUAL));
      InstructionHandle ih_5 = il.append(_factory.createReturn(Type.OBJECT));
      method.setMaxStack();
      method.setMaxLocals();
      _cg.addMethod(method.getMethod());
      il.dispose();
      }
    • Writing Bytecode
      class MyClassLoaderextends ClassLoader{
      MyClassLoader(ClassLoader parent) {
      super(parent);
      }
      public void defineClass(JavaClassjavaClass) {
      byte[] classBytes= javaClass.getBytes();
      defineClass(javaClass.getClassName(), classBytes, 0, classBytes.length);
      }
      }
      public JavaClass create() {
      createMethod_0();
      createMethod_1();
      createMethod_2();
      createMethod_3();
      createMethod_4();
      return _cg.getJavaClass();
      }
      MyClassLoadermyClassLoader= new MyClassLoader(this.getClass().getClassLoader());
      ExampleMappedClassCreator creator = new ExampleMappedClassCreator();
      JavaClassjavaClass= creator.create();
      myClassLoader.defineClass(javaClass);
      Class<?> clazz= myClassLoader.loadClass(javaClass.getClassName());
      Constructor<?> constructor = clazz.getConstructor(Person.class, PersonDTO.class);
      BaseMapper mapper = (BaseMapper)constructor.newInstance(new Person(), new PersonDTO());
      Using the generated class
      The Class loader
      Creating and loading the new class
      Add a method returning JavaClass to the factory class
      And use it
    • Writing Bytecode
      class MyClassLoaderextends ClassLoader{
      MyClassLoader(ClassLoader parent) {
      super(parent);
      }
      public void defineClass(JavaClassjavaClass) {
      byte[] classBytes= javaClass.getBytes();
      defineClass(javaClass.getClassName(), classBytes, 0, classBytes.length);
      }
      }
      Using the generated class
      The Class loader
      Creating and loading the new class
      Add a method returning JavaClass to the factory class
      And use it
      Create the classloader
      Create the class factory
      Create the class bytecode
      public JavaClass create() {
      createMethod_0();
      createMethod_1();
      createMethod_2();
      createMethod_3();
      createMethod_4();
      return _cg.getJavaClass();
      }
      Define the new class
      Load the new class
      Get the new class constructor
      Call the constructor
      MyClassLoadermyClassLoader= new MyClassLoader(this.getClass().getClassLoader());
      ExampleMappedClassCreator creator = new ExampleMappedClassCreator();
      JavaClassjavaClass= creator.create();
      myClassLoader.defineClass(javaClass);
      Class<?> clazz= myClassLoader.loadClass(javaClass.getClassName());
      Constructor<?> constructor = clazz.getConstructor(Person.class, PersonDTO.class);
      BaseMapper mapper = (BaseMapper)constructor.newInstance(new Person(), new PersonDTO());
    • It is that simple 