Getting Started with JSF 2.0 and CDI in JEE 6 part 1
Here’s a quick tutorial on how easy it is to get started with JSF 2.0 and JSR 299, Java Contexts and Dependency Inject (CDI) using the latest release of Netbeans 6.8.
Read Part 1
Read Part 2
Read Part 3
Getting Netbeans and JEE6
First download the latest version of Netbeans (at the time of writing 6.8 has just been released). Make sure the download version you choose includes Glassfish V3 and java web and EE. Once downloaded, install it and get it up and running and we can start writing the application.
Starting the Project
Once Netbeans is up and running, start a new web project by clicking New Project and select the Java Web category and select a Web Application project and click next.
Give the new project a name (I called mine ee6demo) and a directory and click next. On the server settings, Glassfish v3 should already be selected so select next. In this tab, make sure Java Server Faces is selected and stick with the defaults in the lower panel that appears when you select it.
You can now click finish and Netbeans will create the project and open it up for you in the IDE. On the left you can see the project explorer and in the main tab you can see a file called index.html. Without doing anything, open the Run menu in the main menu and select “Run Main Project”. After a moment of activity and console logging a web browser window should open up with the message “Hello From Facelets” which is exactly what we can see in the index.xhtml file. So far, we haven’t done anything and we already have a working web application shell.
Just take a moment and look at the tabs on the left hand side, you should see Project,Files, and Services. Click on the services tab and expand the Servers node and you should see the Glassfish server we are using with a little green arrow on it indicating that the server is running. For now, we don’t need this because we aren’t actually going to deploy to the server again, no restarts and no manual deployments, so go back to the projects tab on the left.
Adding some code
In the projects tab, expand the “Source Packages” node and right click and select New->Java Class. Give the class the name MessageServerBean
and a package name (I used eedemo
). We annotate the class with the javax.inject.Named
annotation and a single method to return a string.
package eedemo; import javax.inject.Named; @Named public class MessageServerBean { public String getMessage() { return "Hello World!"; } }
This a managed bean as defined by CDI which in Glassfish v3 is implemented using Weld from JBoss. One thing we need to do now is tell the server that this project is a module containing CDI beans. We add a file called beans.xml
to the project in the WEB-INF folder. Right click on the WEB-INF folder in the project manager in the ee6Demo/Web Pages/folder and select New->XML Document. In the file name editor, just call it beans
, not beans.xml
as the IDE will add the xml extension for you and if you add the xml extension, the file will be called beans.xml.xml
(I’ve often tripped myself up with that one!). Open the beans.xml file in the editor, and select all the text and delete it so it is an empty file. You could alternatively just put
. (Note This file can be used to specify bean related information in xml so you aren’t limited to annotations)
The last change is to edit the index.xhtml
and replace the “Hello From Facelets” with our own text.
Message is : #{messageServerBean.message}<br/> Message Server Bean is : #{messageServerBean}
Save it and go to your browser and refresh the page (http://localhost:8080/ee6demo/
).
Message is : Hello World!
Message Server Bean is : eedemo.MessageServerBean@xxxxxxx
You should now see the message from the bean displayed on the page. Now go back into your message bean and change the message to something else (I used Hello From Weld!
), save the file and then refresh the browser. Your new message appears automatically since your application code has been hot deployed automatically by Netbeans . If you don’t see your changes just give it a second and refresh again.
From the second line in our page you can see that the class name is eedemo.MessageServerBean
and the bean is just a pojo. Even though this is JEE, there is no complex class hierarchy wrapped in layers of transactions, interceptors and all that ‘Heavy’ stuff you keep hearing about.
What’s going on?
When the application is deployed, the presence of a beans.xml
file signals that this module contains CDI managed beans so the classes on the path are scanned for CDI annotations. Our bean was annotated with the @Named
annotation and so this class was registered with Weld (under that name) (edit in a CDI module, all beans are registered with Weld, the named annotation is just used to match beans to injection points). When our JSF page was rendered, JSF tried to resolve the value of messageServerBean
in the page using the registered expression resolvers in JSF. One of these is the Weld EL Resolver which has the MessageServerBean class registered under the name messageServerBean
. We could have specified a name with the annotation, but since we didn’t it was registered under the default name of the class name with a lower case first name. The Weld resolver returns an instance of this bean in response to the request from JSF. Bean naming is only needed when using EL expressions and should not be used as the default mechanism for injection. CDI provides type safe injection by class type and stereotypes or qualifiers as we’ll see later.
Upgrading to an EJB
As we are using a JEE stack, we can easily deploy our bean as an EJB with some small changes thanks to EJB 3.1. Just open up the MessageServerBean
and add the javax.ejb.Stateless
annotation at the class level. Again, just save the file and go to your browser and refresh (no manual deploying, just save the file), and you should see something like :
Message is : Hello From Weld!
Message Server Bean is : eedemo.__EJB31_Generated__MessageServerBean__Intf____Bean__@xxxxxxx
Amazingly, we turned our pojo bean into a fully featured EJB with just one annotation, we saved it, and refreshed our page and our changes appeared, we don’t have to create any weird project configurations, local interfaces or arcane deployment descriptors.
Different EJB types
You can also try using the @Stateful
annotation (don’t forget to implement the java.io.Serializable
interface in the bean as it needs to be able to passivate (edit This isn’t necessary for it to be an EJB, but it is necessary if you want it to be session or conversation scoped)). Alternatively, you could try the new @Singleton
annotation for singleton instances. If you do, you may notice that there is a javax.ejb.Singleton
and javax.inject.Singleton
. Why two Singleton annotations? A single annotation in CDI lets you define a singleton instance outside of EJB in case you are using CDI in a non-EJB environment. An EJB singleton will have all the features of an EJB such as transaction management so you have the choice depending on your needs and whether the environment is EJB or not.
In this first part, we have created a new JSF 2.0 application, made it CDI enabled and added a managed bean which we then referenced from the web page. In part 2, we’ll start looking at creating more complex beans and injecting them into and with other beans.
Click to view Part 2
29 thoughts on “Getting Started with JSF 2.0 and CDI in JEE 6 part 1”
Comments are closed.
Nice introduction, thanks. Hot deployment is still a bit of a mystery to me though. Is it a feature of the application server, the IDE, or both? Does hot deployment of EJBs work with glassfish3/netbeans6.8 ? Apparently in JBoss it doesnt (https://jira.jboss.org/jira/browse/EJBTHREE-1096) which seems to be a serious issue for many people working on large apps. Some of them even ported all their EJBs to POJOs because of that.
Hot deployment is a server feature that the IDE takes advantage of. You can get the same hot deployment with Eclipse and the Glassfish v3 plugin.
I should also note that with the Seam hot deployment IIRC it required the beans to be held in a particular directory unlike the Glassfish V3 hot deploy which hot deploys a plain old web app (POWA?). Frankly, having used Glassfish with POJO, EJB, and CDI hot deployment (it can hot deploy anything it seems) I don’t know whether I can do without full hot deployment.
It does have drawbacks though, if you have an ORM and rebuild the tables on deployment, it will also be rebuilt on each hot deployment which can be a problem, so I could see a point where I might turn off the automatic hot deployment when I save each file.
Hi Andy, nice tutorial!
A couple of comments:
It’s not quite accurate to say: “Our bean was annotated with the @Named annotation and so this class was registered with Weld.” The bean would be registered with Weld even without an @Named annotation. All the @Named annotation does is make the bean available in EL.
Secondly, you should not need to implement Serializable to make the bean a stateful session bean. That’s not required by the EJB spec.
Hey Gavin,
Thanks for the heads up on the Serializable issue, I was probably thinking of the session/conversation scopes where you need to implement Serializable and you probably wouldn’t have a request scoped stateful session bean.
Regarding the @Named annotation, I have no idea why I wrote that because I cover the fact that all beans are registered with Weld in part 2 which was nearly complete when I put this one out, I’ll put an edit in the post to mention this.
Cheers,
Andy
Hi,
You may also want to check a presentation I did on some cool features of Weld here http://ejn3.blogspot.com/2009/12/weld-di-and-glassfish-example.html
Cheers
“Thanks for the heads up on the Serializable issue, I was probably thinking of the session/conversation scopes where you need to implement Serializable and you probably wouldn’t have a request scoped stateful session bean.”
Actually it’s even better than that.
A @SessionScoped or @ConversationScoped plain managed bean needs to implement Serializable, but a @SessionScoped or @ConversationScoped stateful session bean doesn’t, since the container takes care of passivation under the covers.
Don’t worry, you don’t actually need to remember these rules, since the CDI implementation is required to report an error if you forget to implement Serializable in something that needs to be serializable 🙂
Heh, I never really thought about it much before but yes, I’ve written stateful session beans without the Serializable interface before and never thought about it. It’s often one of those things that is an after thought at least until you run into errors because it isn’t there.
Spring web flow and wicket often require the serializable interface to be implemented by beans but won’t tell you until it needs to use it. That is one of the nice things about CDI is the early warning, now if we can just get that in some tooling 😉
If I have an EJB class, do I still need to include @ManagedBean (or @Named) in order to inject the bean in the JSF page?
“If I have an EJB class, do I still need to include @ManagedBean (or @Named) in order to inject the bean in the JSF page?”
If you want to use a bean in EL (any kind of bean, including EBs), yes, you need a @Named annotation. You don’t need any annotation if you want to inject the bean into another Java class.
If you define a bean with @ManagedBean, NetBeans helps you by including the bean’s name on a code assist list when you press Ctrl-Space inside the #{} of an EL, and, besides that, it shows all the public methods of the bean when you type the “.”
If you use @Named, it doesn’t, which is a pity, because this feature is very helpful (you don’t have to remember all the beans names and methods).
I filed this bug at bugzilla: https://netbeans.org/bugzilla/show_bug.cgi?id=178687
I hope they fix that soon.
Maybe it’s related to the severe warning shown when using javax.ejb.Singleton (Weld javax.inject.Singleton doesn’t show that error) Any idea why?
[#|2009-12-19T01:29:19.423+0100|SEVERE|glassfish|global|_ThreadID=16;_ThreadName=Thread-1;|The annotation symbol defined in super-class is not compatible with Session ejb ElaphusManager.
Anyway, I can also get JEE injection services (@PersistenceContext for example) when using @ManagedBean. @Named annotation will just return an instance of the class without any JEE services.
symbol: TYPE location: class com.cervatoh2.elaphus.ejb.ElaphusManagerBean
Geraldo, yes, it’s a shame the auto completion in Netbeans doesn’t have CDI beans included which I’ve also mentioned in other posts. It’s a shame that just as standard JSF gets some nice auto completion, every is moving to (or should be moving to) CDI.
Ignacio, no idea on the error, it may depend on something else in your code as I haven’t experienced it. There are a number of examples (in the docs and I think on Gavins blog) about setting up a producer method to make a persistence context available in any CDI bean. Off the top of my head, it is as simple as creating a bean into which you put the persistence context and mark the getEntityManager() method as a producer. (something like that).
Agreed, it is a shame auto completion does not work for CDI beans. I’m a member of NetBeans team which works on Java EE 6 support and I will make sure we fix it ASAP. CDI specification changed several times and we could not include support for CDI in NetBeans 6.8 because of time and resource constraints. I don’t know exact date when NetBeans CDI support module will be available, especially with coming Christmas break, but what I know is that it has already some other cool features like navigation from injection point to class being injected. Also the need to create beans.xml should be simplified by the IDE if not done automatically.
Thanks for your feedback,
David
Ah great stuff David, I really like the JSF support in Netbeans 6.8 and am looking forward to the new CDI support.
I think Netbeans 6.8 is providing better support and features for Java EE 6 than it has for any of the previous versions making it a really attractive environment for a really attractive platform.
How were you able to work around the problem one of your other readers submitted here: https://jira.jboss.org/jira/browse/WELD-350 (NPE on redeploy).
There is a comment 13/1 to say that it is fixed in trunk. Did you need to patch your GlassFish installation?
I have tried starting GlassFish with a different weld-osgi-bundle I found here:
http://oss.sonatype.org/content/groups/jboss/org/jboss/weld/weld-osgi-bundle/1.0.1-SNAPSHOT/
Apologies Daniel, I thought I had replied to your comment.
If it is the thing I think you are seeing, I believe this is an NPE on redeploy where it cannot restore the session state so the session data prior to the redeploy is lost. While this might be an error, its not one I care about to much since the redeploy works just fine, just the session information is lost which I can live with for the things I do with it. In short the answer is, no I don’t have a work around, it seems to be fixed though, but even if it isn’t in your current version, don’t worry about it unless having a reset session state on redeploy is a big deal.
Cheers,
Andy
Thank’s Andy Gibson, for this preview of two of the best players actually : Seam, an evolution of JEE, transformed in the JSR-299, and Facelets, now the default view of JSF2.0.
Thank you very much, Seam (Gavin)
Good night Andy.
It is possible to perform the injection of persistent classes?
Example:
@ Entity
public class ClientBean implements Serializable {
/ / Attributes
}
@ Named
@ SessionScoped
public class ClientController implements Serializable {
@ Inject
private ClientBean clientBean;
}
Diego, probably not because they come from different places. Hibernate needs to construct entities and CDI constructs beans for injection. If you did this, it would just inject a new instance of the entity. How would you load an entity with a specific ID? (CDI wouldn’t know how).
See my latest blog post (http://www.andygibson.net/blog/tutorial/pattern-for-conversational-crud-in-java-ee-6/) on how to handle entities.
Cheers,
Andy Gibson
Hello Andy, thanks a lot! I tried this with JBoss 6.0 and it worked.
Just one thing: Upgrading to an EJB:
I was not able to store form data in a stateful session bean. Do I have to create a local/remote interface?
I annotated the MessageServerBean with @stateful, created a String attribute, getter, setter.
The result was, that the setter was called with the right string, but the getter always returned null. Hence new new object was created each time the page was reloaded. Can you help me please ? Thanks Chris
Hi Chris,
Add javax.enterprise.context.@RequestScoped to the bean to give it scope. Currently the bean is without a scope (my bad). If it uses the default (no) scope then a new bean is created for each call. One is created for the setter and another for the getter. Adding request scoped means the same one will be used for the life of the request. I’m guessing you have an input box or something on the page to set the value on postback?
Cheers,
Andy Gibson
Thank you Andy, that’s it. And your completely right! I used a test input post to pass values from one page to the other. Thanks again.
I tried to make the example webapp, with a difference: the war is contained in an EAR. In this case I can’t deploy, due to java.lang.ClassNotFoundException: WEB-INF.classes.eedemo.DefaultItemDao.
Does anyone have any suggestion to make this simple example working? In my app, I want an EAR containing some WAR and some EJB_JARs packages.
Thank you. Andrea