Did you know? DZone has great portals for Python, Cloud, NoSQL, and HTML5!

Alex is a software developer at iBASEt working on a large manufacture execution system. His interests include Java technologies, Math, distributed graph databases. Also he is a founder of Seambase where he works on software artifact mining tools. Alex has posted 1 posts at DZone. View Full User Profile

Dynamic subtyping in Java

10.20.2011
Email
Views: 2996
  • submit to reddit

Subtyping Issues in Java

Behavior customization is a common requirement for large software systems. A software product cannot fully satisfy requirements of all customers; there are always differences that must be implemented, which are specific to each customer. Thus, software products must be flexible enough to allow these customizations in behavior even without changes in product's source code.

In Java-based software products, a solution for such problems is usually based on a principle called subtyping. Subtyping can be defined on an example of two types A and B: if type B is a subtype of type A, then all code that operates correctly on objects of type A will operate correctly on objects of type B. Naturally, a software product behavior can be customized by replacing some default class A with custom class B where B is a subtype of A.

If subtyping is based on an interface, then implementations of the interface can be independent of each other, which decreases complexity of the system and benefits modularity. At the same time such independence limits code reusability. A custom implementation can use Delegation pattern to call methods, but it is impossible to override a method in the base class.

Another approach for subtyping is direct subclassing of the implementation class. Subclassing allows method overriding in the base class and also introduces design-time dependencies on that class. These dependencies limit subclass reusability.

As you can see standard Java subtyping techniques limit reusability of either a base class or a subclass.

Dynamic subtyping

The approach described below combines the advantages of standard Java subtyping techniques. It allows creation of a new class, which can override methods in an original class, but at the same time, is dependent only on the interface of the original.

Let's start with the following example:
 
Suppose we have an interface Action as described below and its implementation in form of class ActionImpl.

//This is an interface of Action
public interface Action{
void doAction1();
void doAction2();
void doAll();
}

//This is a default implementation of the interface Action
class ActionImpl implements Action{
public void doAction1(){ ... }
public void doAction2(){ ... }
public void doAll(){
doAction1();
doAction2();
}
}

Class ActionImpl implements all methods of the interface and is used as a default implementation.
Now let's suppose we want to override method doAction2 in the ActionImpl in such a way that the new class won't depend on ActionImpl.
Let's create a new class ActionExtension as the following:

//This is a custom implementation that overrides one method.
abstract class ActionExtension extends ImplementationOf<Action> implements Action{
public void doAction2(){

Super.doAction2();
}
}
This class extends a simple base class which looks like this:

//This is  base class for dynamic subclasses
public abstract class ImplementationOf<T>{
/**
* A field for calling super class methods.
* Should be used only in expressions where super keyword can be used.
* */
protected final T Super = null;
}
Note that ActionExtension class is an abstract class, so we don't have to define all methods, just those that we want to override in ActionImpl.
That's all we need to do at design time. Now let's look how it works at run-time.

At the point of code where instance of Action is expected we need to create a new class:

//Fragment of code that creates dynamic subclass of ActionImpl
Class dynamicSubclass = DynamicClassExtender.extend(ActionImpl.class, Action.class, ActionExtension.class);
The created class is a subclass of ActionImpl and contains all methods copied from ActionExtension class and modified in such a way that all calls to methods of Super field are directed to ActionImpl class. This class can be used to create an instance which can be used instead of instance of ActionImpl class:

Action action = (Action) dynamicSubclass.newInstance();
In the real product the code above should be integrated into a dependency injection framework of your choice, and actual mapping of extension classes to implementations should be configurable.

Dynamic class extender

From the previous chapter we saw that all the complexities of dynamic subclassing are hidden in DynamicClassExtender class, which uses a byte code manipulation library to create a direct subclass of ActionImpl from ActionExtension class. In order to see what kind of byte code manipulation is involved let's start with ActionExtender class decompiled using standard javap utility:

public abstract class ActionExtension extends ImplementationOf implements Action{
public ActionExtension();
Code:
0: aload_0
1: invokespecial #10; //Method ImplementationOf."<init>":()V
4: return

public void doAction2();
Code:
0: aload_0
1: getfield #17; //Field Super:Ljava/lang/Object;
4: checkcast #5; //class Action
7: invokeinterface #21, 1; //InterfaceMethodAction.doAction2:()V
12: return

}
Now if we manually create a class that extends ActionImpl and overrides doAction2 method and then decompile it with javap we'll see the following byte code:

public class ActionExtension$ActionImpl extends ActionImpl{
public ActionExtension$ActionImpl();
Code:
0: aload_0
1: invokespecial #8; //Method ActionImpl."<init>":()V
4: return

public void doAction2();
Code:
0: aload_0
1: invokespecial #15; //Method ActionImpl.doAction2:()V
4: return

}
After comparing byte codes from both classes we can figure out a list of manipulations that DynamicClassExtender must apply on ActionExtension class in order to create a dynamic subclass of ActionImpl:
  • change class name to ActionExtension$ActionImpl
  • change access attribute to public, remove abstract attribute
  • change super class name to ActionImpl
  • replace references to ImplementationOf with references to ActionImpl
  • replace method invocations on Super field (instructions 1,4,7 in ActionExtension.doAction2) with method invocations in super class (instruction 1 in ActionExtension$ActionImpl.doAction2)
You can find a proof-of-concept implementation of DynamicClassExtender in the zip file attached to this article. The source code is distributed under the terms of BSD License.

Conclusion

The dynamic approach for subtyping, presented above, may help to create customizable Java applications without sharing implementation source code and without sacrificing code reusability.
AttachmentSize
dex.zip50.73 KB
Published at DZone with permission of its author, Alex Antonau.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Epo Jemba replied on Tue, 2011/11/08 - 3:43pm

Hi Alex,

Great article on a topic I appreciate a lot !

I co-work (specifications mainly, my asm skills are not powerfull enough) with the author of the lib Proxetta (http://www.jodd.org a very very great framework that deserve to be known) on a little feature to achieve something similar technically speaking, but different in the goal (properly implements the D.C.I. role pattern).

In order to remove the inheritance/coupling on ImplementationOf, you could use a simple class marker with one method : like the following

/**
 * Marker.
 */
public class Self {
        public static < T > T get() {
                throw new UnsupportedOperationException();
        }
}

This allows you to have an ActionExtension free of ImplementationOf :

abstract class ActionExtension  implements Action{
  public void doAction2(){
     …
     Self. < Action > get().doAction2();
  }
}

In you asm class/method visitor just catch static call on Self.get and replace it by the good call. This way the sample will base class free. You even can remove the interface Action.

To conclude, i'm pretty sure the example you supply is doable with proxetta http://jodd.org/doc/proxetta/index.html.

What do you think ? (BTW, I prefer use "Self" idiom rather than "Super" in my sample)

Alex Antonau replied on Wed, 2011/11/16 - 12:35pm in response to: taharqa

Thanks for your post!

In my opinion your example is conceptually identical to one I provided. There is no decoupling from the ImplementationOf class, inheritance just replaced with a call to another marker class.

Thank you for the reference to Proxetta. However, I haven't found a way to use Proxetta to create a dynamic subclass. Proxetta replaces methods but I need to override methods with possibility to call a super method.

Robert Craft replied on Tue, 2011/12/27 - 12:27pm

Suppose I have a class A which defines a method bar(). The method bar() calls another method foo(). I then extend A in B and override foo() and do not override bar() (so it gets inherited). Which foo() is being called in these two cases? A a = new B(); a.bar(); // A or B's foo called? B b = new B(); b.bar(); // A or B's foo called?

Alex Antonau replied on Wed, 2012/01/04 - 4:03pm in response to: robertcraft4

In both cases B.foo().

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.