Monday, December 17, 2012

Creating custom converters for jsf (h:selectOneMenu , h:selectManyCheckbox , h:selectManyListbox).

Suppose we have two models, Book and Author. each book having a list of authors. both books and authors are objects and for creating books we need to select authors for that book from an author list. here we use jsf. we use custom converter to convert author names in the list into author objects so that the selected authors from the view are turned into author list for the book. here is how we do it.

the book and author models are as follows,

@Entity
@Table(name = "BOOKS")

public class Book implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long book_id;
    @NotNull(message = "book title cant be empty")
    String title;
    @NotNull(message = "book isbn cant be empty")
    String isbn;
    @Temporal(javax.persistence.TemporalType.DATE)
    Date publishDate;
        Double price;
    
    
    @JoinTable(name = "BOOK_AUTHOR", joinColumns = {
        @JoinColumn(name = "BOOK_ID",
        referencedColumnName = "BOOK_ID")},
    inverseJoinColumns = {
        @JoinColumn(name = "AUTHOR_ID",
        referencedColumnName = "AUTHOR_ID")})
    @ManyToMany
    List<Author> authors;
//getter setters equals and hashcode
@Entity
public class Author implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="AUTHOR_ID")        
    Long author_id;
    String name;

    
    @JoinTable(name = "BOOK_AUTHOR", joinColumns = {
        @JoinColumn(name = "AUTHOR_ID",
        referencedColumnName = "AUTHOR_ID")},
    inverseJoinColumns = {
        @JoinColumn(name = "BOOK_ID",
        referencedColumnName = "BOOK_ID")})
    @ManyToMany(mappedBy = "authors")
    List<Book> books;
//getter setters equals and hashcode

BookController class is used as the book crud controller.

@Named
@ConversationScoped
public class BookController implements Serializable{

    @EJB
    BookDao dao;
    @Valid
    Book selectedBook;
    @Inject
    Conversation conversation;

    public Book getSelectedBook() {
        if (selectedBook == null) {
            selectedBook = new Book();
        }
        return selectedBook;
    }

    public void setSelectedBook(Book selectedBook) {
        this.selectedBook = selectedBook;
    }

    public BookDao getDao() {
        return dao;
    }

    public void setDao(BookDao dao) {
        this.dao = dao;
    }

    public String createBook() {
       try {
            dao.create(selectedBook);
        } catch (Exception e) {

            String message = "creation failed !!" + e.getMessage();
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(message));

            return "createBook";
        }

        String message = "creation successful !!";
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(message));
        return "bookList?faces-redirect=true";

    }

//other methods for bookController

}

here bookDao is the dao layer implementation for book crud operation. we wont cover that here.

now we write a custom converter for author class (which by the way is the main goal of this post).

@FacesConverter(value = "authorConverter")
public class AuthorConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (context == null) {
            throw new NullPointerException("context");
        }
        if (component == null) {
            throw new NullPointerException("component");
        }
        FacesContext ctx = FacesContext.getCurrentInstance();
        ValueExpression vex =
                ctx.getApplication().getExpressionFactory().createValueExpression(ctx.getELContext(),
                "#{authorController}", AuthorController.class);
        AuthorController authorController = (AuthorController) vex.getValue(ctx.getELContext());
        Author author;
        try {
            author = authorController.load(Long.valueOf(value)); //todo
        } catch (Exception e) {
            e.printStackTrace();
            throw new ConverterException();
        }

        if (author == null) {
            throw new ConverterException();
        }

        return author;
    }

    @Override
    public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
        if (arg0 == null) {
            throw new NullPointerException("context");
        }
        if (arg1 == null) {
            throw new NullPointerException("component");
        }
        return String.valueOf(((Author)arg2).getAuthor_id());
    }
}

the jsf view for creatBook.xhtml will be something like this

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

    <head>
        <title>create book</title>
    </head>
    <body>
        <h:messages globalOnly="true" />
        <h:form>
            <h:outputLabel value="Enter Title" />
            <h:inputText value="#{bookController.selectedBook.title}" />

            <br/>

            <h:outputLabel value="Enter ISBN" />
            <h:inputText value="#{bookController.selectedBook.isbn}" />

            <br />

            <h:outputLabel value="Enter Price" />
            <h:inputText value="#{bookController.selectedBook.price}">
                       
            </h:inputText>

            <br/>

            <h:outputLabel value="Enter publishing date" />
            <h:inputText value="#{bookController.selectedBook.publishDate}"> 
                         <f:convertDateTime type="date" pattern="dd/mm/yyyy"/>
            </h:inputText>

            <br/>

            <h:outputLabel value="select authors from list" />
            <h:selectManyMenu value="#{bookController.selectedBook.authors}" converter="authorConverter">
                <f:selectItems value="#{authorController.authorListAsSelectItems}"/>
            </h:selectManyMenu>

            <br/>

            <h:commandButton value="Create" action="#{bookController.createBook()}" />
        </h:form>
    </body>
</html>

here we can see use of authorController for retrieving list of authors. part of authorController is like this:

@Named
@RequestScoped
public class AuthorController {

    @EJB
    AuthorDao dao;

// other properties, getter and setter methods and other methods for crud operations
   
   public List<SelectItem> getAuthorListAsSelectItems(){
    
        List<SelectItem> items = new ArrayList<SelectItem>();
        
        List<Author> authorList = getAuthorList();
        
        for(Author author:authorList){
        
            items.add(new SelectItem(author, author.getName()));
        }
        
        return items;
    }

    public List<Author> getAuthorList() {

        return dao.findAll();

    }

}

the browser output will be like the following image


i hope the code will be self explanatory on how it works.

No comments:

Post a Comment