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

CDI Dependency Injection - Tutorial II - Annotation Processing and Plugins - Java EE

04.05.2011
| 92442 views |
  • submit to reddit

CDI provides a pluggable architecture allowing you to easily process your own annotations. Read this article to understand the inner workings of CDI and why this JSR is so important.

CDI simplifies and sanitizes the API for DI and AOP like JPA did for ORMs. Through its use of Instance and @Produces, CDI provides a pluggable architecture. This is a jaw dropping killer feature of CDI. Master this and you start to tap into the power of CDI. The last article was just to lay the ground work to the uninitiated for this article.

This article continues our tutorial of dependency injection with CDI.

This article covers:

  • How to process annotations for configuration (injection level and class level)
  • How to use an annotation for both injection and configuration (@Nonbinding)
  • Using Instance to manage instances of possible injection targets
  • CDI's plugin architecture for the masses

With this pluggable architecture you can write code that finds new dependencies dynamically. CDI can be a framework to write frameworks. This is why it is so important that CDI was led through the JSR process.

Just like last time, there are some instructions on how to run the examples: Source code for this tutorial, and instructions for use. A programming article without working sample code is like a sandwich with no condiments or dry toast without jelly.



Advanced CDI tutorial


The faint of heart stop here. All of the folks who want to understand the inner workings of CDI continue. So far, we have been at the shallow, warm end of the pool. Things are about to get a little deeper and colder. If you need to master CDI, then this article if for you. If you don't know what CDI is then read the first CDI DI article.



Advanced: Using @Produces and InjectionPoint to create configuration annotations


Our ultimate goal is to define an annotation that we can use to configure the retry count on a transport. Essentially, we want to pass a retry count to the transport.

We want something that looks like this:

Code Listing: TransportConfig annotations that does configuration
	@Inject @TransportConfig(retries=2)
	private ATMTransport transport;

(This was my favorite section to write, because I wanted to know how to create a annotation configuration from the start.)

Before we do that we need to learn more about @Produces and InjectionPoints. We are going to use a producer to read information (meta-data) about an injection point. A major inflection point for learning how to deal with annotations is the InjectionPoints. The InjectionPoints has all the metadata we need to process configuration annotations.

An InjectionPoint is a class that has information about an injection point. You can learn things like what is being decorated, what the target injection type is, what the source injection type, what is the class of the owner of the member that is being injected and so forth.

Let's learn about passing an injection point to @Produces. Below I have rewritten our simple @Produces example from the previous article, except this time I pass an InjectionPoint argument into the mix.



Code Listing: TransportFactory getting meta-data about the injection point
package org.cdi.advocacy;

import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;

public class TransportFactory {


    @Produces ATMTransport createTransport(InjectionPoint injectionPoint) {
		
        System.out.println("annotated " + injectionPoint.getAnnotated());
        System.out.println("bean " + injectionPoint.getBean());
        System.out.println("member " + injectionPoint.getMember());
        System.out.println("qualifiers " + injectionPoint.getQualifiers());
        System.out.println("type " + injectionPoint.getType());
        System.out.println("isDelegate " + injectionPoint.isDelegate());
        System.out.println("isTransient " + injectionPoint.isTransient());

        return new StandardAtmTransport();
    }

}
Now we just run it and see what it produces. The above produces this output. Output
annotated AnnotatedFieldImpl[private org.cdi.advocacy.ATMTransport org.cdi.advocacy.AutomatedTellerMachineImpl.transport]
bean ManagedBeanImpl[AutomatedTellerMachineImpl, {@javax.inject.Named(value=atm), @Default(), @Any()}, name=atm]
member private org.cdi.advocacy.ATMTransport org.cdi.advocacy.AutomatedTellerMachineImpl.transport
qualifiers [@Default()]
type interface org.cdi.advocacy.ATMTransport
isDelegate false
isTransient false
deposit called
communicating with bank via Standard transport

It appears from the output that annotated tells us about the area of the program we annotated. It also appears that bean tells us which bean the injection is happening on.

From this output you can see that the annotated property on the injectionPoint has information about which language feature (field, constructor argument, method argument, etc.). In our case it is the field org.cdi.advocacy.AutomatedTellerMachineImpl.transport. is being used as the target of the injection, it is the thing that was annotated.

From this output you can see that the bean property of the injectionPoint is being used to describe the bean whose member is getting injected. In this case, it is the AutomatedTellerMachineImpl whose is getting the field injected.

I won't describe each property, but as an exercise you can.

Exercise: Look up the InjectionPoint in the API documentation. Find out what the other properties mean. How might you use this meta-data? Can you think of a use case or application where it might be useful? Send me your answers on the CDI group mailing list. The first one to send gets put on the CDI wall of fame. (All others get honorable mentions.)

Drilling further you can see what is in the beans and annotated properties.



Code Listing: TransportFactory.createTransport drilling further into the meta-data about the injection point
    @Produces ATMTransport createTransport(InjectionPoint injectionPoint) {
        
        System.out.println("annotated " + injectionPoint.getAnnotated());
        System.out.println("bean " + injectionPoint.getBean());
        System.out.println("member " + injectionPoint.getMember());
        System.out.println("qualifiers " + injectionPoint.getQualifiers());
        System.out.println("type " + injectionPoint.getType());
        System.out.println("isDelegate " + injectionPoint.isDelegate());
        System.out.println("isTransient " + injectionPoint.isTransient());

        Bean<?> bean = injectionPoint.getBean();

        System.out.println("bean.beanClass " + bean.getBeanClass());
        System.out.println("bean.injectionPoints " + bean.getInjectionPoints());
        System.out.println("bean.name " + bean.getName());
        System.out.println("bean.qualifiers " + bean.getQualifiers());
        System.out.println("bean.scope " + bean.getScope());
        System.out.println("bean.stereotypes " + bean.getStereotypes());
        System.out.println("bean.types " + bean.getTypes());

        Annotated annotated = injectionPoint.getAnnotated();
        System.out.println("annotated.annotations " + annotated.getAnnotations());
        System.out.println("annotated.annotations " + annotated.getBaseType());
        System.out.println("annotated.typeClosure " + annotated.getTypeClosure());
        
        return new StandardAtmTransport();
}

Now we are cooking with oil. Throw some gas on that flame. Look at the wealth of information that the InjectionPoint defines.

Output
...
bean.beanClass class org.cdi.advocacy.AutomatedTellerMachineImpl
bean.injectionPoints [InjectionPointImpl[private org.cdi.advocacy.ATMTransport org.cdi.advocacy.AutomatedTellerMachineImpl.transport]]
bean.name atm
bean.qualifiers [@javax.inject.Named(value=atm), @Default(), @Any()]
bean.scope interface javax.enterprise.context.Dependent
bean.stereotypes []
bean.types [class org.cdi.advocacy.AutomatedTellerMachineImpl, interface org.cdi.advocacy.AutomatedTellerMachine, class java.lang.Object]
annotated.annotations AnnotationSet[@javax.inject.Inject()]
annotated.annotations interface org.cdi.advocacy.ATMTransport
annotated.typeClosure [interface org.cdi.advocacy.ATMTransport, class java.lang.Object]
...

We see that bean.beanClass gives up the class of the bean that is getting the injected field. Remember that one, we will use it later.

We can see that bean.qualifiers gives up the list of qualifiers for the AutomatedTellerMachineImpl.

We can also see that annotated.annotations gives us the list of annotations that are associated with the injected field. We will use this later to pull the configuration annotation and configure the transport with it.

Exercise: Look up the Bean and Annotated in the API documentation. Find out what the other properties mean. How might you use this meta-data? Can you think of a use case or application where it might be useful? Send me your answers on the CDI group mailing list. The first one to send gets put on the CDI wall of fame. (All others get honorable mentions.)

Ok now that we armed with an idea of what an Injection point is. Let's get configuring our transport.

First let's define an TransportConfig annotation. This is just a plain runtime annotation as follows:



Code Listing: TransportConfig an annotation used for configuration
package org.cdi.advocacy;


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



@Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface TransportConfig {
    int retries() default 5;
}

Notice that this annotation has one member retries, which we will use to configure the ATMTransport (transport).

Now go ahead and use this to decorate the injection point as follows:



Code Listing: AutomatedTellerMachineImpl using TransportConfig to configure retries
public class AutomatedTellerMachineImpl implements AutomatedTellerMachine {
	
    @Inject @TransportConfig(retries=2)
    private ATMTransport transport;

Once it is configured when you run it, you will see the following output from our producer:

Output
annotated.annotations AnnotationSet[@javax.inject.Inject(), @org.cdi.advocacy.TransportConfig(retries=2)]

This means the annotation data is there. We just need to grab it and use it. Stop and ponder on this a bit. This is pretty cool. The producer allows me to customize how annotations are consumed. This is powerful stuff and one of the many extension points available to CDI. CDI was meant to be extensible. It is the first mainstream framework that encourages you to consume your own annotation data. This not some obscure framework feature. This is in the main usage.

Please recall that the injectionPoint.annotated.annotations gives us the list of annotations that are associated with the injected field, namely, the transport field of the AutomatedTellerMachineImpl. Now we can use this to pull the configuration annotation and configure the transport with it. The party is rolling now.

Now we need to change the transport implementations to handle setting retires. Since this is an example, I will do this simply by adding a new setter method for retires (setRetries) to the ATMTranport interface like so:



Code Listing: ATMTransport adding a retries property
package org.cdi.advocacy;

public interface ATMTransport {
    public void communicateWithBank(byte[] datapacket);
    public void setRetries(int retries);
}

Then we need to change each of the transports to handle this new retries property as follows:



Code Listing: StandardAtmTransport adding a retries property
package org.cdi.advocacy;

public class StandardAtmTransport implements ATMTransport {
	
    private int retries;

    public void setRetries(int retries) {
        this.retries = retries;
    }


    public void communicateWithBank(byte[] datapacket) {
        System.out.println("communicating with bank via Standard transport retries=" + retries);
    }

}
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.

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.

Rick Hightower is CTO of Mammatus and is an expert on Java and Cloud Computing. Rick is invovled in Java CDI advocacy and Java EE. 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

Rogerio Liesenfeld replied on Tue, 2011/04/05 - 11:18am

Great stuff!

Unless I missed something, though, CDI does not (yet?) support injection into non-managed beans, as provided through @Configurable in Spring. Is this planned? And if it is, with build-time or load-time bytecode modification, or with either mechanism as in Spring?

Frank Schwarz replied on Tue, 2011/04/05 - 12:36pm

The source code is missing some angle-bracketed stuff, isn't it?

Rick Hightower replied on Tue, 2011/04/05 - 2:58pm in response to: Rogerio Liesenfeld

If you have a beans.xml under META-INF then that resource (classpath location or jar file) will get processed. It will process all of the Java classes in that jar.
All of the examples were tested with Resin CANDI and WELD.
I reserve the right to be wrong, but I am pretty sure I am right.

Rick Hightower replied on Tue, 2011/04/05 - 2:59pm in response to: Frank Schwarz

Well there was some angle brackets in the first article to activate Alternatives, but nothing in this article. No XML. No XML is needed.

Rick Hightower replied on Tue, 2011/04/05 - 5:35pm in response to: Rick Hightower

Clarification: The AutomatedTellerMachineImpl from the first article is not marked with any @Service, @Managed, etc. and it uses @Inject. But, AutomatedTellerMachineImpl is being "managed" when we look it up through the container.

The example would not work if you "new"ed AutomatedTellerMachineImpl instead of looking it up.

Dan Allen replied on Tue, 2011/04/05 - 9:12pm

You can also add beans programmatically using a CDI extension. Observe the BeforeBeanDiscovery event and use the addAnnotatedType method:

event.addAnnotatedType(beanManager.createAnnotatedType(MyClass.class));

That's one idea. We were using this in Solder for a while, but we opted to switch back to using beans.xml.

Samuli Saarinen replied on Wed, 2011/04/06 - 12:24am

Hi,

 Is the something missing from the last example code snippet or how this can work with identical annotation literals?

standardTransport = allTransports.select(new AnnotationLiteral(){}).get();
jsonTransport = allTransports.select(new AnnotationLiteral(){}).get();
soapTransport = allTransports.select(new AnnotationLiteral(){}).get();

 

Rogerio Liesenfeld replied on Wed, 2011/04/06 - 10:18am in response to: Rick Hightower

Yes, of course, I could do that.

But suppose I don't want to depend on a "ServiceLocator" lookup in top-level components, ie, I don't want to have to make calls like

AutomatedTellerMachine atm = BeanContainerManager.getInstance().getBeanByType(AutomatedTellerMachine.class);

in AtmMain.java. Instead, I would prefer to simply write

AutomatedTellerMachine atm = new AutomatedTellerMachineImpl();

BTW, this "Impl" class would probably be the only implementation in practice, so in most cases it would make more sense to not have the separate interface.

Personally, I prefer my business service classes to have initial state passed through a constructor. With injection into non-managed beans, it would be possible to use custom constructors and final instance fields, while still having dependencies injected into instances created with "new".

Rick Hightower replied on Wed, 2011/04/06 - 12:52pm in response to: Samuli Saarinen

Samuli,

Good eye. It appears I have a slight error in my code listing. DOH! I will fix it and repost that last listing. I meant to pass the annotation to annotation literal and then to the select. It appears I misfired. :)

Pobody's Nerfect.

Rick Hightower replied on Wed, 2011/04/06 - 7:12pm in response to: Samuli Saarinen

http://code.google.com/p/jee6-cdi/wiki/DependencyInjectionAnIntroductoryTutorial_Part2#Code_Listing:_AutomatedTellerMachineImpl_using_selects_and_some Ok... the angle bracket stuff was in it when I wrote it. :) It seems the JavaLobby engine thinks it is a tag and then strips it from the post (on the way out... the tags are in the post).

Rick Hightower replied on Wed, 2011/04/06 - 7:19pm in response to: Frank Schwarz

Ok... Frank... It has all of the angle bracket stuff back.

Rick Hightower replied on Wed, 2011/04/06 - 8:02pm in response to: Rogerio Liesenfeld

(I got the ideas from this response from someone... I am not sure if they want credit, but please chime in if you do... you know who you are....)

"There is no standards-defined way of injecting into objects instantiated via 'new' in CDI as you would do in the case of Spring @Configurable."

"It is doubtful whether there will ever be. The issue is that it would basically require mandating that all CDI implementations use AspectJ style byte-code manipulation as opposed to code generation, proxying, etc."

"If this is something that is really needed, you could create an AspectJ based tool for CDI that takes a class definition and adds CDI run-time look-ups behind the scenes to mimic injection/other CDI functionality. If run-time weaving is necessary, you would then need to specify a weaver for class-loading. In my opinion, this is not really something that needs to be done (as part of the JSR) since it adds additional build/compile/class-loading complexity for a very rare, domain-driven-design purist case. For example, I know of no Spring shops that use @Configurable or compile time weaving and a very small handful that uses load-time weaving."

I could see us adding something like this to CDISource.

Mark Struberg replied on Thu, 2011/04/07 - 12:50am

Hi Rick!

 

Good series!  I just like to add a few oftern overlooked gems. Today it's the @Typed Annotation. It can be used to explicitely declare the type of a bean. There are 2 cases where this is reaaaly handy.

 

Use case 1: 'disabling' a java class as bean

 

Let's say we have a 


@Typed()
public class Menu {
private String name;
private String action;
private Menu parent;
}

and we have a producer method like

@ApplicationScoped
public class MenuProducer {
private @Inject menuSvc;
private @Inject User currentUser;

public @Produces @SessionScoped Menu menuForUser() {
Menu menu = menuSvc.getMenuForUser(currentUser);
return menu;
}
}

 

 A Menu is naturally a tree with a 1:n parent menu relationship. So this will just be created via an @ApplicationScoped MenuServiceImpl or such - but never directly as a bean! Annotate the Menu class as @Typed() effectively says: this bean has no Type at all, thus it will not satisfy any injection point. This has almost the same effect as veto() ing a bean in an Extension (via @Observes ProcessAnnotatedType) but without needing to write an Extension. If we wouldn't annotate our Menu class as @Typed(), it would get picked up as @Dependent scoped bean automatically (I personally don't like that, but thats what the spec defines) - leading to an AmbiguousResolutionException.

 

The 2nd case where @Typed is really handy is if you have subclasses which should not get picked up as the base type:

 

/** 
* This menu service will provide
* read operations only!
*/
@ApplicationScoped
public class MenuService {
public Menu getMenuOfUser(User user) {
..
}
}
/** 
* This will add Administration
* functionality to our base MenuService
*/
@ApplicationScoped
@Typed(MenuAdminService.class)
public class MenuAdminService extends MenuService {
public addMenuPermission(Menu menuTree, String role) {
... }
public storeMenuTree(Menu menu) {
... }
}

 If I would not use the @Typed annotation at the MenuAdminService, then it would automatically satisfy all the types in it's whole class hierarchy - including the MenuService it extends. So if you would try to

private @Inject MenuService menuSvc; 

 then you would get an AmbiguousResolutionException (remember: both MenuService and MenuAdminService implement the MenuService type!). By adding 

@Typed(MenuAdminService.class)

it will only act as the type in the annotation and not automatically use all the parent types too! 


 

Rick Hightower replied on Thu, 2011/04/07 - 10:25am in response to: Mark Struberg

Thanks for adding this. Great info. Thanks again for taking the time to expand on this.

Mark Struberg replied on Thu, 2011/04/07 - 11:47am

Might as well add another tip: Beware of the Constructor!

Writing CDI bean initialisation code in Constructors is not a good thingy as you will see weird effects.

Remember - all beans you get injected (except  @Dependent ones) are always 'contextual references' = proxies for their underlying contextual instances! But CDI implementations do not use Java's own reflect proxy (because this one is only able to proxy interfaces) but must use instance proxies.

How goes? The CDI implementations I know (Weld, CanDI and of course OpenWebBeans) create proxies by dynamically subclassing the class which should get proxied. So whenever a proxy gets created, it will naturally also invoke the constructors up in the parent-class chain.

Thus writing the classic reference counter for your bean will give you wrong numbers:

@SessionScoped
public class MyBean implements Serializable {
  private static int refCounter = 0;

  public MyBean() {
    refCounter++;  // <- this will be called too often since the ct will also get called for proxies
  }
  ...
}

 Instead use the @PostConstruct or @Inject annotations on any method:

@SessionScoped
public class MyBean implements Serializable {
  private static int refCounter = 0;

  @Inject
  public void init() {
    refCounter++;  // <- this will be called too often since the ct will also get called for proxies
  }

  @PostConstruct
  pubic void anotherInit() {
  }
  ...
  @PreDestroy // ofc this works as well btw!
  public void cleanup() {
  }
}

 

Mark Struberg replied on Thu, 2011/04/07 - 12:19pm

btw, in your example above:
@Produces ATMTransport createTransport(InjectionPoint injectionPoint) {

please note that this would only work for producing @Dependent scoped beans! (which is exactly what you get if you don't explicitely specify another scope).

 

The reason why this only works with @Dependent scoped beans is that for all NormalScoped beans (@RequestScoped, @SessionScoped, @ApplicationScoped,...), you just don't know where they get injected into.

In fact, your contextual instance (your one-and-only instance of that bean in the given scope) will never get @Inject-ed directly, but instead you will always 'only' get a contextal reference (the proxy) injected into your injection point!

Ergo, this trick only works for @Dependent scoped beans...

 

Overally the JSR-299 spec is one of the best specs I've ever read. But as I already expressed above: I don't like the automatic pickup of not-explicitely scoped beans as @Dependent.

Reason is that this information is not really obvious and often gets forgotten.  If you forget about adding the scope annotation or per accident import e.g. javax.faces.beans.SessionScoped instead of javax.enterprise.context.SessionScoped - IDEs are damn good in picking up the wrong import ;) - you will end up with @Dependent. This mean you will be creating a new instance for each and every injection point and EL invocation - and loosing lots of data in between...

Rogerio Liesenfeld replied on Thu, 2011/04/07 - 12:44pm in response to: Rick Hightower

Indeed. If I have the time, I could implement a CDI portable extension that installs a java.lang.instrument.ClassFileTransformer at startup. The transformer would then modify bytecode in the constructors of classes containing injection points (while ignoring classes without such points). Such a modified constructor would end with a call to the InjectionTarget#inject(...) method.

Use of java.lang.instrument is much better and simpler than using AspectJ or compile-time instrumentation. And by using the Attach API, there is no need to have users manually add a "-javaagent:instrumentation.jar" JVM parameter when running an app/container. There is some runtime overhead, obviously, but I believe it should be small enough (based on my experience with the JMockit tools).

I wish CDISource the best of luck. CDI is great, and I am sure it will only improve.

Mark Struberg replied on Thu, 2011/04/07 - 12:58pm

@Rogerio:

 

I fear using -javaagent has one BIG problem: you will always hit the SystemClassLoader!

This is really a no-go  in EE server scenarios and any other situations where you need classpath isolation by using a ClassLoaders hierarchy. The whole javaagent approach is imo only useful if you have a standalone application.In all other situations you will most probably either break the application - or even worse - open a fat security hole without even notizing it!

All existing CDI implementations (Dan and Reza can confirm this for Weld and CanDI) are using a ClassLoader hack. So we are not using compile time instrumentation - in fact we don't change the original bean classes at all! We just additionally create proxies for them at runtime by 'dynamically' creating subclasses via in memory byte-code engineering.So you can still write code like

private MyBean myBean = new MyBean();

 

Mark Struberg replied on Thu, 2011/04/07 - 1:12pm in response to: Rogerio Liesenfeld

> support injection into non-managed beans

Stu (Stuart Douglas) of JBoss fame wrote a portable CDI Extension for exactly that [1]. This Extension basically will dynamically apply annotations to your classes - without having to write them in your code. It will give you the kind of XML config you might know from Spring 2.

 In general: if you are looking for CDI Extensions, then check JBoss Seam3 [2] and  Apache MyFaces CODI [3] first

 LieGrue,
strub

 

[1] http://docs.jboss.org/seam/3/xml-config/latest/reference/en-US/html_single/

[2] http://docs.jboss.org/seam/3/3.0.0.Final/reference/en-US/html/

[3] http://myfaces.apache.org/extensions/cdi/

PS: <shamelessselfadvert>the Seam3 doc is much better, but CODI is in some areas much more powerful ;) </shamelessselfadvert>

Rick Hightower replied on Thu, 2011/04/07 - 1:53pm in response to: Mark Struberg

RE: the Seam3 doc is much better, but CODI is in some areas much more powerful ;)


When I think of successful OS projects, they usually have on thing in common: good docs.

Facelets was well documented and easy to learn. Hibernate had excellent documents (not everyone agrees with this). Spring has excellent documents. etc. etc.

Docs are a good sign of the overall quality of a project. That being said. I am horrible at writing docs (see crank).

Reza Rahman replied on Thu, 2011/04/07 - 2:29pm

Yep - we do the same thing. In the early EJB 3.1 time-frame there was actually some talk of making EJB/JPA/CDI "new"-able. It was tabled because it gets hideously complicated for everyone involved - especially when you get beyond simple injection and there is a possibility the modified byte-code can be run in environments/class-loaders that you cannot entirely predict (e.g. taking a war that runs fine on Resin and try to run it on GlassFish). Basically it would require standardizing not just the API but how the API is actually implemented.

Rogerio Liesenfeld replied on Thu, 2011/04/07 - 3:26pm in response to: Mark Struberg

Hello Mark,

Actually, a ClassFileTransformer (registered through the java.lang.instrument.Instrumentation object provided by a "Java agent") can transform classes loaded by *any* classloader. In fact, the first parameter to the "transform" method is the ClassLoader which defined the class to be transformed. Therefore, the transformer implementation can decide whether to transform or not each class based on its defining classloader.

Also, it's not actually necessary to use the "-javaagent" parameter at all. A Java agent can be loaded programmaticaly (at least from JDK 1.6 on).

I have actually implemented this kind of stuff in a tool which uses multiple classloaders; it works.

Mark Struberg replied on Fri, 2011/04/08 - 3:59am in response to: Rogerio Liesenfeld

Hi Rogerio!

What I meant is that by using -javaagent alll the classes you need for the transformation will end up getting loaded via the SystemClassLoader. I'm not 100% sure yet about the 'transformed classes' butI think they also get loaded that way.

 You will see this effect if you use those libs with tomcat - they will just refuse to work. The reason is that tomcat implements a security feature to prevent people from overloading classes which got loaded via the SystemClassLoader. I stumbled accross this problem in OpenJPA:

https://issues.apache.org/jira/browse/OPENJPA-1454
https://issues.apache.org/jira/browse/OPENJPA-1410

I haven't yet used the programmatical way to use the javaagent in Java6 of course

Jessie Mear replied on Wed, 2011/09/07 - 6:40am

The latest release of the technology, JSR 314: JavaServer Faces 2.0, makes UI development for Java EE applications even easier through support for annotations and the addition of new features such as Facelets and composite components. java programmers

Rick Siskey replied on Thu, 2011/10/27 - 12:06am

CDI or Computer Design Integration understands what your business is like, its application, structure, the whole nine yards. After it gets the necessary information, it then evaluates what you require and finally, it formulates recommendations. - Rick Siskey

Krishna Bheeman... replied on Sun, 2012/06/24 - 9:49pm

Hi Rick is it posible to have @Inject @Any private Instance allTransports; and @Produces ATMTransport createTransport(InjectionPoint injectionPoint) { in same application? I am getting null for allTransports Thank you for your help

Pradeep Kumar replied on Wed, 2012/09/19 - 12:57pm

Thanks for adding this, great explanation, very useful for me..!!!!!!!!!!!

Mark Srikanth replied on Tue, 2014/05/20 - 8:07am

 great work really thank you for the info about sap .a free live demo on all sap courses.by Exp trainers  SAP BO Online Training .http://sapbusinessobjectstraining.com/

Vladislav Naydenov replied on Mon, 2014/06/30 - 9:06am

Hi, Rick.

I'm following your tutorial step-by-step and I can't make

 createTransport(InjectionPoint injectioPoint) 

to work only with @Produces annotation. I'm getting 

org.jboss.weld.exceptions.DeploymentException: WELD-001409Ambiguous dependencies for type [IATMTransport] with qualifiers [@Default] at injection point [[field] @Inject private com.automatedtellermachine.AutomatedTellerMachine.transport]. Possible dependencies [[Producer Method [IATMTransport] with qualifiers [@Default @Any] declared as [[method] @Produces public com.automatedtellermachine.transport.factory.TransportFactory.createTransport(InjectionPoint)], Managed Bean [class com.automatedtellermachine.transport.StandartATMTransport] with qualifiers [@Default @Any]]]

Comment viewing options

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