Rick has posted 25 posts at DZone. You can read more from them at their website. View Full User Profile

CDI AOP Tutorial: Java Standard Method Interception Tutorial - Java EE

05.25.2011
| 47043 views |
  • submit to reddit
This article discusses CDI based AOP in a tutorial format. CDI is the Java standard for dependency injection (DI) and interception (AOP). It is evident from the popularity of DI and AOP that Java needs to address DI and AOP so that it can build other standards on top of it. DI and AOP are already the foundation of many Java frameworks.

CDI is a foundational aspect of Java EE 6. It is or will be shortly supported by Caucho's Resin Java Application Server, Java EE WebProfile certified, IBM's WebSphere, Oracle's Glassfish, Red Hat's JBoss and many more application servers. CDI is similar to core Spring and Guice frameworks. Like JPA did for ORM, CDI simplifies and sanitizes the API for DI and AOP. If you have worked with Spring or Guice, you will find CDI easy to use and easy to learn. If you are new to AOP, then CDI is an easy on ramp for picking up AOP quickly, as it uses a small subset of what AOP provides. CDI based AOP is simpler to use and learn.

One can argue that CDI only implements a small part of AOP—method interception. While this is a small part of what AOP has to offer, it is also the part that most developers use.

CDI can be used standalone and can be embedded into any application.

Here is the source code for this tutorial, and instructions for use. It is no accident that this tutorial follows many of the same examples in the Spring 2.5 AOP tutorial written three years ago.

It will be interesting to compare and contrast the examples in this tutorial with the one written three years ago for Spring based AOP.



Design goals of this tutorial


This tutorial is meant to be a description and explanation of AOP in CDI without the clutter of EJB 3.1 or JSF. There are already plenty of tutorials that cover EJB 3.1 and JSF (and CDI).

We believe that CDI has merit on its own outside of the EJB and JSF space. This tutorial only covers CDI. Repeat there is no JSF 2 or EJB 3.1 in this tutorial. There are plenty of articles and tutorials that cover using CDI as part of a larger JEE 6 application. This tutorial is not that. This tutorial series is CDI and only CDI.

This tutorial only has full, complete code examples with source code you can download and try out on your own. There are no code snippets where you can't figure out where in the code you are suppose to be.

So far these tutorials have been well recieved and we got a lot of feedback. There appears to be a lot of interest in the CDI standard. Thanks for reading and thanks for your comments and participation so far.



AOP Basics


For some, AOP seems like voodoo magic. For others, AOP seems like a cure-all. For now, let's just say that AOP is a tool that you want in your developer toolbox. It can make seemingly impossible things easy. Aagin, when we talk about AOP in CDI, we are really talking about interception which is a small but very useful part of AOP. For brevity, I am going to refer to interception as AOP.

The first time that I used AOP was with Spring's transaction management support. I did not realize I was using AOP. I just knew Spring could apply EJB-style declarative transaction management to POJOs. It was probably three to six months before I realized that I was using was Spring's AOP support. The Spring framework truly brought AOP out of the esoteric closet into the main stream light of day. CDI brings these concepts into the JSR standards where other Java standards can build on top of CDI.

You can think of AOP as a way to apply services (called cross-cutting concerns) to objects. AOP encompasses more than this, but this is where it gets used mostly in the main stream.

I've using AOP to apply caching services, transaction management, resource management, etc. to any number of objects in an application. I am currently working with a team of folks on the CDI implementation for the revived JSR-107 JCache. AOP is not a panacea, but it certainly fits a lot of otherwise difficult use cases.

You can think of AOP as a dynamic decorator design pattern. The decorator pattern allows additional behavior to be added to an existing class by wrapping the original class and duplicating its interface and then delegating to the original. See this article decorator pattern for more detail about the decorator design pattern. (Notice in addition to supporting AOP style interception CDI also supports actual decorators, which are not covered in this article.)



Sample application revisited


For this introduction to AOP, let's take a simple example, let's apply security services to our Automated Teller Machine example from the first the first in this series.

Let's say when a user logs into a system that a SecurityToken is created that carries the user's credentials and before methods on objects get invoked, we want to check to see if the user has credentials to invoke these methods. For review, let's look at the AutomatedTellerMachine interface.



Code Listing: AutomatedTellerMachine interface
package org.cdi.advocacy;

import java.math.BigDecimal;

public interface AutomatedTellerMachine {

	public abstract void deposit(BigDecimal bd);

	public abstract void withdraw(BigDecimal bd);

}

In a web application, you could write a ServletFilter, that stored this SecurityToken in HttpSession and then on every request retrieved the token from Session and put it into a ThreadLocal variable where it could be accessed from a SecurityService that you could implement.

Perhaps the objects that needed the SecurityService could access it as follows:

Code Listing: AutomatedTellerMachineImpl implementing security without AOP
	public void deposit(BigDecimal bd) {
	    	/* If the user is not logged in, don't let them use this method */
    		if(!securityManager.isLoggedIn()){
    			throw new SecurityViolationException();
    		}
	    	/* Only proceed if the current user is allowed. */

	    	if (!securityManager.isAllowed("AutomatedTellerMachine", operationName)){
    			throw new SecurityViolationException();
    		}
		...

		transport.communicateWithBank(...);
	}

In our ATM example, the above might work out well, but imagine a system with thousands of classes that needed security. Now imagine, the way we check to see if a user is "logged in" changed. If we put this code into every method that needed security, then we could possibly have to change this a thousand times if we changed the way we checked to see if a user was logged in.

What we want to do instead is to use CDI to create a decorated version of the AutomateTellerMachineImpl bean. The decorated version would add the additional behavior to the AutomateTellerMachineImpl object without changing the actual implementation of the AutomateTellerMachineImpl. In AOP speak, this concept is called a cross-cutting concern. A cross-cutting concern is a concern that crosses the boundry of many objects.

CDI does this by creating what is called an AOP proxy. An AOP proxy is like a dynamic decorator. Underneath the covers CDI can generate a class at runtime (the AOP proxy) that has the same interface as our AutomatedTellerMachine. The AOP proxy wraps our existing atm object and provides additional behavior by delegating to a list of method interceptors. The method interceptors provide the additional behavior and are similar to ServletFilters but for methods instead of requests.



Diagrams of CDI AOP support


Thus before we added CDI AOP, our atm example was like Figure 1.

Figure 1: Before AOP advice
After we added AOP support, we now get an AOP proxy that applies the securityAdvice to the atm as show in figure 2.

Figure 2: After AOP advice

You can see that the AOP proxy implements the AutomatedTellerMachine interface. When the client object looks up the atm and starts invoking methods instead of executing the methods directly, it executes the method on the proxy, which then delegates the call to a series of method interceptor called advice, which eventually invoke the actual atm instance (now called atmTarget).

Let's actually look at the code for this example.

For this example, we will use a simplified SecurityToken that gets stored into a ThreadLocal variable, but one could imagine one that was populated with data from a database or an LDAP server or some other source of authentication and authorization.

Here is the SecurityToken, which gets stored into a ThreadLocal variable, for this example:

SecurityToken.java Gets stored in ThreadLocal
package org.cdi.advocacy.security;

/**
 * @author Richard Hightower
 *
 */
public class SecurityToken {
        
        private boolean allowed;
        private String userName;
        
        public SecurityToken() {
                
        }
        
        
        
        public SecurityToken(boolean allowed, String userName) {
                super();
                this.allowed = allowed;
                this.userName = userName;
        }



        public boolean isAllowed(String object, String methodName) {
                return allowed;
        }

        
        /**
         * @return Returns the allowed.
         */
        public boolean isAllowed() {
                return allowed;
        }
        /**
         * @param allowed The allowed to set.
         */
        public void setAllowed(boolean allowed) {
                this.allowed = allowed;
        }
        /**
         * @return Returns the userName.
         */
        public String getUserName() {
                return userName;
        }
        /**
         * @param userName The userName to set.
         */
        public void setUserName(String userName) {
                this.userName = userName;
        }
}
The SecurityService stores the SecurityToken into the ThreadLocal variable, and then delegates to it to see if the current user has access to perform the current operation on the current object as follows:

SecurityService.java Service
package org.cdi.advocacy.security;


public class SecurityService {
        
        private static ThreadLocal<SecurityToken> currentToken = new ThreadLocal<SecurityToken>();
        
        public static void placeSecurityToken(SecurityToken token){
                currentToken.set(token);
        }
        
        public static void clearSecuirtyToken(){
                currentToken.set(null);
        }
        
        public boolean isLoggedIn(){
                SecurityToken token = currentToken.get();
                return token!=null;
        }
        
        public boolean isAllowed(String object, String method){
                SecurityToken token = currentToken.get();
                return token.isAllowed();
        }
        
        public String getCurrentUserName(){
                SecurityToken token = currentToken.get();
                if (token!=null){
                        return token.getUserName();
                }else {
                        return "Unknown";
                }
        }

}


The SecurityService will throw a SecurityViolationException if a user is not allowed to access a resource. SecurityViolationException is just a simple exception for this example.



SecurityViolationException.java Exception
package com.arcmind.springquickstart.security;

/**
 * @author Richard Hightower
 *
 */
public class SecurityViolationException extends RuntimeException {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

}

To remove the security code out of the AutomatedTellerMachineImpl class and any other class that needs security, we will write an Aspect in CDI to intercept calls and perform security checks before the method call. To do this we will create a method interceptor (known is AOP speak as an advice) and intercept method calls on the atm object.

Here is the SecurityAdvice class which will intercept calls on the AutomatedTellerMachineImpl class.



SecurityAdvice
package org.cdi.advocacy.security;



import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

/**
 * @author Richard Hightower
 */
@Secure @Interceptor
public class SecurityAdvice {
        
        @Inject
        private SecurityService securityManager;

        @AroundInvoke
        public Object checkSecurity(InvocationContext joinPoint) throws Exception {
        	
        	System.out.println("In SecurityAdvice");
                
            /* If the user is not logged in, don't let them use this method */
            if(!securityManager.isLoggedIn()){            
                throw new SecurityViolationException();
            }

            /* Get the name of the method being invoked. */
            String operationName = joinPoint.getMethod().getName();
            /* Get the name of the object being invoked. */
            String objectName = joinPoint.getTarget().getClass().getName();


           /*
            * Invoke the method or next Interceptor in the list,
            * if the current user is allowed.
            */
            if (!securityManager.isAllowed(objectName, operationName)){
                throw new SecurityViolationException();
            }
        
            return joinPoint.proceed();
        }
}

Notice that we annotate the SecuirtyAdvice class with an @Secure annotation. The @Secure annotation is an @InterceptorBinding. We use it to denote both the interceptor and the classes it intercepts. More on this later.

Notice that we use @Inject to inject the securityManager. Also we mark the method that implements that around advice with and @AroundInvoke annotation. This essentially says this is the method that does the dynamic decoration.

Thus, the checkSecurity method of SecurityAdvice is the method that implements the advice. You can think of advice as the decoration that we want to apply to other objects. The objects getting the decoration are called advised objects.

Notice that the SecurityService gets injected into the SecurityAdvice and the checkSecurity method uses the SecurityService* to see if the user is logged in and the user has the rights to execute the method.

An instance of InvocationContext, namely joinPoint, is passed as an argument to checkSecurity. The InvocationContext has information about the method that is being called and provides control that determines if the method on the advised object's methods gets invoked (e.g., AutomatedTellerMachineImpl.withdraw and AutomatedTellerMachineImpl.deposit). If *`joinPoint.proceed()`* is not called then the wrapped method of the advised object (withdraw or deposit) is not called. (The proceed method causes the actual decorated method to be invoked or the next interceptor in the chain to get invoked.)

In Spring, to apply an Advice like SecurityAdvice to an advised object, you need a pointcut. A pointcut is like a filter that picks the objects and methods that get decorated. In CDI, you just mark the class or methods of the class that you want decorated with an interceptor binding annotation. There is no complex pointcut language. You could implement one as a CDI extention, but it does not come with CDI by default. CDI uses the most common way developer apply interceptors, i.e., with annotations.

CDI scans each class in each jar (and other classpath locations) that has a META-INF/beans.xml. The SecurityAdvice get installed in the CDI beans.xml.



META-INF/beans.xml
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

    <interceptors>
        <class>org.cdi.advocacy.security.SecurityAdvice</class>
    </interceptors>
</beans>

You can install interceptors in the order you want them called.

In order to associate a interceptor with the classes and methods it decorates, you have to define an InterceptorBinding annotation. An example of such a binding is defined below in the @Secure annotation.



Secure.java annotation
package org.cdi.advocacy.security;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import javax.interceptor.InterceptorBinding;


@InterceptorBinding 
@Retention(RUNTIME) @Target({TYPE, METHOD})
public @interface Secure {

}

Notice that we annotated the @Secure annotation with the @InterceptorBinding annotation.

InterceptorBindings follow a lot of the same rules as Qualifiers as discussed in the first two articles in this series. InterceptorBindings are like qaulifiers for injection in that they can have members which can further qualify the injection. You can also disable InterceptorBinding annotation members from qualifying an interception by using the @NonBinding just like you can in Qualifiers.

To finish our example, we need to annotate our AutomatedTellerMachine with the same @Secure annotation; thus, associating the AutomatedTellerMachine with our SecurityAdvice.



AutomatedTellerMachine class using @Secure
package org.cdi.advocacy;
...
import javax.inject.Inject;

import org.cdi.advocacy.security.Secure;

@Secure
public class AutomatedTellerMachineImpl implements AutomatedTellerMachine {

    @Inject
    @Json
    private ATMTransport transport;

    public void deposit(BigDecimal bd) {
        System.out.println("deposit called");
        transport.communicateWithBank(null);

    }

    public void withdraw(BigDecimal bd) {
        System.out.println("withdraw called");

        transport.communicateWithBank(null);

    }

}

You have the option of use @Secure on the methods or at the class level. In this example, we annotated the class itself, which then applies the interceptor to every method.

Let's complete our example by reviewing the AtmMain main method that looks up the atm out of CDI's beanContainer.

Let's review AtmMain as follows:



AtmMain.java
package org.cdi.advocacy;

import java.math.BigDecimal;

import org.cdi.advocacy.security.SecurityToken;
import org.cdiadvocate.beancontainer.BeanContainer;
import org.cdiadvocate.beancontainer.BeanContainerManager;
import org.cdi.advocacy.security.SecurityService;

public class AtmMain {

    public static void simulateLogin() {
        SecurityService.placeSecurityToken(new SecurityToken(true,
                "Rick Hightower"));
    }

    public static void simulateNoAccess() {
        SecurityService.placeSecurityToken(new SecurityToken(false,
                "Tricky Lowtower"));
    }

    public static BeanContainer beanContainer = BeanContainerManager
            .getInstance();
    static {
        beanContainer.start();
    }

    public static void main(String[] args) throws Exception {
        simulateLogin();
        //simulateNoAccess();

        AutomatedTellerMachine atm = beanContainer
                .getBeanByType(AutomatedTellerMachine.class);
        atm.deposit(new BigDecimal("1.00"));
    }

}

Continue reading... Click on the navigation links below the author bio to read the other pages of this article.

Be sure to check out part I of this series as well: CDI DI Tutorial!



About the author
This article was written with CDI advocacy in mind by Rick Hightower with some collaboration from others. Rick Hightower has worked as a CTO, Director of Development and a Developer for the last 20 years. He has been involved with J2EE since its inception. He worked at an EJB container company in 1999. He has been working with Java since 1996, and writing code professionally since 1990. Rick was an early Spring enthusiast. Rick enjoys bouncing back and forth between C, Python, Groovy and Java development. Rick Hightower is CTO of Mammatus (Experts on IaaS, EC2 and all things cloud) and is an expert on Java and Cloud Computing.

Although not a fan of EJB 3, Rick is a big fan of the potential of CDI and thinks that EJB 3.1 has come a lot closer to the mark.

CDI Implementations - Resin Candi - Seam Weld - Apache OpenWebBeans

Published at DZone with permission of its author, Rick Hightower.

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

Comments

Jonathan Fisher replied on Wed, 2011/05/25 - 1:52pm

A note, only WebSphere v8 supports CDI, which just recently (mid April I think) went "GA" public release.

Reza Rahman replied on Thu, 2011/05/26 - 3:11pm

Wow - that's a pretty fast release for WebSphere :-).

Krzysztof Kowalczyk replied on Fri, 2011/05/27 - 5:55am

I would argue that CDI / EJB interceptor implementation is not an proper AOP. At least some behaviors are counterintuitive. When we have:
class InterceptedBean{
  @MethodReturnOne <-- interceptor, always returns 1
  Integer x(){ return 2L; }
  Integer y(){ return x(); }
}
x() would return 1 when called outside of the bean, but when called inside the bean -> y() will return 2L. So interceptor is not applied on all method invocations. In CDI it's quite easy to create scope-cached functions for instance, what is really handy considering JSF bindings behavior. Unfortunately in practice private or protected functions cannot be cached in that way and public functions cannot be reused in the same bean. That's annoying.

Reza Rahman replied on Fri, 2011/05/27 - 4:45pm in response to: Krzysztof Kowalczyk

The trivial fix would be:

class InterceptedBean{
  @MethodReturnOne <-- interceptor, always returns 1
  Integer x(){ return 2L; }
  @MethodReturnOne <-- interceptor, always returns 1
  Integer y(){ return x(); }
}

The big benefit to using proxying vis-a-vis AspectJ style byte-code injection is class-loader simplicity/performance. CDI interceptors are also way easier than arcane AspectJ point-cut syntax.

Krzysztof Kowalczyk replied on Sat, 2011/05/28 - 12:18pm in response to: Reza Rahman

This is never a fix! In real world there would be some logic before calling x() e.g. random() * x(). If one implement "arround" behavior with compile time bytecode modification or load time subclass creation, the example would work. So it probably means that interceptor implementation is more complex, thus slower - I did not checked that, yet.

Reza Rahman replied on Sat, 2011/05/28 - 8:22pm in response to: Krzysztof Kowalczyk

I think you are overstating the issue a bit.

Even in the Spring world, AspectJ use is very rare. Take a look at this graph. As you can see, AspectJ use is quite insigficant, even in  the Spring world.

If the issue you noted is really that critical, you'd see more AspectJ use, right :-)?

Krzysztof Kowalczyk replied on Sun, 2011/05/29 - 8:21am in response to: Reza Rahman

This has nothing to do with AspectJ, but with implementation of AOP in JEE. AspectJ is a quite sophisticated and mature solution that is not needed by most developers. Simple arround invoke aop implementation is enough for most of users. JEE gives such solution but with bad implementation IMHO. This implementation of aop may cause many hard to find errors in near future. What if in a financial system someone use interceptor and one of the methods is not transactional(or recorded, or logged, or whatever) because one called the intercepted method from other method in the same class? It is possible and really hard to find. So now I have to explain to developers: sorry guys, but your methods will behave differently depending in which class they are called... and they think that aop is hard and strange. I guess that other AOP implementation will behave correctly, including Spring AOP even without AspectJ, but did not checked that. CDI / EJB is a standard, Glassfish is a reference implementation of the standard. As for today they behave in a non-OOP way (in my opinion this behavior is breaking Liskov substitution principle, as one could see an intercepted class as a subclass of that type) and I think it is an error. If it is a design decision, then I'm would like to know it's rationale.

Reza Rahman replied on Mon, 2011/05/30 - 3:07pm

I thought I was being very clear about the rationale, but I'll try again for you:

CDI is based on proxying, exactly like Spring AOP (so it too will have the issue you are concerned about). CDI (and Java EE in general) does not mandate direct byte-code manulation/code-generation like AspectJ does (that is the only way of implementing what you are looking for -- that is interception at the class instance level rather than injection proxy level). This is done primarily because of class-loading/deployment/implemention simplicity as well as performance (manipulating byte code/generating code is a lot more performance intensive rather than simple Java proxying via sub-classing).

CDI/Java EE is crystal clear that interceptors are only applied via injected proxy -- it is not applied when making a self-call or a call on a direct class instance (likely created via "new" instead of injection). Just like anyone using Spring AOP, anyone using CDI interceptors should be aware of this before the fact. If interceptors are really needed during self-call the solution is quite simple -- do a self-injection like this:

class InterceptedBean {
  @Inject
  private InterceptedBean self;
  @MethodReturnOne <-- interceptor, always returns 1
  Integer x(){ return 2L; }
  Integer y(){ return self.x(); }
}

As I said, in practice this case is very rare which is why Spring AOP and CDI interceptors are sufficient for most cases as compared to full-blown AspectJ. For example, I have not come across it once in ten years of real-world enterprise developement and I have seen a self-call example only in the Java EE compatibility test kit (and was surprised when I saw it).

Hope this helps.

Krzysztof Kowalczyk replied on Mon, 2011/05/30 - 5:29pm

Thanks for your opinion, but I still can't see any rationale for such behavior - it still breaks OOP principles, for what reason? (or am I missing something?).

You claim that you never have seen such use case, so you say that you never invoke a method from another method? (joke ;) ) CDI is general purpose solution and should not constrain itself to procedural style code.

You mentioned subclassing. If we used exactly such style of aop, it would behave exactly as I expect it to behave. The virtual dispatch would be fulfilled, it would not change behavior of not managed instances and it is also one of fastest(runtime) solutions . It is semantically equivalent to a class:

//Proxy
class ReturnOne extends InterceptedBean{
 Integer x(){return 1; }
}


This would cause y() to return 1 (because x is a virtual method)! It can be implemented at injection proxy level as subclass, the original class is not changed in any way. So again, this has nothing to do with AspectJ way. Subclassing is actually easiest way to implement aop afaik, but behaves differently than EJB interceptors.
The behavior of EJB interceptor points rather to a "subclass and delegate" implementation style, or proxy with dynamic filters on method invocations handlers, both are slower in theory, but in practice it should not make a big difference. So I cannot agree with your comments about performance issues.

Reza Rahman replied on Tue, 2011/05/31 - 3:49am in response to: Krzysztof Kowalczyk

Spring AOP and CDI interceptors are good enough for the vast majority of real world use cases and both AOP system are clear that they require interception only on injected proxy calls. For the remaining cases, it is possible to use AspectJ with CDI, Java EE or pretty much anything else.

Now, I believe I've said everything that needs to be said on this. I don't have the time or patience to explain to you why the imaginary code you have above makes little sense in a real-world proxy-based container. You'll have to find that out on your own by looking at Weld, OpenWebBeans, CanDI or Spring AOP. The way I see it, I have paid this more attention than most people would.

If you really feel that strongly about it, feel free to bring it to the attention of the CDI 1.1 EG that is just currently underway: http://www.jcp.org/en/jsr/proposalDetails?id=346. The JCP page references a JIRA instance for CDI/Weld that you can also use.

Hope it helps.

Krzysztof Kowalczyk replied on Tue, 2011/05/31 - 3:16am

Thanks for discussion. When I've asked on weld forum if this behavior is correct, there was no answer. I just could not agree on incorrect statements like the one with "proxy via subclassing" behavior.
Btw. I've checked JBoss interceptor implementation. It is using load time bytecode manipulation. So CDI does mandate bytecode manipulation, whitout it one cannot create dynamic proxy for classes, only for interfaces. It also uses "delegate" style proxy. Spring AOP does the same, but it actually call the self-invocation behavior as "issue" and is explicit about this behavior in documentation. Thought you'd like to know.
Regards, Krzysztof Kowalczyk

Reza Rahman replied on Tue, 2011/05/31 - 3:54am

I'll tell you what -- I'll go ahead and enter the issue for you, but I have a good guess right now what the outcome will be...

Krzysztof Kowalczyk replied on Tue, 2011/05/31 - 6:22am

The more I investigate this, the more I'm aware that it is a design decision, just can't find explanation for it. It just occured to me that it might be implemented that way because of remote beans.

Krzysztof Kowalczyk replied on Tue, 2011/05/31 - 6:37am

Ok, I finally have satisfying answer. The delegate style aop is needed (only reasonable way to do it) when we have a remote bean and we want to apply aop on the client side. Having two different behaviors for the same thing would be really bad so local interceptors works the same. Thanks again for the discussion.

Reza Rahman replied on Tue, 2011/05/31 - 1:00pm in response to: Krzysztof Kowalczyk

I think you should look at real world implementations instead of simply thinking in a void of how this should be. There is more to any of this than unfortunately readily meets the eye. I mentioned some of those concerns already -- implementation (both simplicity and flexibility)/class-loading/deployment/code-generation/byte-code manipulation/proxying/performance/overall container architecture/innovation and so on.

However, as I promised, I'll bring up the issue for you anyway.

Krzysztof Kowalczyk replied on Wed, 2011/06/01 - 1:28pm

The issue is already filled:
https://issues.jboss.org/browse/CDI-44
https://issues.jboss.org/browse/CDI-74

A bit similar discussion:
http://lists.jboss.org/pipermail/weld-dev/2010-May/002506.html
http://lists.jboss.org/pipermail/weld-dev/2010-May/002513.html (I like the example)
I did not found those links earlier. The implementation will be changed, some things are not yet specified.
I do check real world implementations, I know differences between some of them, especially considering performance and some issues caused by them (as in the case of subclass and delegate (proxy) pattern of aop), that's why it caught my attention.

Reza Rahman replied on Sat, 2011/06/11 - 7:45pm in response to: Krzysztof Kowalczyk

Good -- I'll follow it up on the EG and reference the above Weld issues.

Carla Brian replied on Tue, 2012/04/03 - 12:53pm

Thank you for posting this one. I am new to this topic. Good thing I stumbled upon in your post. - Paul E. Perito

Comment viewing options

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