What is the Weaver?

The Weaver adjusts the byte code of Entity classes such that JEMM can hook into the classes code and implement the storage behaviour. The transformations applied are completely transparent to the enhanced class code and does not change the behaviour in any way. You should not rely on the transformations always being the same as they change with each release but when using reflection these elements will be available.

Counter Example

The Counter example from the quickstart will be used as a starting example to show the main transformations. The class has two sycnhronised methods and a default a constructor that is empty and takes no parameters.

package com.test;

import org.sourceforge.jemm.Entity;

@Entity
public class Counter {
    private int count = 0;
        
    public synchronized void incrementCount() {
            count++;
    }
        
    public synchronized int getCount() {
        return count;
    }
}

Class signature changes

The class signature is changed to make the class implement a tag Interface. This interface does not contain any methods it just tells the rest of the program that the object has been JEMM Enhanced and works similar to the Serializable interface from the Java Object Serialization framework.

package com.test;

import org.sourceforge.jemm.Entity;
import org.sourceforge.jemm.util.JEMMObject;

public class Counter implements JEMMObject {

Field additions

The weaver introduces a single field into the object called jemmOIF. This field allows JEMM to access the core framework and it stores JEMM specific data such as the objects global ID.

package com.test;

import org.sourceforge.jemm.Entity;
import org.sourceforge.jemm.util.JEMMObject;
import org.sourceforge.jemm.lifecycle.ShadowUserObject;

public class Counter implements JEMMObject {

        protected ShadowUserObject jemmOIF;

Constructor Enhancement

The next transformation is the change to the default constructor. Here JEMM relies on the JVM specification and puts code before the super() call. The transformation puts a marker to the beginning and end of the constructor to allow it to introduce IDs and to finally store the object once its been created.

        public Counter() {
                ConstructorLifecycle.preConstructor(CounterTransformed.class.getName());
                super();
            ConstructorLifecycle.beginConstructor(this);
            try {
                this.count = 0;
                ConstructorLifecycle.endConstructor(this);
            } catch(Throwable t) {
                ConstructorLifecycle.failedConstructor(this);
                //would in the real program throw t not a RuntimeException
                throw t;
            }
        }

This constructor code wont actually compile using javac as it breaks the rules of the Java language. The first broken rule is that the preConstructor method call is made before the call to super(). That isn't allowed normally but it is allowed as part of the JVM specification. It might look like this call isn't necessary, and in this example it isn't, but in a hierarchy of model classes this call allows JEMM to only synchronise once on endConstructor calls rather than in every constructor, dramatically improving performance with deep hierarchies.

The second rule this breaks is the throw t; which would normally require the code to declare a "throws Throwable" as part of the constructor signature. This is not actually required by the JVM specification so JEMM doesn't need to change the signature and affect the application with the added annoyance of catching Throwable everywhere.

JEMM uses the various events (preConstructor, beginConstructor, endConstructor and failedConstructor) to determine the actions that need to be taken. These actions are context aware, not all calls to endConstructor save the object and not all beginConstructors assign an ID. These methods inter operate to make an object, give it an ID and store it if no exception is thrown in the normal constructor code.

Additional Constructors

The next transformation is the addition of a Constructor. This constructor allows JEMM objects to be recreated after they have been stored without rerunning the original constructor code. Rerunning the code would cause problems with new objects being created or variables being set to default values, which would be especially problematic with final variables.

      public CounterTransformed(ShadowUserObject jemmOIF) {
        this.jemmOIF = jemmOIF;
    }

Method Enhancement

The most important part of JEMM is the tracking of method entry and exit to save the objects state as the program runs without the need to call save.

All methods in a class are enhanced to tell JEMM when they started and when they finished as below.

    public void incrementCount() {
        jemmOIF.entityEntered(Counter.class.getName() + "#incrementCount ()V");
        jemmOIF.beginLock();
        try {
            count++;
        } finally {
            jemmOIF.endLock();
            jemmOIF.entityExited(Counter.class.getName() +"#incrementCount ()V");
        }
    }

The synchronized keyword is removed from the method and replaced by calls to beginLock and endLock. The original code is framed into a try/finally block ensuring the lock is always released and the entity saved.

The entityEntered and entityExit calls pass a Descriptor like string to the client libraries and this is used to generate complete stack knowledge for a particular thread. This information is converted into the right actions to save or load properties as not all method entries and exits translate into an object save.

The getCount method would similarly be changed with enter/exit and begin/end lock calls, which completes the transformations applied to this example class.

Other transformations

There are many more transformations that make up the Weaver, including replacement of the bytecode for synchronization blocks, other types of constructor changes and information about objects used by a method. The actual transformations are changing all the time and to get the full details check out the Java Docs under the package org.sourceforge.jemm.weaver.transformation.