Since we started our EJB 3.0 implementation, I've written a lot of unit tests and tutorials for it. Other than actually actually enjoying writing an EJB for a change, I thought alot about when and where XML should be used over annotations and in what situations annotations should probably be used over XML. I came up with these rules:

  1. Use an annotation if the metadata you are applying changes the design of your class.
  2. Use an annotation if the metadata changes the design of code interacting with your class.
  3. If your application needs to be portable between app-servers or databases, don't use an annotation that will not allow you to be portable
  4. Use XML when you want to configure on a per-deployment basis.


So, let's do a little exercise and walk through a few of the EJB 3.0 annotations. Let's start off with Session bean annotations.

 

@Stateless, @Stateful

Rule 1 is triggered here. You need to know if the EJB you are working with can hold state or not. Pretty obvious that this should always be used.

 

@Remote, @Local

At first glance, I thought that this possibly triggered Rule 4. Then I thought that it is important to know the semantics of the interface you are invoking on. Going through a @Remote interface forces call-by-value semantics. @Local forces call-by-reference. You'll probably want your application code to realize this just by navigating to the definition of the interface.

 

@TransactionAttribute

Rule 1 definately applies to @TransactionAttribute. Whether or not your code is invoked in the context of a transaction usually effects the design of your code. For example, you cannot access an EntityManager service when you aren't within a transaction. I don't think Rule 3 applies here since you probably don't even want to allow deployers to change your transaction boundaries at deployment time as the design of your code may depend on it. @TransactionAttribute looks like a good candidate for always being used.

 

Security annotations

For security annotations I think Rule 4 applies. Rule 1 isn't triggered because security probably has little to no effect on the design of the Session bean you are writing. Rule 3 isn't triggered because your application will remain portable, but you may want to configure security on a per-deployment basis. Then again, how often does one change XML DDs after the JAR is built? How often to operations people actually modify XML DDs?

 

Persistence

First let's look at purely logical Entity bean annotations. @OneToOne, @OneToMany, @ManyToOne, @ManyToMany, @Basic, @Serialized, @Transient. The relationship annotations give information about the bi or unidirectionalnes of a given relationship. This effects how you wire the relationships at runtime when creating or merging. The FetchType tells you whether or not the property will be lazily loaded or not. THis effect code interacting with your beans as to be totallyl performant, queries might have to use the "fetch" keyword to preload relationships in the same query. @Transient is important because you'll need to know whether something can be accessed within a query or not. @Transient properties might also something you'll want to initialize in a @PostLoad callback. So, all and all, I think these mappings fall under Rules 1 and 2.

What about table/column mappings? If you're not auto-generating tables, then Rule 3 probably doesn't apply. Table and column names should be portable across databases. Rule 3 is triggered if you're using annotation attributes like @Column.columnDefinition or annotations like @Lob (since some databases do not support blobs and/or clobs) though.

Rule 3 is also triggered when you're doing primary key generation. It would probably be best to use a generator and define the generator in XML so that it could be changed on a per-deployment basis. Some databases don't support Sequences or Identity generation for PKs.

@Entity public class Customer {

   @Id(generate="PLUGGABLE_GENERATOR") long pk;

}



Does Rule 4 apply to table mappings? It could. The same class could be needed in multiple O/R mappings for different legacy systems or databases.

 

Conclusion

It looks like for Session/MDBs, annotations might be preferrable over XML, while for persistence it is less clear. For persistence I think the general case will be to use annotations except for primary-key generator definition and the case where a class is needed to be mapped to more than one relational structure. Annotations will also be really nice when you have tools that generate Java code from relational schemas as you won't have to continually be referencing verbose XML documents to figure out how to interact with your persistent objects. Annotations are not only useful to describe metadata for frameworks, but are also a form of documentation. I remember Gavin talking at the NEJug saying that

 

@OneToMany(mappedBy="item")

Collection<Bid> getBids() {...}



is much less verbose than

 

/**

 * This is a OneToMany relationship to the Bids class.  It is also

 * bidirectional with the owning side of the relationship being maintained

 * by the "item" property on the Bid class

 */

Collection<Bid> getBids() {...}