I'm the creator of Hibernate, a popular object/relational persistence solution for Java, and Seam, an application framework for enterprise Java. I've also contributed to the Java Community Process standards as Red Hat representative for the EJB and JPA specifications and as spec lead of the CDI specification. At Red Hat, I'm currently working on Ceylon, a new programming language for Java and JavaScript VMs.
I now blog at the Ceylon blog.
I also post stuff on G+.
| Recent Entries |
|
30. Oct 2012
|
|
|
20. Mar 2012
|
|
|
26. Feb 2012
|
|
|
10. Jan 2012
|
|
|
12. Aug 2011
|
|
|
11. Aug 2011
|
|
|
06. Aug 2011
|
|
|
02. Aug 2011
|
|
|
01. Aug 2011
|
|
|
24. Jul 2011
|
|
|
22. Jul 2011
|
|
|
21. Jul 2011
|
|
|
20. Jul 2011
|
|
|
19. Jul 2011
|
|
|
17. Jul 2011
|
| Ceylon | (44) |
| Contexts and Dependency Injection | (44) |
| Web Beans | (41) |
| Seam News | (29) |
| Seam | (28) |
| Weld | (14) |
| Java EE 6 | (13) |
| Introduction to Ceylon | (12) |
| Hibernate | (6) |
| JavaServer Faces | (6) |
| JPA | (5) |
| JPA 2 | (5) |
| Web Beans Sneak Peek | (5) |
| Criteria Queries | (4) |
| Bean Validation | (3) |
| EE6 Wishlist | (3) |
| Portable Extensions | (3) |
| Seam Wiki | (3) |
| Web Frameworks | (3) |
| Interceptors | (2) |
| JBoss Tools | (2) |
| Payasos | (2) |
| XML Hell | (2) |
| Ceylon IDE | (1) |
| EJB | (1) |
| Granite DS | (1) |
| JDO | (1) |
| News | (1) |
| Persistence | (1) |
| Photography | (1) |
| RichFaces | (1) |
|
Java Persistence with Hibernate
with Christian Bauer November 2006 Manning Publications 841 pages (English), PDF ebook |
|
Hibernate in Action
with Christian Bauer August 2004 Manning Publications 408 pages (English), PDF ebook |
Since the release of Weld and Java EE 6, there's been a heap of activity in the Weld user forum, and especially a lot of questions about problems related to framework development. You can do some kinds of generic programming in CDI just using managed beans, producer methods and InjectionPoint. But if you want to get serious, you're eventually going to have to embrace the portable extension SPI. Here's a couple of examples of how people are using this SPI.
Steven Verborgh has written a nice tutorial showing how to implement a custom JSF view scope for CDI. Henri Chen has integrated the ZK framework with CDI (hopefully other web frameworks won't be far behind). Matt Corey has been experimenting with environment configuration via JNDI.
Meanwhile, I've been working on compiling user feedback into a list of enhancements to the SPI. We plan to roll the most important items into the first CDI maintenance release.
UPDATE: for completeness, I should also link Pete Royle's Quartz scheduling extension.
I've seen a couple of folks wondering why CDI requires a beans.xml file in every bean archive. If there's no alternatives, interceptors, or decorators to declare, why do you need to have the empty file?
Well, there's two things about CDI that we need to keep in mind:
- CDI does not require any special declaration for a Java class to be injected - that's right, no annotation or XML declaration at all!
- CDI does not define any special kind of module - CDI beans can be deployed in a library jar, EJB jar, war, rar, or JVM classpath directory.
The CDI specification calls the process of identifying beans in modules bean discovery.
So there are potentially a lot of classes in the classpath which might be beans! We don't want to force the container to scan every one of those classes at startup and build its internal metamodel for each of them. This really could make bean discovery very slow.
But there's another reason we need to give the user some control over which classes are available for injection. We don't want every class in the classpath to potentially match an injection point, including classes that were never intended to be injected into things. This would force the developer to have to use qualifiers much more often to disambiguate injection points.
So we have two choices. We could have the developer:
- explicitly exclude modules which do not contain beans, or
- explicitly declare modules which do contain beans.
I think it's clear that the second option is a much better way to go. Thus, CDI has the notion of a bean archive. A bean archive is just a module that has a file named beans.xml in the metadata directory. The container looks for beans in bean archives. It ignores other modules.
Now, you might be wondering if we've got the granularity wrong here. Why should module be the right criteria to use for including/excluding a class. Why not consider:
- a class-level annotation,
- the package,
- some type it implements or extends, or
- some naming convention.
Well, I think we've got the first option covered. Annotate a bean @Alternative, or with an alternative stereotype, and it will be considered disabled by CDI, as long as you don't explicitly enable it in beans.xml. That's not quite the same thing as excluding the class from scanning altogether, but it's close. (One difference is that a portable extension with still get a ProcessAnnotatedType event for that class.)
Excluding a package makes sense to me, and a future version of CDI might allow you to declare excluded packages in beans.xml.
Excluding a bean by type or naming convention doesn't appeal to me at all. In the world of CDI, we use stereotypes for identifying architectural roles. We don't use marker interfaces or naming conventions. I strongly disapprove of having names affect functionality.
We'll experiment with giving you some finer grained control over bean discovery in Weld. However, my expectation is that the current solution is going to work great for most people.
InfoQ has published a their questions and my answers about CDI and Weld.
Here's a CDI portable extension that reads values from properties files and configures fields of Java EE components. In Java EE 6, this works for any Java EE component supporting injection
, including servlets, EJBs, managed beans, interceptors and more.
In this example, properties for a class such as org.mydomain.blog.Blogger go in a resource named org/mydomain/blog/Blogger.properties, and the name of a property must match the name of the field to be configured. So Blogger.properties would contain:
firstName=Gavin lastName=King
The portable extension works by wrapping the containers InjectionTarget and setting field values from the inject() method.
public class ConfigExtension implements Extension {
<X> void processInjectionTarget(ProcessInjectionTarget<X> pit) {
final InjectionTarget<X> it = pit.getInjectionTarget();
final Map<Field, Object> configuredValues = new HashMap<Field, Object>();
AnnotatedType<X> at = pit.getAnnotatedType();
String propsFileName = at.getClass().getSimpleName() + ".properties";
InputStream stream = at.getJavaClass().getResourceAsStream(propsFileName);
if (stream!=null) {
try {
Properties props = new Properties();
props.load(stream);
for (Map.Entry<Object, Object> property : props.entrySet()) {
String fieldName = property.getKey().toString();
Object value = property.getValue();
try {
Field field = at.getJavaClass().getField(fieldName);
field.setAccessible(true);
if ( field.getType().isAssignableFrom( value.getClass() ) ) {
configuredValues.put(field, value);
}
else {
//TODO: do type conversion automatically
pit.addDefinitionError( new InjectionException("field is not of type String: " + field ) );
}
}
catch (NoSuchFieldException nsfe) {
pit.addDefinitionError(nsfe);
}
}
}
catch (IOException ioe) {
pit.addDefinitionError(ioe);
}
finally {
stream.close();
}
}
InjectionTarget<X> wrapped = new InjectionTarget<X>() {
@Override
public void inject(X instance, CreationalContext<X> ctx) {
it.inject(instance, ctx);
for (Map.Entry<Field, Object> configuredValue: configuredValues.entrySet()) {
try {
configuredValue.getKey().set(instance, configuredValue.getValue());
}
catch (Exception e) {
throw new InjectionException(e);
}
}
}
@Override
public void postConstruct(X instance) {
it.postConstruct(instance);
}
@Override
public void preDestroy(X instance) {
it.dispose(instance);
}
@Override
public void dispose(X instance) {
it.dispose(instance);
}
@Override
public Set<InjectionPoint> getInjectionPoints() {
return it.getInjectionPoints();
}
@Override
public X produce(CreationalContext<X> ctx) {
return it.produce(ctx);
}
};
pit.setInjectionTarget(wrapped);
}
}
The portable extension must be deployed in a jar with a file named META-INF/services/javax.enterprise.inject.spi.Extension containing the fully qualified extension class name.
One of the really nice things about Weld is how nicely it works in Java SE. Of course, if you run Weld on its own, you won't get nice functionality like EJBs (you'll need an embeddable EJB container for that), but you do get a bunch of great stuff, including:
- Managed beans with @PostConstruct and @PreDestroy lifecycle callbacks
- Dependency injection with qualifiers and alternatives
- @ApplicationScoped, @Dependent and @Singleton scopes
- Interceptors and decorators
- Stereotypes
- Events
- Portable extension support
The Weld distribution comes with an example console application, and an example Swing application.
Here's a very simple console application:
@Singleton
public class HelloWorld {
@PostConstruct
void init() {
System.out.println("Initializing Hello World application");
}
void printHello(@Observes ContainerInitialized event,
@Parameters List<String> parameters) {
System.out.println("Hello " + parameters.get(0));
}
}
The printHello() method is a CDI observer method for the ContainerInitialized event. This event is fired by the Weld Java SE extension when the console application starts. The command line parameters are available for injection using @Parameters List<String>.
As usual, we need a file named META-INF/beans.xml the the jar or classpath directory containing our HelloWorld class.
We run the application using:
java org.jboss.weld.environments.se.StartMain Gavin
Of course, if you're using CDI you probably want to make much more use of dependency injection, for example:
@Singleton
public class HelloWorld {
void printHello(@Observes ContainerInitialized event,
@Parameters List<String> parameters,
Hello hello) {
hello.say(parameters.get(0));
}
}
Where Hello is a bean:
public class Hello {
public void say(String name) {
System.out.println("Hello " + name);
}
}
The Weld SE extension was created by contributor Peter Royle.
| Showing 1 to 5 of 14 blog entries tagged 'Weld' |
|
|