Reputation: 185
I want to use a DynamicEntity as a managed bean providing properties for my xhtml form.
When I use the above as backing bean for my xhtml page, I got the following exception:
The class 'com.invoice.Invoic' does not have the property 'sellerAddress'.
com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:111)
javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
javax.faces.component.UIOutput.getValue(UIOutput.java:169)
com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:205)
com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:355)
com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:164)
javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875)
javax.faces.component.UIComponent.encodeAll(UIComponent.java:1786)
javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782)
javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782)
com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:402)
com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:125)
javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
org.ocpsoft.rewrite.faces.RewriteViewHandler.renderView(RewriteViewHandler.java:186)
javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:200)
com.tsystems.odx.idm.authentication.web.AuthenticationFilter.doFilter(AuthenticationFilter.java:231)
org.ocpsoft.rewrite.servlet.impl.HttpRewriteResultHandler.handleResult(HttpRewriteResultHandler.java:38)
org.ocpsoft.rewrite.servlet.RewriteFilter.rewrite(RewriteFilter.java:263)
org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:188)
com.tsystems.odx.idm.authentication.web.AuthenticationFilter.doFilter(AuthenticationFilter
I put a debug breakpoint and looked into my DynamicEntity object, the sellerAddress object was there.
Here is a dummy example how I would like to use DynamicEntity as bean
package com.test.beans;
import java.io.InputStream;
import javax.annotation.PostConstruct;
import javax.enterprise.inject.Produces;
import javax.faces.bean.ViewScoped;
import javax.inject.Named;
import javax.xml.bind.JAXBException;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
@Named
@ViewScoped
public class CustomerHandler {
DynamicJAXBContext jaxbContext;
@PostConstruct
public void init() throws JAXBException {
InputStream xsdInputStream = getClass().getClassLoader().getResourceAsStream("customer.xsd");
jaxbContext = DynamicJAXBContextFactory.createContextFromXSD(xsdInputStream, null, null,
null);
}
@Produces
@Named("Customer")
public DynamicEntity createCustomer() {
DynamicEntity customer = jaxbContext.newDynamicEntity("org.example.Customer");
customer.set("name", "Jane Doe");
DynamicEntity address = jaxbContext.newDynamicEntity("org.example.Address");
address.set("street", "1 Any Street").set("city", "Any Town");
customer.set("address", address);
return customer;
}
public void save()
{
// do something
}
}
The customer.xsd file is in src/main/resources
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.example.org"
targetNamespace="http://www.example.org"
elementFormDefault="qualified">
<xsd:complexType name="address">
<xsd:sequence>
<xsd:element name="street" type="xsd:string" minOccurs="0"/>
<xsd:element name="city" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="customer">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string" minOccurs="0"/>
<xsd:element name="address" type="address" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
And my test page is customer.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>Welcome to Customer Page</title>
</h:head>
<h:body>
<h:form>
<h:inputText value="#{Customer.name}" />
<h:inputText value="#{Customer.address.street}" />
<h:commandButton value="Submit" action="#{customerHandler.save()}" />
</h:form>
</h:body>
</html>
Upvotes: 0
Views: 894
Reputation: 11742
Documentation for DynamicEntity
class shows us that it is an interface and nowhere states that this interface provides for good old POJO getters like getSellerAddress()
that will return the desired property. As you're trying to manipulate the values as #{Customer.name}
that is indeed not going to work, as there is no getName()
/setName()
method pair.
The methods exposed by the DynamicEntity
interfaces are the following:
DynamicEntity#get(propertyName)
to retrieve the value andDynamicEntity#set(propertyName, value)
to preset the value.So there is clearly no way to use these methods to create a bilateral binding with a bean property in a standard JSF way.
You have the following choices to deal with your problem:
@Entity public class Customer
as your model. This is clearly the best way to go further and the best practice;DynamicEntity
(that is, the instance returned from the call to DynamicJAXBContext#newDynamicEntity(String n)
) is backed by a Map
implementation. Debug to see what that call returns and apply that information to your use case. In case it's backed by a map with a public getter/setter pair with the name persistentMap
your EL will become #{Customer.persistentMap['name']
. Be aware that this is a discouraged practice and an example of tight coupling and is possible in case there are accessors for the backed collection.To sum it up, I'd highly recommended to switch to JPA to solve your use case.
Upvotes: 1