Red Hat

In Relation To Hibernate ORM

In Relation To Hibernate ORM

Hibernate Core 3.3.2 maintenance release

Posted by    |       |    Tagged as Hibernate ORM Releases

Just got done releasing 3.3.2 with tons of fixes/enhancements/improvements including some much needed documentation updates and again building translated docs.

Next we start focusing on 3.5 and implementing JPA 2 support...

Hibernate Core 3.2.7 maintance release

Posted by    |       |    Tagged as Hibernate ORM Releases

I just pushed a new Hibernate Core maintenance release 3.2.7 for download. It is mostly minor fixes and improvements; check out the specifics in the change log either in Jira or SourceForge.

3.3.2 will be coming later this week or early next.

Linda blogs the typesafe query API for JPA 2.0

Posted by    |       |    Tagged as Hibernate ORM JPA

Linda has written up the new typesafe query API. I previously blogged the reasoning behind this stuff here and here.

An open issue that Linda doesn't mention is query execution. I'm trying to convince the rest of the group that we should carry the typesafety all the way through to the query result set. Here's what I wrote to the group a few weeks ago:

Folks, I figured out a refactoring that gives us a way to do typesafe result sets, avoiding the use of Result. In this new approach, CriteriaQuery and Query would both have a type parameter. You could write code like this, if you have a single selection:
  CriteriaQuery<Order> q = qb.create(Order.class);
  Root<Order> order = q.from(Order.class);
  q.select(order);

  Query<Order> eq = em.createQuery(q);
  List<Order> res= eq.getTypedResultList();
like this, if you have multiple selections and an object to wrap them in:
  CriteriaQuery<OrderProduct> q = qb.create(OrderProduct.class);
  Root<Order> order = q.from(Order.class);
  Join<Item, Product> product = order.join(Order_.items)
                                     .join(Item_.product);
  q.select( qb.construct(OrderProduct.class, order, product) );

  Query<OrderProduct> eq = em.createQuery(q);
  List<OrderProduct> res= eq.getTypedResultList();
Or, if you don't have a nice wrapper class like OrderProduct, you can fall back to use Result:
  CriteriaQuery<Result> q = qb.create();
  Root<Order> order = q.from(Order.class);
  Join<Item, Product> product = order.join(Order_.items)
                                     .join(Item_.product);
  q.select( qb.result(order, product) );

  Query<Result> eq = em.createQuery(q);
  List<Result> res= eq.getTypedResultList();
This change let's people directly get typesafe lists of entities or wrappers, which is something that many people have asked for!

The big point about this API is that I can't write a query which selects Foo and then try to put it in a List<Bar>. It's truly typesafe, end-to-end.

The sticking point with this is that javax.persistence.Query does not currently have the needed type parameter, and there are millions of queries written to the JPA 1.0 APIs which would suddenly spit compiler warnings if we added a type parameter. So we might have to introduce a new interface like TypesafeQuery or something.

Migrating databases with DBUnit

Posted by    |       |    Tagged as Hibernate ORM

In the last few weeks I had to migrate a MySQL database and it turned out to be more difficult than I thought. In the past I've used the tools that ship with MySQL, such as mysqldump and its various options. For the recent migrations that was surprisingly... impossible.

The first migration was from a latin MySQL database to a UTF encoded database. By default MySQL and the JDBC driver all use latin encoding (or they derive it from the system character set), so you better make sure that your database is using UTF8 if you want, for example, Chinese users to be able to store their data. I recommend doing this on a per-table basis, which is easy if you export the schema with Hibernate - just add an extension to your dialect. Also make sure that you set characterEncoding=UTF-8 on your JDBC connection string to initialize the SQL session properly. Note that the useUnicode=true switch is not necessary for MySQL 5.x.

The problem I had was the seamframework.org production database, which was latin encoded when it was created a year ago. I've been pushing migration back because we never had any issue with it and the manual migration with mysqldump and recode turned out not to work for me (some instructions for this if you want to try).

The second migration I was looking at was a migration from MySQL to PostgreSQL, for development and testing purposes. Now, many people use mysqldump for this, then fiddle about with its many command line options and switches (make it ANSI compatible SQL damnyou!) and then close their eyes and pray when they import the dump into Postgres. Well, that didn't work in my case because mysqldump exports bit typed columns as raw binary. You can't make it to export something like true or false or anything that you can import into a Postgres boolean type. The problem here is actually that MySQL (just like the mighty Oracle) doesn't support a true boolean datatype and that Hibernate defaults to creating a bit column for a java.lang.Boolean mapping. In retrospect, Hibernate should probably not do this on MySQL for portability reasons and use a tinyint(1) mapping - on the other hand it is fine if you always stay on MySQL.

So mysqldump didn't work in both cases, I had to find another solution. I solved it with DBUnit and a simple 20 line class:

import org.dbunit.database.IDatabaseConnection;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.QueryDataSet;
import org.dbunit.operation.DatabaseOperation;

import java.sql.Connection;
import java.sql.DriverManager;

public class Migration {

    public static final String[] TABLES = new String[]{ "FOO", "BAR", "BAZ" };

    public static void main(String[] args) throws Exception {
        System.out.println("Running Migration...");

        Class.forName("com.mysql.jdbc.Driver");
        //Class.forName("org.postgresql.Driver");

        Connection exportConnection = DriverManager.getConnection(
            "jdbc:mysql://localhost/mydb", 
            "johndoe", 
            "secret"
        );
        IDatabaseConnection exportDatabaseConnection = new DatabaseConnection(exportConnection);

        Connection importConnection = DriverManager.getConnection(
            "jdbc:mysql://localhost/mytarget?characterEncoding=UTF-8&sessionVariables=FOREIGN_KEY_CHECKS=0", 
            "johndoe", 
            "secret"
        );
        IDatabaseConnection importDatabaseConnection = new DatabaseConnection(importConnection);

        for (String table : TABLES) {
        System.out.println("Migrating table: " + table);
            QueryDataSet exportDataSet = new QueryDataSet(exportDatabaseConnection);
            exportDataSet.addTable(table, "SELECT * FROM " + table);
            DatabaseOperation.INSERT.execute(importDatabaseConnection, exportDataSet);
        }

        exportDatabaseConnection.close();
        importDatabaseConnection.close();
        System.out.println("Migration complete");

    }
}

This is the code I used to migrate from MySQL latin to MySQL UTF encoding. For the PostgreSQL migration, uncomment the driver and use a different import JDBC URL. Make sure that you disable foreign key checks for the importing SQL session as you don't know or control in which order tables and rows will be exported and imported.

XForms Visual Editor

Posted by    |       |    Tagged as Eclipse Hibernate ORM JBoss Tools

Remember the blog, How to create a visual DocBook editor in 10 minutes and how it described how to create a Docbook editor with the Visual page editor in JBoss Tools ?

It turns out Ronald van Kuijk picked it up and created a visual editor for XForms. He introduced his attempt on our forums yesterday, and in the evening he was fully running and did a blog showing of the features including screenshots.

Here are two of them (click for full size):

XForms as it looks by default without the plugin:

XForms as it looks with the plugin enabled:

You can download the experimental plugin here.

Since Ronald were so much on fire I instantly offered him to host the sourcecode for him at JBoss tools SVN .

That is what I like about open development, from idea to execution within less than 24-hours.

Have fun!

The first part of my new article, published today on JSFCentral, explains how you can increase the rendering performance of a data-driven, JSF-based Seam application by two orders of magnitude! The article originated out of a contract job I did over the summer (before joining Red Hat). I worked for a group of scientists to develop a data-driven application using Seam, JSF, and RichFaces. That means it comes straight to you from the real-world ;)

In the article, I point out several easy-to-fall-into traps that can hinder the performance of your application and go on to present several best practices that ensure your JSF-based Seam application can give the responsiveness of a desktop application a run for it's money. Go see for yourself! Sadly, you'll have to wait for part 2 to unfold to discover all the secrets and realize the full benefit.

You might be wondering what else I've been up to lately. JSF2, JSF 2, and more JSF 2. Over the course of the last several weeks I have been working on submitting proposals and implementations to port features from Seam to JSF 2. It's hard work because we're not just throwing the features over the fence, but working with the expert group to improve on them and ensure they integrate well with JSF, rather than just tacked onto the side. If things move along smoothly, I should be rolling out some blog entries about what is changing and how to use the new features.

Java 6 compiler plugins and typesafe criteria queries

Posted by    |       |    Tagged as Hibernate ORM JPA

There's been plenty of discussion in the JPA group about my typesafe criteria proposal. My new favorite feature of the Java language is javax.annotation.Processor. Java 6 annotation processors are derived from the APT tool that existed in JDK 5, but are built into javac. Really, the name annotation processor is misleading, since this feature is only incidentally related to annotations. The Processor is really a fairly general purpose compiler plugin. If, like me, you've never been a fan of code generation, now is the time to reconsider. A Java 6 Processor can:

  • analyze the compiler's metamodel of the Java source code that is being compiled
  • search the source path for other metadata, such as XML
  • generate new types, which will also be compiled, or other files

Best of all, this functionality requires no special tool or commandline options to javac. All you need to do is put the jar containing your Processor in the classpath, and the compiler does the rest!

In the typesafe query API, I want to use this to work around Java's lack of a typesafe metamodel for fields and methods of a class. The basic idea is that the compiler plugin will generate a metamodel type for each persistent class in the application.

Suppose we have the following persistent class:

@Entity
public class Order {
    @Id long id;
	
    boolean filled;
    Date date;

    @OneToMany Set<Item> items;

    @ManyToOne Shop shop;
	
    //getters and setters...
}

Then a class named Order_ would be generated, with a static member of each persistent attribute of Order, that the application could use to refer to the attributes in queries.

After several iterations, we've settled on the following format for the generated type:

import javax.jpa.metamodel.Attribute;
import javax.jpa.metamodel.Set;
import javax.jpa.metamodel.Metamodel;

@Metamodel
public abstract class Order_ {
    public static Attribute<Order, Long> id;
    public static Attribute<Order, Boolean> filled;
    public static Attribute<Order, Date> date;
    public static Set<Order, Item> items;
    public static Attribute<Order, Shop> shop;
}

The JPA provider would be responsible for initializing the values of these members when the persistence unit is initialized.

Now, criteria queries would look like the following:

Root<Item> item = q.addRoot(Item.class);
Path<String> shopName = item.get(Item_.order)
                            .get(Order_.shop)
                            .get(Shop_.name);
q.select(item)
 .where( qb.equal(shopName, "amazon.com") );

Which is equivalent to:

select item 
from Item item
where item.shop.name = 'amazon.com'

Or like:

Root<Order> order = q.addRoot(Order.class);
Join<Item, Product> product = order.join(Order_.items)
		                   .join(Item_.product);
		
Path<BigDecimal> price = product.get(Product_.price);
Path<Boolean> filled = order.get(Order_.filled);
Path<Date> date = order.get(Order_.date);
		
q.select(order, product)
 .where( qb.and( qb.gt(price, 100.00), qb.not(filled) ) )
 .order( qb.ascending(price), qb.descending(date) );

Which is equivalent to:

select order, product 
 from Order order 
    join order.items item
    join item.product product
 where
    product.price > 100 and not order.filled
 order by
    product.price asc, order.date desc

The queries are almost completely typesafe. Because of the generic type parameters of Attribute:

  • I can't pass an attribute of Order to a Join or Path that represents an Item, and
  • I can't try to perform a comparison like gt() on a Path that represents a boolean attribute, or not() on a Path that represents an attribute of type Date.

There's some skeptics in the expert group, but my feeling is that once people get used to the idea that type generation is no longer something that gets in your way during development, we're going to see a lot more frameworks using this kind of approach. I certainly think this API is a big improvement over the previous proposal:

Root item = q.addRoot(Item.class);
Path shopName = item.get("order")
                    .get("shop")
                    .get("name");
q.select(item)
 .where( qb.equal(shopName, "amazon.com") );

Or:

Root order = q.addRoot(Order.class);
Join product = order.join("items")
		    .join("product");
		
Path price = product.get("price");
Path filled = order.get("filled");
Path date = order.get("date");
		
q.select(order, product)
 .where( qb.and( qb.gt(price, 100.00), qb.not(filled) ) )
 .order( qb.ascending(price), qb.descending(date) );

Both these queries are riddled with non-typesafe method invocations which can't be validated without executing the query.

A typesafe criteria query API for JPA

Posted by    |       |    Tagged as Hibernate ORM JPA

The public draft of the JPA 2.0 specification is already out and includes a much-awaited feature: an API that lets you create queries by calling methods of Java objects, instead of by embedding JPA-QL into strings that are parsed by the JPA implementation. You can learn more about the API proposed by the public draft at Linda's blog.

There's several reasons to prefer the API-based approach:

  • It's easier to build queries dynamically, to handle cases where the query structure varies depending upon runtime conditions.
  • Since the query is parsed by the Java compiler, no special tooling is needed in order to get syntactic validation, autocompletion and refactoring support.

(Note that JPA-QL syntax validation and autocompletion is available is some IDEs - in JBoss Tools, for example.)

There's two major problems with criteria query APIs in the Java language:

  • The queries are more verbose and less readable.
  • Attributes must be specified using string-based names.

The first problem isn't really solvable without major new language features (usually described as DSL support). The second problem could easily be solved by adding a typesafe literal syntax for methods and fields to Java. This is now a sorely needed feature of the language, it's especially useful in combination with annotations.

There have been some previous efforts to work around the lack of method and field literals. One recent example is LIQUidFORM. Unfortunately that particular approach forces you to represent every persistent attribute as a public getter method, which is not a restriction that is acceptable in the JPA specification.

I've proposed a different approach to the JPA EG. This approach comes in three layers:

  • A metamodel API for JPA
  • A query API where types and attributes are specified in terms of metamodel API objects
  • Support for third-party tooling which would generate a typesafe metamodel from the entity classes

Let's go layer-by layer.

The Metamodel

The metamodel API is a bit like the Java reflection API, except that it is provided by the JPA persistence provider, is aware of the JPA metadata, and uses generics in a clever way. (Also it uses unchecked exceptions.)

For example, to obtain an object that represents an entity, we call the MetaModel object:

import javax.jpa.metamodel.Entity;
...
Entity<Order> order = metaModel.entity(Order.class);
Entity<Item> item = metaModel.entity(Item.class);
Entity<Product> item = metaModel.entity(Product.class);

To obtain attributes of the entity, we need to use string-based names, as usual:

import javax.jpa.metamodel.Attribute;
import javax.jpa.metamodel.Set;
...
Set<Order, Item> orderItems = order.set("items", Item.class);
Attribute<Item, Integer> itemQuantity = item.att("quantity", Integer.class);
Attribute<Item, Product> itemProduct = item.att("product", Product.class);
Attribute<Product, BigDecimal> productPrice = product.att("price", BigDecimal.class)

Notice how the metamodel types which represent attributes are parameterized not only by the type of the attribute they represent, but also by the type that they belong to.

Also notice that this code is non-typesafe and can fail at runtime if no persistent attribute with the given type and name exists in the entity class. This is the only non-typesafe code we'll see - our goal is keep the rest of the API completely typesafe. How does that help us? Well, the trick here is to notice that the metamodel objects represent completely static information about a persistent classes, state that doesn't change at runtime. So we can:

  • obtain and cache these objects at system intialization time, forcing any errors to occur upfront, or even
  • let a tool that has access to our persistent classes generate the code that obtains and caches metamodel objects.

That's much better than having these errors occur at query execution time, as they do in the previous criteria query proposal.

The metamodel API is generally useful, even independent of the query API. Currently it's very difficult to write generic code that interacts with JPA because JPA metadata may be partitioned between annotations and various XML documents.

But, of course, the most popular use of the metamodel is to build queries.

Queries

To construct a query, we pass metamodel objects to the QueryBuilder API:

Query query = queryBuilder.create();

Root<Order> orderRoot = query.addRoot(order);
Join<Order, Item> orderItemJoin = orderRoot.join(orderItems);
Join<Item, Product> itemProductJoin = orderItemJoin.join(itemProduct);

Expression<Integer> quantity = orderItemJoin.get(itemQuantity);
Expression<BigDecimal> price = itemProductJoin.get(productPrice);

Expression<Number> itemTotal = queryBuilder.prod(quantity, price);
Expression<Boolean> largeItem = queryBuilder.gt(itemTotal, 100);

query.restrict(largeItem)
     .select(order)
     .distinct(true);

For comparison, here is the same query expressed using the API proposed in the public draft:

Query query = queryBuilder.createQueryDefinition();

DomainObject orderRoot = query.addRoot(Order.class);
DomainObject orderItemJoin = orderRoot.join("items");
DomainObject itemProductJoin = orderItemJoin.join("product");

Expression quantity = orderItemJoin.get("quantity");
Expression price = itemProductJoin.get("price");

Expression itemTotal = quantity.times(price);
Predicate largeItem = queryBuilder.greaterThan(100);

query.where(largeItem);
     .selectDistinct(order);

Of course, this query could be written more compactly in either API, but I'm trying to draw attention to the generic types of the objects that make up the query. The type parameters prevent me from writing something like this:

orderItemJoin.get(productPrice); //compiler error

The use of generics means the compiler can detect when we try to create a path expression by combining a queried entity of one type and an attribute of some other type. The metamodel object productPrice has type Attribute<Product, BigDecimal> and therefore cannot be passed to the get() method of orderItemJoin. get() only accepts Attribute<Item, ?>, since orderItemJoin is of type Join<Order, Item>.

Expressions are also parameterized by the expression type, so the compiler detect mistakes like:

queryBuilder.gt(stringExpression, numericExpression); //error

Indeed, the API has sufficient typesafeness that it's more or less impossible to build an unexecutable query.

Generating a typesafe metamodel

It's completely possible to build queries with only the metamodel API and the query API. But to really make the most of these APIs, the final piece of the puzzle is a little code generation tool. This tooling doesn't need to be defined by the JPA specification, and different tools don't need to generate exactly the same code. Nevertheless, the generated code will always be portable between all JPA implementations. All the tool does is reflect upon the persistent entities and create a class or classes that statically cache references to the metamodel Entity and Attribute objects.

Why do we need this code generator? Because writing Attribute<Item, Integer> itemQuantity = item.att("quantity", Integer.class); by hand is tedious and slightly error prone, and because your refactoring tool probably isn't smart enough to change the string based name when you refactor the name of the attribute of the persistent class. Code generation tools don't make these kind of errors, and they don't mind re-doing their work from scratch each time you ask them to.

In a nutshell: the tool uses the non-typesafe metamodel API to build a typesafe metamodel.

The most exciting possibility is that this code generation tool could be an APT plugin for javac. You wouldn't have to run the code generator explicitly, since APT is now fully integrated into the Java compiler. (Or, it could be an IDE plugin.)

But didn't code generation tools go out of fashion recently? Wasn't one of the great features of ORM solutions like Hibernate and JPA that they didn't rely upon code generation? Well, I'm a great believer in using whatever tool is the right solution to the problem at hand. Code generation has certainly been applied to problems where it wasn't the best solution. On the other hand, I don't see anyone bashing ANTLR or JavaCC for their use of code generation to solve the problem they address. In this case, we're working around a specific problem in the Java type system: the lack of a typesafe metamodel (reflection is one of the worst-designed language features). And code generation is simply the only solution that works. Indeed, for this problem it works well.

Don't worry, the generated code won't be hard to understand ... it might look something like this, for example:

public class persistent {
	static Metamodel metaModel;

	public static Entity<model.Order> order = metaModel.entity(model.Order.class);
	public static class Order {
		public static Attribute<model.Order, Long> id = order.id(Long.class);
		public static Set<model.Order, model.Item> items = order.set("items", model.Item.class);
		public static Attribute<model.Order, Boolean> filled = order.att("filled", Boolean.class);
		public static Attribute<model.Order, Date> date = order.att("date", Date.class);
	}

	public static Entity<model.Item> item = metaModel.entity(model.Item.class);
	public static class Item {
		public static Attribute<model.Item, Long> id = item.id(Long.class);
		public static Attribute<model.Item, model.Product> product = item.att("product", model.Product.class);
		public static Attribute<model.Item, model.Order> order = item.att("order", model.Order.class);
		public static Attribute<model.Item, Integer> quantity = item.att("quantity", Integer.class);
	}

	public static Entity<model.Product> product = metaModel.entity(model.Product.class);
	public static class Product {
		public static Attribute<model.Product, Long> id = product.id(Long.class);
		public static Set<model.Product, model.Item> items = product.set("items", model.Item.class);
		public static Attribute<model.Product, String> description = product.att("description", String.class);
		public static Attribute<model.Product, BigDecimal> price = product.att("price", BigDecimal.class);
	}

}

This class just let's us refer to attributes of the entities easily. For example, we could type persistent.Order.id to refer to the id attribute of Order. Or persistent.Product.description to refer to the description of the Product.

I am please to announce the GA release of Hibernate Search 3.1. This release focuses on performance improvement and code robustness but also add interesting new features focused on usability:

  • An analyzer configuration model to declaratively use and compose features like phonetic approximation, n-gram approximation, search by synonyms, stop words filtering, elision correction, unaccented search and many more.
  • A lot of performance improvements at indexing time (including reduced lock contention, parallel execution).
  • A lot of performance improvements at query time (including I/O reduction both for Lucene and SQL, and better concurrency).
  • Additional new features both for indexing and querying (including support for term vector, access to scoped analyzer at query time and access to results explanation).

A more detailed overlook of the features follows

Analyzer

  • Support for declarative analyzer composition through the Solr library

Analyzers can now be declaratively composed as a tokenizer and a set of filters. This enable easy composition of the following features: phonetic approximation, n-gram approximation, search by synonyms, stop words filtering, elision correction, unaccented search and so on.

  • Support for dynamic analyzers

Allows a given entity to defined of the analyzer used at runtime. A typical use case is multi-language support where the language varies from one entity instance to an other.

Indexing

Indexing performance has been enhanced and new controls have been added

New features

  • Better control over massive manual indexing (flushToIndexes())
  • Support for term vector
  • Support for custom similarity
  • Better control over index writing (RAM consumption, non-compound file format flag, ...)
  • Better support for large index replication

Performance improvements

  • Improve contention and lock window during indexing
  • Reduce the number of index opening/closing
  • Indexing is done in parallel per directory

Querying

New useful features have been added to queries and performance has been improved.

New features

  • Expose entity-scoped and named analyzer for easy reuse at query time
  • Filter results (DocIdSet) can now be cached declaratively (default)
  • Query results Explanation is now exposed for better debugging information

Performance improvements

  • Reduces the number of database roundtrips on multi-entity searches
  • Faster Lucene queries on indexes containing a single entity type (generally the case)
  • Better performance on projected properties (no noticeable overhead compared to raw Lucene calls)
  • Reduction of I/O consumption on Lucene by reading only the necessary fields of a document (when possible)
  • Reduction of document reads (during pagination and on getResultSize() calls)
  • Faster index reopening (keeps unchanged segments opened)
  • Better index reader concurrency (use of the read only flag)

Libraries

  • Migration to Lucene 2.4 (and its performance improvements)
  • Upgrade to Hibernate Core 3.3
  • Use SLF4J as log facade

Bug fixes

  • Fix a few race conditions on multi core machines
  • Resources are properly discarded at SessionFactory.close()
  • Fix bug related to embedded entities and @Indexed (HSEARCH-142)
  • Filter instances are properly cached now
  • And more (see the change logs)

Download and all

You can download the release here. Changelogs are available on JIRA. Migrating to this version is recommended for all users (see the Migration guide).

Many thanks to everyone who contributed to the development and test of this release. Especially, many thanks to Sanne and Hardy who worked tirelessly pushing new features and enhancements and fixing bugs while John and I where finishing Hibernate Search in Action.

We have some features on the work that we could not put in 3.1, so stay tuned.

Web Beans and the EE platform

Posted by    |       |    Tagged as CDI Hibernate ORM

If there's one thing that we really want to get right as Web Beans goes from Public Draft to Proposed Final draft, it's integration with the Java EE platform. Up to this point, most of the work we've been doing as an EG was focused on nailing down the programming model, the semantics of the Web Beans services, and the behavior of the Web Bean manager. We've been writing the spec to assume that Web Beans implementations should be pluggable between different Java EE containers, because this is a direction that a lot of folks in the Java EE community believe that the EE platform should move in, and because we would like Web Beans to help show the way for other specifications such as EJB, JTA and perhaps even Servlets (note that JPA and JSF already support this).

Since the release of the Public Draft, our main focus has shifted to the integration problem. Web Beans generated a bunch of controversy when the draft was circulated to the EE platform expert group and proposed by Sun for inclusion in the Web Profile. That's not surprising - Web Beans solves some very important problems that lots of people have strong opinions on. I've also had a number of more technical discussions with the EE and EJB spec leads and with the EJB expert group. A number of concerns have emerged, which we're now attempting to address.

Let me share my take on these issues, and some directions we might pursue. But first...

...some history

In the days of EJB 1.x and 2.x, a major complaint against EJB was that the programming model was too restrictive. The specification imposed many annoying, distracting and unnecessary requirements upon developers. EJB 3.0 changed all that. Gone were the most of these annoying coding restrictions. In place of verbose XML deployment descriptors, EJB 3.0 was the first Java component model to be based around the use of annotations. In place of JNDI lookups was a simple dependency injection model, which ended up being generalized at the EE 5 platform level. I was a member of the EJB 3.0 expert group, and remain proud of what we accomplished.

However, the Java EE 5 dependency injection model was criticized from the outset. Many folks, including Rod Johnson of SpringSource, argued that the lack of support for injection of Java classes which were not EJBs was a fatal flaw. (At the time I did not agree, but I've changed my mind since.) On the other hand, I was dissatisfied with the lack of a contextual lifecycle model - though, in fairness, some other DI solutions of the time, including Spring, also lacked a contextual model. I was also unhappy with the mismatch between the JSF (XML-based, contextual) dependency injection model and the platform-level (annotation-based, non-contextual) model. This mismatch made it difficult to integrate EJB components with JSF.

Most of the changes introduced in EJB 3.0 and JPA 1.0 have stood the test of time remarkably well. The EE 5 dependency injection model has not. Contextual lifecycle management is now a standard feature of dependency injection solutions including Seam, Spring and Guice. Most importantly, Guice showed us the folly of using string-based names to identify implementations of an API. And Seam showed how to simplify application development by unifying dependency management in the web and EJB tiers.

Web Beans was initiated to address these problems. The original JSR proposal complained that:

  • EJB components are not aware of the web-tier request, session and application contexts and do not have access to state associated with those contexts. Nor may the lifecycle of a stateful EJB component be scoped to a web-tier context.
  • The JSF component model is not consistent with Java EE ... dependency injection...

The JSR promised to unif[y] the two component models and enabl[e] a considerable simplification to the programming model.

A new dependency injection model was needed: a model that provided contextual lifecycle management to transactional EE components.

Is Web Beans a component model?

In the Web Beans Early Draft, we characterized Web Beans as a component model. The specification defined two things:

  1. a set of restrictions that a Java class or EJB session bean must satisfy in order to be a Web Bean (principally, but not only, that it must explicitly specify @Component or another deployment type), and
  2. the services that would then be available to the Web Bean.

I viewed this as a unifying component model: a unification that would solve a major problem that has existed since J2EE - that the Java EE web tier has a completely different component model (actually, component models plural) to the transactional tier. It promised to tear down the wall between the two tiers, allowing transactional components to be aware of state related to the Web request. It promised a truly uniform programming model for components concerned with orchestration of the Web request, and components concerned with managing data access (at least when JSF was used).

This turned out to be the wrong approach. The strong feedback from the EE group was that Web Beans shouldn't define a new component model. The feedback from the EE spec leads at Sun was that the services defined by Web Beans should be available to all kinds of Java EE components - not just those which satisfied our definition of a Web Bean.

At Sun's urging, we made two changes to the specification. The first was primarily a language change. We repositioned Web Beans as a set of services, provided by a Manager analogous to the JTA TransactionManager, instead of a component model with a Container. But this also implied two more technical changes:

  1. we dramatically loosened the restrictions on what objects are Web Beans, so that every EJB session bean and every JavaBean is now a Web Bean, without any requirement for explicit declaration, and
  2. we provided a set of SPIs to allow objects which are not JavaBeans or EJB session beans to take advantage of the services provided by the Web Bean manager.

In particular, we provided injection into Servlets and message-driven beans (objects which by nature are not injectable) and an SPI that allowed other EE technologies and thirdparty frameworks to offer their components up for injection by Web Beans, and take advantage of the Web Beans services.

This was certainly the right thing to do, and the Web Beans specification is now more powerful and less intrusive. It still promises a more uniform programming model, but a side effect of these changes was that the model became even more generally useful, and even less specific to JSF and EJB. This isn't the first time I've seen something like that happen: the EJB 3.0 expert group also produced some technology (JPA, EE 5 dependency injection) that ended up being applied more generally than was originally envisaged.

Is Web Beans still a component model?

Unfortunately, some people are still not satisfied. A number of members of the platform expert group believe that the notion of a simple Web Bean still specifies a new component model. So what, exactly, is a simple Web Bean, and why do we need them?

A simple Web Bean is nothing new. It's just a Java class. You've already written hundreds or even thousands of simple Web Beans. Every JavaBean is a simple Web Bean. All we're trying to do is allow objects which were not specifically written as EJBs to be injectable and take advantage of the Web Beans services.

A simple Web Bean has the following advantages over an EJB session bean:

  • it does not need to be explicitly declared as an EJB using a component-defining annotation or XML
  • its interfaces do not need to be explicitly declared using @Local or @LocalBean
  • it can be final, or have final methods
  • it has a more natural lifecycle and concurrency model - the normal lifecycle for a Java class, instead of the enhanced lifecycle/concurrency semantics defined by EJB
  • if it's a stateful object, it does not require a @Remove method
  • it can take advantage of constructor injection

You can use preexisting JavaBeans and many other Java classes as simple Web Beans. As a side effect, simple Web Beans reduce the mental gap for new Java EE users who might be, initially, scared off by the unfamiliar EJB semantics - and the rather painful requirements to explicitly designate business interfaces and add empty @Remove methods - and let these new users get started with container-managed objects more easily.

On the other hand, unlike session beans, simple Web Beans, as currently defined:

  • don't have method-level transaction demarcation or security
  • can't have timeouts or asynchronous methods
  • can't have remote interfaces or be web service endpoints
  • don't have container-managed concurrency (locks)
  • don't support instance-level passivation or pooling

Therefore, in my opinion (an opinion shared the current and previous EJB spec leads), simple Web Beans don't compete with EJB as a solution for the transactional tier of the application. In fact, simple Web Beans aren't really anything new - Java EE developers already use EJBs and JavaBeans side by side. Web Beans just makes their life a little easier.

But some folks disagree. For example, one expert is worried that by providing something called a simple Web Bean, we're encouraging people to use them instead of EJB. The risk is that developers will be guided away from the use of non-simple EJBs. This has become a real sticking point in the EE group, and threatens to derail the whole Web Beans effort.

Of course, we're trying to work through this. One possibility is that we could move the definition of a simple Web Bean to the EJB specification, as a new EJB component type. Another possibility is to simply drop simple Web Beans from the specification, and ask everyone to write all their objects as EJBs.

Personally, I can't imagine releasing Java EE 6 with a dependency injection solution that doesn't support JavaBeans. All the other solutions in the space support both JavaBeans and EJB. EE 5 missed this boat - I don't want EE 6 to repeat the mistake. And I think that this is a case where users want to make the decision about when to use EJB. They don't want us to force a decision down their throats.

Injection of other EE resource types

A second issue raised by the EE experts is that the Web Beans specification does not currently define support for injection of all the various Java EE resource types. Specifically, Web Beans does not explicitly define injection of JDBC datasources, connections, web service endpoints, remote EJBs or persistence contexts. Of course, you can still use the existing Java EE 5 @Resource and @PersistenceContext annotations to inject Java EE resources, but then you'll miss out on the advantages of the more flexible and more typesafe model defined by Web Beans.

Well, the true situation is that injection of EE resources (or anything else at all) is already supported by Web Beans, assuming that the Java EE container calls an appropriate Web Beans SPI at initialization time. But neither the EE specification nor the Web Beans specification requires it to do so. So this is an issue that should be easy to fix.

Pluggability

We put a fair amount of effort into defining the interaction between the EE container and the Web Bean manager, for the purpose of supporting pluggable Web Bean managers. However, nothing that is currently defined imposes any new requirement upon the EE container. Unfortunately, at this point, there remain a number of open issues in the specification that can only be resolved by either:

  • dropping the requirement for pluggability or
  • imposing new requirements upon the EE container.

(Search for Open issue in the Public Draft if you're interested in knowing exactly what new requirements would be imposed upon the Java EE container.)

Either of these paths is technically feasible, but one of them is a lot more work and involves a lot more coordination between the various expert groups, some of which are already struggling to meet tight deadlines. If Web Beans is required in Java EE 6, it's not clear that pluggability is truly of great value to users. Does anyone really need to switch out their Web Bean manager?

I'd love to hear from the community whether pluggability is really worth pursuing.

Packages and naming

Quite a number of people hate the name Web Beans, which they see as obscuring the generality of the model we've defined. I view the name as more of a catchy brand than a definition of what Web Beans does. Think of Microsoft and .net. I don't mind changing the name, but nobody has yet suggested a great alternative. For one thing, I hate acronyms, and something descriptive like Java Dependency Injection wouldn't really capture all that Web Beans does.

Independently of this objection, quite a number of people think that it would be better to package our annotations by concern rather than putting them all in the package javax.webbeans. For example, the following package layout might make better sense:

  • javax.dependency - DI-related annotations: binding types, deployment types, @Initializer, @Produces, etc.
  • javax.contexts - scope-related annotations, Context interface
  • javax.interceptor (which already exists) - interceptor and decorator related annotations
  • javax.events - @Observes, event bus interfaces

I see repackaging as a great idea.

The good news

The good news is that there's very little debate about the actual technical details of the (Guice and Seam inspired) dependency injection model in Web Beans. The feedback I'm getting from spec reviewers is uniformly positive. This gives me a lot of confidence that the more political issues are also solvable.

What do you think?

The issues I've discussed in this post are important to all members of the Java EE community and to the future direction of the Java EE platform. I don't believe that we should be making these decisions behind closed doors, without the involvement of users. Please speak up and let us know what you want us to do. And please take the time to learn more about Web Beans.

back to top