Saturday, August 28, 2010

JSF 2 templating

In this post I want to share my knowledge about JSF 2 templating. Most of this post are source codes, but if you are novice and don't know how to start, and where to put the source code, here you go.

0. Download Netbeans and setup the project.

Install Netbeans and run it. I use version 6.9. In Netbeans, go to File -> New Project... and then choose Java Web and Web Application. Click Next.


In next window choose project name, optionally directory where to store it, and set the project as the main project.


In the next window leave <None> in enterprise application and choose web server. Default should be ok, the same about context path.


Check JavaServer Faces. In Libraries tab select Registered Libraries and JSF 2.0.

1. Simple template and it's client. <ui:insert> and <ui:define>

Ok, we'll create simpliest template possible. In Web Pages create new .xhtml file, let's name it headerFooter.xhtml. It's our template containing header, footer, and place for some content between them.


You can let Netbeans create it for you along with nice CSS files, you can also select one of predefined template layouts. Click File ->  New File -> JavaServer Faces -> Facelets Template. Our template code:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Header-Footer Template</title>
    </h:head>
    <h:body>
        <div id="top">
            Here goes our header
        </div>
        <div id="content" class="center_content">
            <ui:insert name="content">Content</ui:insert>
        </div>
        <div id="bottom">
            And here footer
        </div>
    </h:body>
</html>
Now create template client. It is a page which uses the template. Let's call it templateClient.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
                template="./headerFooter.xhtml">
    
    <ui:define name="content">
        content
    </ui:define>

</ui:composition>
In template there is <ui:insert> tag. This is a named place where content from template client goes, and it's name in this case is content. In client, there is <ui:composition>. It uses template given as tags attribute, and has <ui:define> tags, with the same name as <ui:insert> in template. So what's in <ui:define> tag is inserted in place of <ui:insert> with the same name. You can run your project (in Netbeans right-click on project and select Run) and see the templated page at http://localhost:8080/JsfTemplating/faces/templateClient.xhtml Any content surrounding <ui:composition> tag is ommitted.

Template client can also be a template. Just put some <ui:insert> tag inside of <ui:define> block. E.g.
<ui:define name="content">
    <div class="info">
        Here goes some additional info, which is not in the header nor in the footer, but we need it on some pages.
    </div>
    <ui:insert name="innerContent">
</ui:define>

2. Decorate

We can also insert parts of markup in our pages. If you have piece of code which you put on some pages and it's always the same, you can separate it to a file and just insert it in the pages. <ui:decorate> tag is used for this:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <body>
        Some page text
        <ui:decorate template="./disclaimer.xhtml"/>
    </body>
</html>
Content of disclaimer.xhtml is injected where <ui:decorate> tag is. Don't add <?xml ... ?> declaration or doctype there, or it is going to be inserted in the middle of your page, which is not desirable. You can also use standard templating in disclaimer.xhtml. You can put <ui:insert> there and <ui:define> in page which uses it.

3. Include

Another method to attach some piece of markup is <ui:include>. This one also lets us pass some parameter to the piece of code we want to include, and this parameter can be managed bean. Lets say we have bean with information about some documents:
@ManagedBean
public class Paper {

    private String author;
    private String title;

    //getters and setters omitted
}
Piece of code to display information about a book is prepared in book.xhtml file:
<div xmlns="http://www.w3.org/1999/xhtml">
    Book "#{book.title}" by #{book.author}
</div>
Now in any other JSF page we can use it:
<ui:include src="./book.xhtml">
    <ui:param name="book" value="#{tomSawyer}" />
</ui:include>
I hope this post is going to be helpful to somebody. At least to me. Happy templating with JSF!

Monday, August 9, 2010

JPA Puzzle. When your entity misses some fields.

Today I encountered quite interesting problem. It wasted few hours of my life, so maybe if you read this you can save some. Example is simplified as much as possible.
@Entity
@Table(name = "PERSONS")
@NamedNativeQueries({
    @NamedNativeQuery(
        name = "getPersonBasic",
        query = "SELECT p.name, p.surname FROM persons where p.surname = ?",
        resultClass = Person.class),
    @NamedNativeQuery(
        name = "getPersonDetails",
        query = "SELECT p.name, p.surname, p.age, p.street, p.city FROM persons where p.surname = ?",
        resultClass = Person.class)
})
public class Person {
    
    private String name;

    @Id
    private String surname;

    private int age;

    private String street;

    private String city;

}

Now, in my application I am getting Person with surname "Stawicki" without details, by "getPersonBasic" query. Then I need detailed person in the same transaction, so I execute "getPersonDetails". And... I am getting Person without age, street and city. This three fields are null. Why? Do you already know? If not, look below for answer.













The problem is in cache, and in @Id which is only on surname field. First person is retrieved without details and stored in cache. Then we try to get person with details, but JPA doesn't understand difference between our queries. It queries the database, and identifies that if it builds entity from resulting ResultSet, it is going to have the same @Id as entity which is already in cache. If @Id is the same, logically it is the same entity. So it just returns it without building whole entity from ResultSet.