I have a problem with my custom converter on a p:selectCheckboxMenu and hope that someone might be able to help me out. In my (simplified) example I deal with books that only have an author and a title
Code: Select all
package checkboxselect;
import org.apache.commons.lang.builder.ToStringBuilder;
public class Book {
private String author;
private String title;
public Book(String author, String title) {
this.author = author;
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
Code: Select all
package checkboxselect;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ManagedBean
@SessionScoped
public class BookStash implements Serializable{
private final static transient Logger LOGGER = LogManager.getLogger(BookStash.class);
/**
*
*/
private static final long serialVersionUID = 537394663400478599L;
private List<Book> books;
private List<Book> selection;
private BookService bs = new BookService();
public BookStash() {
this.books = new ArrayList<Book>();
this.books.add(new Book("Victor Kramnik", "The isolated pawn"));
this.books.add(new Book("Judith Polgar", "Trading pieces"));
this.selection = new ArrayList<>();
}
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
public List<Book> getSelection() {
return selection;
}
public void setSelection(List<Book> selection) {
LOGGER.debug("Selection value set to: " + selection);
this.selection = selection;
}
public BookService getBs() {
return bs;
}
public void setBs(BookService bs) {
this.bs = bs;
}
}
Code: Select all
<?xml version='1.0' encoding='UTF-8' ?>
<!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:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Book Store</title>
</h:head>
<h:body>
<h:form id="bookstoreForm">
<h:outputLabel for="bookSelect" value="Please choose" />
<p:selectCheckboxMenu value="#{bookStash.selection}" multiple="true" panelStyle="width:250px" id="bookSelect">
<f:selectItems value="#{bookStash.books}" var="b" itemValue="#{b}" itemLabel="#{bookStash.bs.createBookLabel(b)}"/>
<f:converter converterId="BookConverter"/>
</p:selectCheckboxMenu>
<h:commandButton action="result" value="Submit" />
</h:form>
</h:body>
</html>
as expected since the book instances get converted into their String representations to be rendered in the HTML. Indeed, this looks correct as well, the values are correctly set:12:13:38,833 INFO [stdout] (default task-77) Object checkboxselect.Book@74c8c2c2[author=Victor Kramnik,title=The isolated pawn] converted to String Victor Kramnik~The isolated pawn
12:13:38,833 INFO [stdout] (default task-77) Object checkboxselect.Book@4e5433f5[author=Judith Polgar,title=Trading pieces] converted to String Judith Polgar~Trading pieces
14:31:42,704 INFO [stdout] (default task-72) Object checkboxselect.Book@30dc7884[author=Victor Kramnik,title=The isolated pawn] converted to String Victor Kramnik~The isolated pawn -->
checkboxselect.BookConverter.getAsString(BookConverter.java:43)
14:31:42,704 INFO [stdout] (default task-72) Object checkboxselect.Book@78edd582[author=Judith Polgar,title=Trading pieces] converted to String Judith Polgar~Trading pieces -->
checkboxselect.BookConverter.getAsString(BookConverter.java:43)
Code: Select all
<div id="bookstoreForm:bookSelect">
<input id="bookstoreForm:bookSelect:0" name="bookstoreForm:bookSelect" type="checkbox" value="Victor Kramnik~The isolated pawn" data-escaped="true" />
<label for="bookstoreForm:bookSelect:0">V.K - The isolated pawn</label>
<input id="bookstoreForm:bookSelect:1" name="bookstoreForm:bookSelect" type="checkbox" value="Judith Polgar~Trading pieces" data-escaped="true" />
<label for="bookstoreForm:bookSelect:1">J.P - Trading pieces</label>
</div>
I understand the first line. The converter is asked to convert the submitted text value to a book object. I do not understand the rest ... for some reason the two available options are again converted back to Strings although there is no rendering of them requested (result.xhtml doesn't map them out).:32:03,609 INFO [stdout] (default task-78) String Judith Polgar~Trading pieces converted to Object checkboxselect.Book@65969bee[author=Judith Polgar,title=Trading pieces] --> checkboxselect.BookConverter.getAsObject(BookConverter.java:22)
14:32:03,625 INFO [stdout] (default task-78) Object checkboxselect.Book@30dc7884[author=Victor Kramnik,title=The isolated pawn] converted to String Victor Kramnik~The isolated pawn --> checkboxselect.BookConverter.getAsString(BookConverter.java:43)
14:32:03,625 INFO [stdout] (default task-78) Object checkboxselect.Book@78edd582[author=Judith Polgar,title=Trading pieces] converted to String Judith Polgar~Trading pieces --> checkboxselect.BookConverter.getAsString(BookConverter.java:43)
14:32:03,625 SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (default task-78) Error Rendering View[/faces/standalone/checkboxmenu/index.xhtml]: java.lang.RuntimeException: Inconvertable type: class java.lang.String of value 'Judith Polgar~Trading pieces'
at checkboxselect.BookConverter.getAsString(BookConverter.java:31)
at org.primefaces.renderkit.InputRenderer.getOptionAsString(InputRenderer.java:175)
at org.primefaces.component.selectcheckboxmenu.SelectCheckboxMenuRenderer.encodeMultipleLabel(SelectCheckboxMenuRenderer.java:225)
at org.primefaces.component.selectcheckboxmenu.SelectCheckboxMenuRenderer.encodeMarkup(SelectCheckboxMenuRenderer.java:79)
at org.primefaces.component.selectcheckboxmenu.SelectCheckboxMenuRenderer.encodeEnd(SelectCheckboxMenuRenderer.java:52)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:920)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1863)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:176)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:890)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1856)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:458)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:134)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:659)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:326)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:812)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
And for me even less understandable is the error trace. Why on earth is my BookConverter.getAsString() method (that is supposed to get Books to convert them into a representable String) called with the String representation? It happens in the encoding phase, this is correct but why is it called with the String and not the object instance?
Any help would be appreciated.
EDIT:
The Converter:
Code: Select all
package checkboxselect;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@FacesConverter(value="BookConverter")
public class BookConverter implements Converter {
private final static String DELIMITER = "~";
private final static transient Logger LOGGER = LogManager.getLogger(BookConverter.class);
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
String[] parts = value.split(DELIMITER);
Book result = new Book(parts[0], parts[1]);
LOGGER.debug(String.format("String %s converted to Object %s", value, result));
return result;
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Book)) {
throw new RuntimeException(String.format("Inconvertable type: %s of value '%s'", value.getClass(), value));
}
Book book = (Book)value;
StringBuilder sb = new StringBuilder();
sb
.append(book.getAuthor())
.append(DELIMITER)
.append(book.getTitle());
String result = new String(sb);
LOGGER.debug(String.format("Object %s converted to String %s", value, result));
return result;
}
}