I've been developing software for over 15 years working in Delphi and now Java. This site is a home for my open source projects, writings, articles and tutorials mainly focusing on Java and Java EE. Andy is a DZone MVB and is not an employee of DZone and has posted 34 posts at DZone. You can read more from them at their website. View Full User Profile

Seam Faces makes JSF entity Converters a Breeze

08.23.2010
| 7140 views |
  • submit to reddit

One of the first Seam 3 Modules to appear is the Seam Faces module which provides additional functionality to JSF. While there aren’t many pain points left in JSF, one of the biggest is the issue of data converters for entity objects. This article will take a look at how Seam Faces takes the pain out of writing JSF converters.

Download

Download the Seam Faces Demo Source for Maven

Typically, JSF converters come in two different types, the first converts strings to other strings, numbers or dates and vice-versa. Examples might be dates, formatted phone numbers or social security numbers. These converter are usually isolated and rely on internal logic defined in the converter.

The second kind, which is far more problematic, involves using information outside the converter to perform the conversion. The simplest case being an entity lookup which is represented in the view layer by the primary key value and upon posting back to the server, converted to the entity based on that id. These converters require some mechanism to get the entity from the database based on the Id. JSF doesn’t allow any kind of resource injection in converters so it was always a problem. Seam has a s:convertEntity tag just for the purpose of loading the entity from the database.
With special tags, it is often easier to just hook up lookup components to Long attributes and fetch the actual entity manually on the server side.

The Seam 3 module provides features that augment the existing JSF feature set and provides among other things, converters that can have beans injected to them like they are CDI beans. With this, we can implement converters that take the Id and load the entity from the database.

Here’s some quick demo code to demonstrate the process. The application uses the jee6-sandbox Knappsack archetype and requires either Glassfish or JBoss AS 6 to run.

I created a new project and in the DataFactory.java class I added a producer method to return a list of teachers.

@Produces
@Named("teachers")
@ApplicationScoped
public List<Teacher> getTeachers() {
List<Teacher> teachers = entityManager.createQuery(
"select t from Teacher t")
.getResultList();
return teachers;
}

This makes an application scoped list of teachers available in our application, where they will be used to provide a lookup list.

Now we’ll create a backing bean that has a teacher attribute that we want to set via the lookup list.

package org.knappsack.demo.seam.seamfaces.bean;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

import org.knappsack.demo.seam.seamfaces.model.Teacher;

@Named
@RequestScoped
public class PageBean {

private Teacher selected;

public Teacher getSelected() {
return selected;
}
public void setSelected(Teacher selected) {
this.selected = selected;
}
}

Now we’ll write our converter which implements the javax.faces.convert.Converter interface.

@SessionScoped
@FacesConverter("convert.teacher")
public class TeacherConverter implements Converter,Serializable {

@Inject
@DataRepository
private EntityManager entityManager;

@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
Long id = Long.valueOf(value);
return entityManager.find(Teacher.class, id);
}

@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return ((Teacher)value).getId().toString();
}

}

The @FacesConverter annotation marks this class as a converter when it is processed by CDI and gives it a converter Id for use in a JSF page.
To convert the object to text, we just return the id of the object. To convert from text to an object (a Teacher instance) we load the instance from the database using the injected entity manager.

To use this converter we just add this content of the home.xhtml page :

<ui:define name="content">
<h:form id="form">
<h:outputText value="Selected : #{pageBean.selected.name}" id="msg" />
<br />
<h:selectOneListbox value="#{pageBean.selected}" id="selector"
converter="convert.teacher">
<f:selectItems value="#{teachers}" id="items" var="v_teacher"
itemLabel="#{v_teacher.name}" />
</h:selectOneListbox>

<h:commandButton value="Update" action="update" />
</h:form>
</ui:define>
Seam Faces Screenshot

This page presents a list of teachers in which you can select one, click the update button and the selected teacher message at the top will change. The the only additional code we have is the converter which is a very simple class to write and can be re-used everywhere we have a teacher entity by just specifying the converter name. You could even create a generic entity converter to be used for all your entities.

Injection is not just limited to entity managers, we can inject any kind of bean in there so our options are limitless. One good use case is the injection and re-use of application scoped lists of cached data instead of re-hitting the database all the time.

Download the Seam Faces Demo Source for Maven, unzip it and see the readme.txt file for deployment instructions.

 

From http://www.andygibson.net/blog/article/seam-faces-makes-jsf-conversion-a-breeze/

Published at DZone with permission of Andy Gibson, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Cosmin Mutu replied on Tue, 2010/08/24 - 12:25am

Nice article,

But I don`t see where exactly are you using seam`s tag : s:convertEntity ?

All your code is standard JSF so far ... am I wrong?

Andy Gibson replied on Tue, 2010/08/24 - 7:51am

My apologies, I should have written that a little better,yes, it is all just JSF 2 code.

 Seam 2 has a tag for converting entities, with Seam Faces in Seam 3 you can write your own in a few lines of code. In Seam 2 and Java EE 5, there was no easy way to inject dependencies into converters so it was a bigger deal. 

Cheers,

 Andy Gibson

 

Jacek Furmankiewicz replied on Tue, 2010/08/24 - 8:25am

I can't believe such a basic requirement (converters for dropdowns) isn't provided by the base JSF 2.0 functionality. When we were evaluating Django vs JSF 2.0 for our internal web development having to define these stupid converters for every entity was the last straw. After all these years of design-by-committee JSF still couldn't deliver a simple, easy to use framework that covers such basic pain points as this. Did anyone see how this is done in Django? One line of code in your model (the FK relationship) is enough for the dropdowns in the UI get converted automatically. That's the ease-of-use and productivity JSF 2.0 should have delivered.

Andy Gibson replied on Tue, 2010/08/24 - 9:24am in response to: Jacek Furmankiewicz

Jacek, it is possible to set the converter for a specific type (ie. some BaseEntity class) so you don't need to specify it. This requires just the converter above and a line of configuration code to achieve exactly what you are referring to.

Should such functionality be included from the get-go? It raises questions about how does the converter know which database connection it should be using to fetch the entity, or whether it should be using a pre-fetched cached list of entities for the lookup instead, or even a non-persisted list of objects. There is also the problem of making JSF dependent on a persistence library. Converters with injection also makes it dependent on the CDI API. When you end up with JSF that depends on JPA and CDI, you aren't far from someone complaining that its wrong to have such dependencies and will start calling it heavyweight.

I agree that JSF 2.0 still doesn't hit the mark with regards to having smarter converters (or validators) with resources injected into them. Converters with Injection for me is the sweet spot that lets me easily define what I want to do without defining it for me and making me go around the default when I don't need it.

 Cheers,

 Andy Gibson

Jacek Furmankiewicz replied on Tue, 2010/08/24 - 9:53am in response to: Andy Gibson

The problem is that while the JCP is taking years to come up with a decent "standard" web framework for Java, the competition is leapfrogging us.

I tried very hard to convince myself that JSF 2.0 is the way to go for us, after already completing a prototype of our app in Python Django. But the difference in productivity (and complexity) was so huge between the two that we made the conscious decision to add an extra language to our mix.

I did it with a certain degree of sadness, 'cause as an old Java fanatic I would want my fav language to deliver the best solution in every area. But, unfortunately in this case it was fair inferior. So much for the standard Java EE APIs that some folks seem to be so gung-ho about.

Andy Gibson replied on Tue, 2010/08/24 - 11:10am in response to: Jacek Furmankiewicz

I think the design by committee thing does create a lag that is disheartening but I think people need to adjust their perspective of what the standards are.

Non-JCP projects innovate and the JCP takes those ideas and puts the rubber stamp of standardization on them. This is like most bodies where real world practices lead to standardized solutions, (i.e. building codes).These practices exist long prior to the standards body making it official.

While some of the features of Java  EE 6 add-ons will make it into Java EE 7, they will have been available and usable for a couple of years prior to getting that rubber stamp, so there really is no lag. For some reason Java EE must be judged on the merits of the framework alone, while other frameworks get judged based on the framework plus all the add ons. Using Django doesn't invalidate the idea of using Python alone any more than using Seam Faces invalidates the use of Java EE 6.

That said, Java EE 6 has much to get gung ho about, especially if you are writing web applications, and provides a solution that doesn't require add-ons except in cases like this to make things easier. I'm not sure what areas you felt were lacking in productivity and simplicity. I find myself very productive with it, however, each to his own and it all depends on what kinds of things you were trying to do. JSF probably isn't much use if you want a site built with Javascript and web services, but then, that's not what JSF was built for.

Cheers,

Andy Gibson

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.