Mixing JPA with JAXB/JAXWS
With JavaEE 6, you can publish an SOAP WebService as easy as 1-2-3. It mixes well with JPA, but I give you a small advice: if you need bidirectional ORM mappings, one of them MUST be @XmlTransient. Otherwise, you will receive a com.sun.xml.ws.streaming.XMLStreamReaderException ("unexpected XML tag. expected: {yourns}yourtag but found: {http://schemas.xmlsoap.org/soap/envelope/}Envelope").
h:selectManyCheckbox with multiple columns/rows
If you ever tried to use the
Let's talk about a feature of the
Pretty nice, but the items are rendered with the group orientation: this means JSF will render an horizontal table for the groups with nested horizontal tables for the items. Still ugly!
You can solve this using Tomahawk, but I think it's too much trouble only to get this simple requirement. I prefer using a pure-JSF solution like a new Renderer. Mojarra's renderer makes this job very easy:
public class MyRenderer extends SelectManyCheckboxListRenderer { // keeps track of current rendering private boolean inner; // overriding with synchronized @Override public synchronized void encodeEnd( FacesContext context, UIComponent component) throws IOException { super.encodeEnd(context, component); } @Override protected void renderBeginText( UIComponent component, int border, boolean alignVertical, FacesContext context, boolean outerTable) throws IOException { // are we at the inner table? this.inner = !outerTable; super.renderBeginText(component, border, alignVertical ^ inner, context, outerTable); } @Override protected void renderEndText( UIComponent component, boolean alignVertical, FacesContext context) throws IOException { super.renderEndText(component, alignVertical ^ inner, context); // reset after inner table is rendered this.inner = false; } @Override protected void renderOption( FacesContext context, UIComponent component, Converter converter, SelectItem curItem, Object currentSelections, Object[] submittedValues, boolean alignVertical, int itemNumber, OptionComponentInfo optionInfo) throws IOException { super.renderOption(context, component, converter, curItem, currentSelections, submittedValues, alignVertical ^ inner, itemNumber, optionInfo); } }
The trick is pass "alignVertical" parameter XOR inner state. This will change the alignment for the inner table. If you use "pageDirection" as layout, the inner table will use "lineDirection" and vice-versa. Using the "roles" example, the groups will be aligned horizontally and their roles, vertically.
Now, if you don't want to use groups, you can still benefit - create pseudo-groups for each N elements. This will give you a matrix-like checkbox list.
Using f:selectItems with JPA entities
It's a common scenario: you must do a "SELECT e FROM Entity e" with JPA and pass it to a <h:selectOneMenu> or a <h:selectManyList>. Unfortunately, if you google it, you will find a lot of strange solutions.
I've tested a simple solution on JavaEE 6. On my managed bean, I can define a property like this:
... public class MyBean { ... @PersistenceContext private EntityManager em; public Converter getConverter() { return new Converter() { @Override public Object getAsObject( FacesContext fc, UIComponent uic, String string) { return (string == null) ? null : em.find(MyEntity.class, Long.parseLong(string)); } @Override public String getAsString( FacesContext fc, UIComponent uic, Object o) { return (o == null) ? null : Long.toString(((MyEntity) o).getId()); } }; } }
According to JSF specification, only managed beans can be injected. This is why I declared it as an inner class.
This way, the converter allows you to work only with entities, instead of manually storing IDs on the managed bean. This means the page can bind to this property when a conversion is needed:
<h:selectOneMenu value="#{myBean.myEntitySelection}"> <f:selectItems value="#{myBean.myEntityList}"/> <f:converter binding="#{myBean.converter}"/> </h:selectOneMenu>
One last step: your Entity must have an working "equals" method. If you forget this, you will receive the message "Validation Exception: Value is invalid".
Usually, a boilerplate, like this one generated by NetBeans will suffice:
@Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyEntity other = (MyEntity) obj; if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) { return false; } return true; }
Works like a charm on JSF 2, but I haven't tested on JSF 1.2.
BTW, this solution can be refactored to became a more generic: create a base entity class that declares a "getId" method returning Serializable. Then, the converter can be a class receiving an entity manager and the persistent class.