Skip navigation
2010

We are pleased to announce the availability of Seam XML Configuration 3.0.0.Alpha3 and Seam Persistence 3.0.0.Alpha1.

 

Seam Persistence

 

Seam Persistence brings transactions to managed beans, and also provides the Seam Managed Persistence Context, a conversation scoped extended persistence context for use in CDI based applications. Currently it provides the following features

 

 

In keeping with the spirit of he Seam Managed persistence context is configured via annotations:

 

@Produces
@ConversationScoped
@SeamManaged
@PersistenceUnit(unitName="myPu")
EntityManagerFactory factory;

 

The SMPC can then be injected directly into your managed beans:

 

@Inject
EntityManager em;

 

 

For more information check out the getting started guide.

 

[Download] [JIRA] [Reference Guide] [Project Page]

 

Seam XML Config

 

Seam XML Configuration allows you to configure CDI beans using XML, this release is mainly a compatibility and bugfix release, however there are some notable changes.

 

Seam XML now supports the concept of XML configured virtual producer fields. These fields can be used to configure primitive types and Java EE resources via XML:

 

<s:EntityManager>
  <s:Produces/>
  <sPersistenceContext unitName="customerPu" />
</s:EntityManager>
<s:String>
  <s:Produces/>
  <my:VersionQualifier />
  <value>Version 1.23</value>
</s:String>
<s:EntityManager>
  <s:Produces/>
  <sPersistenceContext unitName="customerPu" />
</s:EntityManager>

<s:String>
  <s:Produces/>
  <my:VersionQualifier />
  <value>Version 1.23</value>
</s:String>

 

This is equivilent to the following java:

 

class SomeClass {

  @Produces
  @PersistenceContext(unitName="customerPu")
  EntityManager field1;

  @Produces
  @VersionQualifier
  String field2 = "Version 1.23";

}

 

 

Using virtual producer fields it is also possible to configure the Seam Managed Persistence Context via XML.

 

The other notable change is that generic beans have been removed, as these are now provided as part of Weld Extensions.

 

[Download] [JIRA] [Reference Guide] [Project Page]

swd847

Weld, CDI and Proxies

Posted by swd847 Oct 12, 2010

This is a post about how Weld uses proxies, and some of the non-portable enhancements that weld includes to allow the proxying of classes that would not normally be proxiable.

 

In Seam 2 injection was performed dynamically via an interceptor. Every time a method was invoked on a Seam component the BijectionInterceptor would look up a value for each injection point on the component and inject it. When the invocation was complete the interceptor would then set the fields back to null, to prevent the component from hanging onto shorter lived components that would otherwise have been eligible for garbage collection. This approach works quite well, however it has two main problems:

 

- Performance

The bijection process is not particularly fast. If you were making repeated invocations on a component (from a <h:DataTable> for example) you would experience performance problems. The solution was to use @BypassInterceptors and not use dependency injection in methods that experienced performance problems.

 

- Thread Safety

If an unsynchronized application scoped component tried to inject a component with a narrower scope (e.g. a session scoped component) thread safety problems would occur. If two threads made calls to the component at the same time the second thread could end up accessing components from the first threads session. This could result in problems that only appear when the application is under load.

 

The CDI Approach To Dependency Injection

 

CDI uses a different approach to dependency injection. Instead of using interceptors, injection is performed once at bean creation time. Dependent scoped beans can be injected directly, as the dependent beans lifecycle is tied to the bean it is injected into.

 

For normal scoped beans however this approach will not work, as the lifecycles of the beans are different, so instead weld injects a proxy. A proxy is a subclass of the bean that is generated at runtime. This proxy overrides all the non-private methods of the bean class, when these overridden methods are invoked the proxy looks up the correct instance of the bean and then forwards the invocation onto the actual bean instance. Say for example we have the following:

 

 

@ConversationScoped
class PaymentProcessor
{
  public void processPayment(int amount)
  {
    System.out.println("I'm taking $" + amount);
  }
}

@ApplicationScoped
public class Shop
{

  @Inject
  PaymentProcessor paymentProcessor; 

  public void buyStuff()
  {
    paymentProcessor.processPayment(100);
  }
}

 

 

 

In this situation the PaymentProcessor instance is not injected directly into Shop. Instead a proxy is injected, and when the processPayment() method is called the proxy looks up the current PaymentProcessor bean instance and calls the processPayment() method on it. Conceptually, this would look sort or like this:

 

public class PaymentProcessor_$$Proxy extends PaymentProcessor
{
  public void processPayment(int amount)
  {
    PaymentProcessor instance = lookupBean();
    instance.processPayment(amount);
  }

  private PaymentProcessor lookupBean()
  {
    //get the correct instance from the BeanManager and return it
  }
}

 

This has several advantages over the seam 2 dynamic injection approach:

 

- No interceptors are required

In many situations this will be a big performance win.

 

- Proxies are thread safe

The proxy will always forward the invocation to the correct bean instance, even when multiple threads are accessing a bean at the same time.

 

- Bean lookup only happens when invoking a method on the bean

In seam 2 even if a method did not use an injected object, it was still created and injected. In CDI a bean will only be created when it is actually used.

 

With that said, there are some things you need to be aware of:

 

- When the proxy is created the bean constructor is called

This is because constructors always have to call the superclass constructor (well, mostly). As the proxy is a sub class of the bean, the bean constructor is invoked when the proxy is created. When using CDI instead of doing bean initialisation in the constructor, you should do it in a @PostConstruct method.

 

- Not all classes can be proxied

The CDI spec places some limits on which beans can be proxied, mainly due to technical restrictions in the JVM.

 

- You need to be carful implementing equals() for normal scoped beans

Classes that implement equals by comparing fields directly in the equals() method may not work as expected, as the class will be inspecting the fields of the proxy, and not the bean instance.

 

Which Classes can be proxied?

 

The CDI specification places the following limitation on normal scoped beans:

 

  • The must not be primitive types and array types
  • They must not be declared final or have final methods
  • They must have a non-private default constructor

 

Primitive types and array types cannot be proxied because they cannot be subclassed, and neither can classes which are declared final. Classes with final methods are also not allowed, as the final methods cannot be overridden to forward calls to the correct bean instance. These limitations are strictly enforced by the JVM, short of instrumenting classes as they are loaded to remove the final modifier, there is no way around them.

 

The constructor limitation is a bit less obvious. The JVM requires that all constructors either call another constructor on the current class or a constructor on the superclass. The means that the proxy subclass must call a bean constructor, and the only one one that makes sense is the default constructor. Although theoretically we could call a non-private constructor with made up arguments (such as nulls and zero's), there is a high chance that this will result in problems such as NullPointerExceptions, so for safety's sake the specification disallows it. This is where Weld's unsafe proxies extension comes into the picture.

 

Weld's Unsafe Proxies Extension

 

All JVM's provide a method of creating a class without calling the constructor. This is necessary for the serialisation API, which needs to create class instances without calling the constructor during the de-serialisation process. Weld can use these API's on some common JVM's in order to relax the constructor restrictions on normal scoped beans. This is enabled by putting an empty file

 

META-INF/org.jboss.weld.enableUnsafeProxies 

 

somewhere on the applications classpath. Internally this uses the sun.misc.Unsafe class, so at the moment it is only availible on JVM's where this class is available. This may be extended to work on other JVM's in future.

 

Using this extension means that normal scoped beans no longer require a default constructor. Proxies instances are created directly, and the bean constructor is never called. This functionality is currently available in the latest release of weld (1.1 Beta1).

 

The beans will still require a non-private constructor of some kind. This is due to another JVM restriction, that requires all constructors to call either a superclass constructor or another constructor on the current class. If all the constructors of a class are private then it is impossible to call super(). It it however possible to get around this restriction by generating some bytecode that when expressed in java would look like this:

 

public class MyClass
{
  public MyClass(int a)
  {
    this("");
  }

  public MyClass(String a)
  {
    this(0);
  }
} 

 

This is not valid java code, as the compiler will complain about the recursive initialisation. This is a java language restriction however, if we generate the corresponding bytecode directly using a library such as javassist we can then load this directly into the JVM.

 

Attempting to instantiate this class normally would result in a stack overflow, however we can use com.sun.Unsafe to bypass the constructor call altogether and create an instance of the proxy class. This functionality is currently only available when building from the latest sources.

 

Using these techniques it is possible to bypass all the constructor based limitations on normal scoped beans, albeit not in a very portable way.