Discussions

News: New AOP framework announced: dynaop

  1. New AOP framework announced: dynaop (15 messages)

    Bob Lee has announced a new AOP framework in dynaop 1.0 beta. The framework uses a proxy-based approach and is meant to be easy for J2EE developers to start using. Along with the announcement, Bob has released some benchmark results comparing dynaop with other AOP tools such as JBossAOP, Spring, and Nanning.

    Excerpt

    "I thought AspectJ and AspectWerkz were impressively powerful but not well suited to your average J2EE developer. I wanted to steer users toward a good design more than I wanted a pointcut to pick out a type cast. The remaining frameworks all lacked a number of key features as well as the sense of refinement I needed to sell my team. I rolled up my sleeves and started dynaop."

    References

    Bob on dynaop 1.0 beta

    dynaop home page

    dynaop manual

    Download

    Threaded Messages (15)

  2. New AOP framework announced: dynaop[ Go to top ]

    Congrats to Bob! Looks like a well done project.

    /Rickard
  3. Yes, good work. I have read some documents and found documentation as very clear.
    How we can sell cglib for you ? Looks like serialization in cglib is the main problem, is not it ?
  4. New AOP framework announced: dynaop[ Go to top ]

    It uses cglib already! :D Serialization problems solved.
  5. New AOP framework announced: dynaop[ Go to top ]

    Yes, I have downloaded and I saw it later.
    It is nice to see serialization for cglib proxies in dynaop, it must be the great work.
    Configuration in dynaop is my faworite feature, very simple and no XML.
    It is a very good use case for scripting language, I think I will steal your idea too.
  6. Serialization with CGLIB[ Go to top ]

    It uses cglib already! :D Serialization problems solved.


    How did you solve the serialization issue?

    I know that serialization of proxied interfaces is solved out-of-the-box. But what about serialization of proxies for concrete/abstract classes?

    I know, a bit off topic. Please email me about it if the explanation is too long. I'm very interested.
  7. Serialization with CGLIB[ Go to top ]

    How did you solve the serialization issue?

    >
    > I know that serialization of proxied interfaces is solved out-of-the-box. But what about serialization of proxies for concrete/abstract classes?

    Tirsen,

    See dynaop.CglibProxyHandle. I tried to post the link, but the filter wouldn't allow it.
  8. Serialization with CGLIB[ Go to top ]

    See dynaop.CglibProxyHandle.


    Why you do not filter trancient and static fields ? Is it just a bug or it has some meaning ?
  9. Serialization with CGLIB[ Go to top ]

    Looks like it must take class level interceptors into account before to deserialize too if it can have side effect.
  10. Serialization with CGLIB[ Go to top ]

    See dynaop.CglibProxyHandle.

    >
    > Why you do not filter trancient and static fields ? Is it just a bug or it has some meaning ?

    Static fields are a mistake (though it doesn't really do anything because it just sets it to the same value ;)).

    It does need to copy transient fields though. What it does is create a new, unproxied instance and serializes that. This instance may have custom readObject/writeObject methods that handle the transient field.
  11. Serialization with CGLIB[ Go to top ]

    In general, serialization of CGLIB enhanced classes works as long as you are willing to introduce protected writeReplace() to the target class (or its super class).

    (or alternatively somehow force CGLIB to emit writeReplace() method within the dynamic class):

    I used Bob's technique for object copy combined with the fact that 'protected writeReplace()' will force custom serialization at the level of the CGLIB-enhanced class

    Tested this over the real wire (distributed JMS producer/consumer):

       /**
        * serialization
        * @return serial proxy instance
        */
       protected Object writeReplace() {
          
          if (this instanceof Factory) {
          
             SerializedProxy serialProxy = new SerializedProxy();
       
             List interfaces = filterInterfaces(getClass().getInterfaces());
       
             for (Iterator i = interfaces.iterator(); i.hasNext();) {
                serialProxy.interfaces.add(((Class) i.next()).getName());
             }
       
             serialProxy.superClass = getClass().getSuperclass();
             serialProxy.callbacks = ((Factory) this).getCallbacks();
             serialProxy.nakedObject = unwrap();
             
             return serialProxy;
          }
          
          return this;
       }
       
       /**
        *
        * A class that serializes cglib proxy
        *
        *
        */
       public static final class SerializedProxy implements Serializable {

          private static final long serialVersionUID = 568312334450175549L;
          
          List interfaces = new LinkedList();
          Class superClass;
          Callback[] callbacks;
          Object nakedObject;
          
          /**
           * deserialization
           * @return cglib proxy
           * @throws ObjectStreamException
           */
          private Object readResolve() throws ObjectStreamException {
             
             Factory factory = null;

             Enhancer enhancer = new Enhancer();
             
             enhancer.setClassLoader(getClassLoader());
             enhancer.setSuperclass(superClass);
             List interfaceClasses = new LinkedList();
             try {
                for (int i = 0; i < interfaces.size(); i++)
                   interfaceClasses.add(
                         getClassLoader().loadClass((String)interfaces.get(i)));
             } catch (ClassNotFoundException e) {
                ObjectStreamException ex = new InvalidClassException(e.getMessage());
                ex.setStackTrace(e.getStackTrace());
                throw ex;
             }
             enhancer.setInterfaces(
                   (Class[]) interfaceClasses.toArray(new Class[interfaceClasses.size()]));
             enhancer.setCallback(new MethodInterceptor() {

                public Object intercept(
                      Object obj,
                      Method method,
                      Object[] args,
                      MethodProxy proxy) throws Throwable {
                   throw new IllegalAccessException(
                         "callbacks not supported during deserialization");
                }
             });
             enhancer.setInterceptDuringConstruction(false);
             
             factory = (Factory) enhancer.create();
             
             copyObject(nakedObject, factory, superClass);
             
             factory.setCallbacks(callbacks);
             
             return factory;
          }
          
          private static ClassLoader getClassLoader() {
             ClassLoader loader = Thread.currentThread().getContextClassLoader();
             return (loader == null)
             ? SerializedProxy.class.getClassLoader() : loader;
          }
       }
       

       private Object unwrap() {
          Object unwrapped;

          try {
             
             unwrapped = getClass().getSuperclass().newInstance();
             
          } catch (InstantiationException e) {
             throw new PersistenceRuntimeException(e);
          } catch (IllegalAccessException e) {
             throw new PersistenceRuntimeException(e);
          }

          copyObject(this, unwrapped, unwrapped.getClass());

          return unwrapped;
       }

       static void copyObject(Object src, Object dest, Class clazz) {

          while (!clazz.equals(Object.class)) {

             Field[] fields = clazz.getDeclaredFields();

             for (int i = 0; i < fields.length; i++) {
                fields[i].setAccessible(true);

                // we can't set final fields. :(
                if (Modifier.isFinal(fields[i].getModifiers()))
                   continue;

                // we can't set static fields. :(
                if (Modifier.isStatic(fields[i].getModifiers()))
                   continue;

                copyField(src, dest, fields[i]);
             }
             clazz = clazz.getSuperclass();
          }
       }

       private static void copyField(Object src, Object dest, Field field) {
          try {
             field.set(dest, field.get(src));
          } catch (IllegalArgumentException e) {
             throw new PersistenceRuntimeException(e);
          } catch (IllegalAccessException e) {
             throw new PersistenceRuntimeException(e);
          }
       }

       /**
        * Filters out cglib interfaces.
        */
       static List filterInterfaces(Class[] interfaces) {
          List interfaceList = new ArrayList(Arrays.asList(interfaces));
          for (Iterator i = interfaceList.iterator(); i.hasNext();)
             if (((Class) i.next()).getName().startsWith("net.sf.cglib."))
                i.remove();
          return interfaceList;
       }
       

    Regards,
    Maciek
  12. New AOP framework announced: dynaop[ Go to top ]

    Awesome work! It'll be interesting to see if this can be combined with PicoContainer in a clean way.

    ~harris

    http://www.harrisreynolds.net/weblog
  13. New AOP framework announced: dynaop[ Go to top ]

    One good thing about Aspectwerkz is the list of simple examples they supply to get you off the ground. I found Bob's example to be a little bit too code heavy so I stripped some stuff out to create a *very* simple example. Here is a link to my blog which shows my example and has a link to the sample app.

    http://analogueboy.blogspot.com/#107669796229118025

    HTH fellow dynaop n00bs!
  14. New AOP framework announced: dynaop[ Go to top ]

    Bob,

       Can u elaborate a little bit why u feel that a solution such as ASPECTWERK or JBOSS AOP (STANDALONE) don’t suit your requirements.

       I have already used both implementations in several projects and I feel that both of them are powerful solutions in terms of AOP features and are also very easy to use.

       They provide not only public method interception as DYNAOP does,but also protected, private,package protected methods, static methods, protected fields interception ,and also constructor interception (JBOSS-AOP only).

       Also, an AOP solution based on runtime byte code modification has the advantage to be a non evasive solution in the application targeted.There is no code change required to intercept method or use Introduction.In DYNAOP, a class can be intercepted if only the class has a public empty constructor and if the class is created by DYNAOP .

    Rgds ,Claude

    Claude Hussenet
    Independent Consultant.
    Email:chussenet@yahoo.com
  15. New AOP framework announced: dynaop[ Go to top ]

    From my weblog (as I saw this same comment there first):

    I've already addressed this question with an example use case in this comment: http://weblogs.java.net/cs/user/view/cs_msg/2816

    There's also the matter of tool support (neither of those has a documentation tool that I know of), ease and flexibility in configuration, support for object serialization, and development impact (i.e. those two frameworks require custom classloaders), all of which I listed in my entry. Also, IMHO, the dynaop API is more polished and in the "Java spirit."

    > Bob,
    >
    > Can u elaborate a little bit why u feel that a solution such as ASPECTWERK or JBOSS AOP (STANDALONE) don’t suit your requirements.
    >
    > I have already used both implementations in several projects and I feel that both of them are powerful solutions in terms of AOP features and are also very easy to use.
    >
    > They provide not only public method interception as DYNAOP does,but also protected, private,package protected methods, static methods, protected fields interception ,and also constructor interception (JBOSS-AOP only).
    >
    > Also, an AOP solution based on runtime byte code modification has the advantage to be a non evasive solution in the application targeted.There is no code change required to intercept method or use Introduction.In DYNAOP, a class can be intercepted if only the class has a public empty constructor and if the class is created by DYNAOP .
    >
    > Rgds ,Claude
    >
    > Claude Hussenet
    > Independent Consultant.
    > Email:chussenet@yahoo.com
  16. How does mixin (introduction) class get a handle of the members/functionality of the mixable (say MyClassImpl) class (or can it)? On the other hand, interception has the handle to the invocation and therefore all the parameters within.