« AJDT 1.1.9 Released | Main | Maven AspectJ 3.0 plugin released »

May 15, 2004

EJB 3.0 - What's wrong with @Inject?

The TSS Symposium gave us all a first glance of what's coming in EJB 3.0 (see Dion's write-up). The new spec has prompted a lot of debate, but I want to comment here on only one small part of it. It struck me as soon as I saw it on the slides, but I couldn't immediately put my finger on why I disliked it so: I'm talking about the use of the @Inject annotation to indicate a setter-method that the container will call to provide a bean with a reference to another bean, or to a service it depends on. Here's an example from the TSS article:

@Session public class MyBean { private DataSource customerDB; @Inject private void setCustomerDB(DataSource customerDB) { this.customerDB = customerDB; } public void foo() { ... Connection c = customerDB.getConnection(); ... } }

There are two separate issues raised here - why do I need the @Inject annotation at all, and if I do need an annotation, is @Inject the right one? Like it or not, annotations are coming. A prominent J2EE specification such as EJB should guide us in their correct usage, and not set a bad example. This morning it fully dawned on me why I think @Inject is a bad example, and it's based on the same reasoning we give for how we think annotations will be best used in conjunction with an aspect-oriented language like AspectJ.

The clue is in the name: "JSR 175: A metadata facility for the Java Programming Language." Annotations are supposed to be metadata - they are supposed to provide information about the language element being annotated: a good annotation describes some property of the thing it is annotating. If classes and data members are nouns, and methods are verbs, then annotations are like adjectives and adverbs, describing the classes, fields, and methods respectively. But "inject" isn't an adverb or adjective - it's a verb. "Inject" doesn't describe any property of the set-method, instead it sounds more like a compiler or run-time directive. That's not a good way to encourage people to think about annotations, though I'm sure we'll see many such abuses in time. The smallest possible change that would make me happier is to add two characters, "ed." That would give us the annotation @Injected, which does at least describe a property of the dependency (it's an injected dependency).

While I'm on the soap-box though, let me also say that the annotation @Injected still sounds a bit mechanistic to me, something that captures the intent more accurately, something a little closer to the intended semantics would be even better. My suggestion of the day is "@ContainerProvided," this annotation tells us that we expect a container to provide a value for us. A final suggestion: is this really a property of the setter-method, or of the data member itself? In the example above, it's the value of the customerDB field that is container provided - the setter method is just the means of achieving that end. Here's how the EJB would look if these suggestions were adopted:

@Session public class MyBean { @ContainerProvided private DataSource customerDB; private void setCustomerDB(DataSource customerDB) { this.customerDB = customerDB; } public void foo() { ... Connection c = customerDB.getConnection(); ... } }

I think it's better anyway - what do you think?


Some footnotes on the discussion:

1) One reason to put the @ContainerProvided annotation on the setter-method rather than the field is that this allows for 'virtual' fields, where there is no customerDB data member in the class, and the setter method performs some calculation based on the passed value without ever storing it. These (relatively rare) cases could be handled by annotating a set-method directly still.

2) A nice feature that follows from annotating the field directly rather than the setter-method, is that both constructor and setter dependency injection could be supported (and even direct field setting), giving more flexibility in different situations.

3) I didn't discuss the issue of whether the annotation is needed at all or not. Spring, pico, nano, and HiveMind all seem to get along fine without annotations. The only thing I can think of that the annotation really buys you here is the ability for a compile time/deploy time/runtime check to say "hey, you asked for this value to be container provided, but I can't find an appropriate setter method, nor a constructor parameter, and neither is the field visible for me to set it directly." That check might be useful if say, you're trying to get the container to provide you with a SessionContext and you misspell the setSesionContext method name - in EJB 3.0 I could see that failing silently without the annotation in place (interfaces used to solve that problem for us, but they're sooooo EJB 2.1 you know).

Posted by adrian at May 15, 2004 02:51 PM [permalink]

Comments

This is a good suggestion, in my opinion. It make sense and is more intuitive. Great job! BTW - The reason annotation are needed for IoC properties is that EJBs wil have many business methods - and in the case of CMP beans even persistent fields - which can be confused with injection methods. The @ContainerProvided helps the container distinguish business/persistent fields from IoC fields. Richard

Posted by: Richard Monson-Haefel at May 15, 2004 10:19 PM

Adrian Colyer asks What's wrong with @Inject? . He talks about how @Inject isn't really metadata, and I agree... Definitely if they're going to use an annotation for this, it should be renamed. The bigger issue is whether the annotation is needed...

Posted by: Jason Carreira at May 15, 2004 10:19 PM

Short version from TSS: How about a simple @Required or @Mandatory? One could also do the reverse and assume all setFoo()s are mandatory, and have an @Optional to mark those that aren't. Could be applicable to general JavaBeans also...

Posted by: Jonik Seeley at May 16, 2004 04:51 PM

And so, foloowing the same ideea, wouldn't it be beter this: @EJBType=Stateful|Stateless|Entity|MessageDriven public class MyBean { instead of this: @Session public class MyBean { I'm not really into Jdk1.5 Metadata, I'm only used to anotations from xdoclet. And I am used with anotations "anotating things" not intermingled in the code.

Posted by: Saint Peter at May 17, 2004 03:24 AM

@EJBType=Stateful|Stateless|Entity|MessageDriven


  public class MyBean { ...



instead of how it is now....

Sorry I'm failing miserably at HTML

Posted by: Saint Peter at May 17, 2004 03:27 AM

I think metadata should be also descriptive in what it's doing and easy to read/understand in the sense that one shouldn't read martin fowler's blog first to know what dependency injection is, to know that field is container provided.

Posted by: Saint Peter at May 17, 2004 03:29 AM

Adrian, I think I strongly disagree with using "adverb/adjective" in this particular case. Let's stay clear of "broad claims" on use of metadata and look at particular cases. The case of @inject is a COMMAND from the developer to the system. And that is good. It is direct and explicity. Easy to understand and says what I want to say AS A DEVELOPER. It says "container INJECT this dependency for me". The thing I don't like is reading code where I wonder "how in the HELL was this reference created..." if there is an external XML file there is too much magic going on and with a VERB it is clear and to the point, even if redundant in certain cases from a run-time standpoint (the container could figure it out), it is EXPLICIT from a CODING standpoint, and that is GOOD. Let's move on, bigger fish to fry in EJB3.

Posted by: marc fleury at May 17, 2004 12:08 PM

Guys...what a boring thing to focus on. I suggest @AbraCadabra

Posted by: Andrew C. Oliver at May 24, 2004 11:03 PM

Post a comment

Thanks for signing in, . Now you can comment. (sign out)

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)


Remember me?