Meeting Plastic I: Introduction

With Tapestry, you know things improve very fast. For the users, everything stays much the same(Ok, only after Tapestry5) but for developers, it keeps you on your toes especially if you are constantly peeking into the source code. In Tapestry 5.3, we are going to see complete replacement of Javassist by Plastic. It is a wrapper around ASM.

Example

Let us first start with the simplest of example. Say, we want to add a toString() method to all the classes in the controlled package. A controlled package is one which contains classes that are to be transformed. In order to perform a transformation, we implement PlasticClassTransformer interface.

/**
 * A simple class transformer which adds a toString method to the
 * classes to be transformed
 */
public class ToStringTransformer implements PlasticClassTransformer {

   /**
    * Adds a toString() method to the class
    */
   public void transform(PlasticClass plasticClass) {
      plasticClass.addToString("Modified by <ToStringTransformer>");
   }

}

In the transform method, we use addToString method to add a toString() method to the class.

I have written a small spock test to use this transformer.

/**
 * A simple test for {@link plasticdemo.transforms.ToStringTransformer}
 */
class ToStringTest extends Specification {
   def pm
   
   def setup(){
      //Create a plastic manager and pass on the controlled package and the transformer
      pm = PlasticManager.withContextClassLoader().packages(["plasticdemo.controlled"]).
         delegate(new StandardDelegate(new ToStringTransformer())).create()
   }
   
   def "test if a class in controlled package has our toString method"(){
      def foo = pm.getClassInstantiator("plasticdemo.controlled.Foo").newInstance()
      expect: foo.toString().equals("Modified by <ToStringTransformer>")
   }
}

The steps involved are
Step #1: Create and configure a PlasticManagerBuilder
PlasticManagerBuilder can be created using either withContextClassLoader() or withClassLoader(ClassLoader) method. In the latter case, class loader can be passed as argument. Once the builder is created, it can be passed our controlled package name and class transformer.

Step #2: Create a PlasticManager
An instance of PlasticManager can be obtained by calling PlasticManagerBuilder.create().

Step #3: Obtain a ClassInstantiator and create instance
To create an instance of the transformed class, we first get ClassInstantiator by calling PlasticManager.getClassInstantiator() and then call its newInstance() method

You can find the source here

About these ads

Tagged: , , , , ,

6 thoughts on “Meeting Plastic I: Introduction

  1. Howard Lewis Ship April 18, 2011 at 10:58 PM Reply

    The only change I might make is that the actual advice object can be shared across any number of services and methods (at least, in your example). Also, I would emphasize that any method may have any amount of method advice added to it. Plastic threads the call to the method advice directly into the method, and chains the first method advice to the next.

    The innovation of Plastic is that it embraces the instrumentation of the Java bytecode at runtime, and therefore can thread Object instances … whereas other tools, such as AspectJ are more fundamentally organized around static methods (a vast simplification, for which I apologize).

    Also, you don’t need to know Gradle (the build tool) to use this, just to build it. There are up to date snapshots in Apache Snapshot repository: https://repository.apache.org/content/groups/snapshots

    • tawus April 18, 2011 at 11:14 PM Reply

      Thanks for your valuable input. Have updated the example.

  2. DH April 29, 2011 at 9:25 PM Reply

    Hi, can not run the Demo.

    Exception in thread “main” java.lang.IllegalArgumentException: Class plasticdemo.MyServiceImpl is not an interface; proxies may only be created for interfaces.

    Even though I replace with ‘pm.createClass(MyServiceImpl.class’, the demo won’t work as expected. Because ‘pc.getMethodsWithAnnotation(Log.class)’ returns empty list.

    BTW, I use the lastest plastic snapshot.

    • tawus April 29, 2011 at 10:48 PM Reply

      Plastic internals have changed since i wrote that post (The javadoc comments are still old ones if you would have noticed). I have modified the post.
      Thanks for taking out the time to write a feedback.

  3. Omar September 2, 2011 at 9:15 AM Reply

    Great article! Really cleared up what Plastic is all about.

    I had a question though, how can I invoke methods added via transformation without implementing an interface? Meaning the method name would be specified as a string.

    Thanks!

    Omar

    • tawus September 5, 2011 at 3:39 PM Reply

      Thanks Omar,

      As the class is only loaded once by a classloader, If you try to directly access the class, you will end up loading the non-transformed version first and so will never be able to access the transformed version. That is the reason interface is used. If you want to directly access the methods by using string name, use reflection. (Use Object reference to hold the class instance)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 90 other followers

%d bloggers like this: