Hi all,
I'm working on a property editor block. My Patient object contains an
embeddable PersonName object.
@Embeddable
public class PersonName {
String prefix;
String given;
String family;
public String getFormattedName() {
String s = this.prefix;
if (!s.isEmpty()) {
s += " ";
}
s += this.given;
if (!s.isEmpty()) {
s += " ";
}
s += this.family;
return s;
}
I want BeanEditor to automatically generate 3 text boxes, one for each
string.
I've written an AppPropertyEditBlock.java
package au.gov.nehta.eps.pages;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.Field;
import org.apache.tapestry5.FieldTranslator;
import org.apache.tapestry5.FieldValidator;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.corelib.components.TextField;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.PropertyEditContext;
import au.gov.nehta.eps.entities.PersonName;
public class AppPropertyEditBlocks {
@Property
@Environmental
private PropertyEditContext context;
@Component(parameters =
{ "label=prop:context.label",
"translate=prop:prefixTranslator",
"validate=prop:prefixValidator",
"clientId=prop:context.propertyId",
"annotationProvider=context" })
private TextField prefix;
@Component(parameters =
{ "label=prop:context.label",
"translate=prop:prefixTranslator",
"validate=prop:prefixValidator",
"clientId=prop:context.propertyId",
"annotationProvider=context" })
private TextField given;
@Component(parameters =
{ "label=prop:context.label",
"translate=prop:prefixTranslator",
"validate=prop:prefixValidator",
"clientId=prop:context.propertyId",
"annotationProvider=context" })
private TextField family;
@Inject
private ComponentResources resources;
public FieldValidator getPrefixValidator()
{
return this.context.getValidator((Field) this.prefix);
}
public FieldTranslator getPrefixTranslator()
{
return this.context.getTranslator((Field) this.prefix);
}
public PersonName getPersonName() {
return (PersonName) this.context.getPropertyValue();
}
}
With page template:
<html t:type="layout" title="sampleImpl Index"
t:sidebarTitle="Current Time"
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
xmlns:p="tapestry:parameter">
<t:block id="personName">
<t:label for="prefix"/>
<t:textfield t:id="prefix" size="10" t:value="personName.prefix"/>
<t:textfield t:id="given" size="10" t:value="personName.given"/>
<t:textfield t:id="family" size="10" t:value="personName.family"/>
</t:block>
</html>
I've also written a translator:
package au.gov.nehta.eps.translators;
import org.apache.tapestry5.Field;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.ValidationException;
import org.apache.tapestry5.internal.translator.AbstractTranslator;
import org.apache.tapestry5.services.FormSupport;
import au.gov.nehta.eps.entities.PersonName;
public class PersonNameTranslator extends AbstractTranslator<PersonName> {
public PersonNameTranslator() {
super("personName", PersonName.class, "personname-format-exception");
}
@Override
public String toClient(PersonName value) {
return value == null ? null : value.getFormattedName();
}
@Override
public PersonName parseClient(Field field, String clientValue, String
message)
throws ValidationException {
if (clientValue == null) {
return null;
}
PersonName name = new PersonName();
name.setPrefix(clientValue);
return name;
}
@Override
public void render(Field field, String message, MarkupWriter writer,
FormSupport formSupport) {
// TODO Auto-generated method stub
}
}
AppModule contains:
/**
* Contribution to the BeanBlockSource service to tell the BeanEditForm
* component about the editors.
*/
public static void contributeBeanBlockSource(
Configuration<BeanBlockContribution> configuration) {
configuration.add(new EditBlockContribution("personname",
"AppPropertyEditBlocks", "personname"));
}
@SuppressWarnings("rawtypes")
public static void
contributeTranslatorSource(MappedConfiguration<Class, Translator>
configuration) {
configuration.add(PersonName.class, new PersonNameTranslator());
}
But when I go to the page with the BeanEdit block I get:
An unexpected application exception has occurred.
* org.apache.tapestry5.internal.services.RenderQueueException
Render queue error in BeginRender[AppPropertyEditBlocks:prefix]:
Could not find a coercion from type java.lang.String to type
au.gov.nehta.eps.entities.PersonName.
activeComponents
o patients/Detail (class
au.gov.nehta.eps.pages.patients.Detail)
o patients/Detail:layout (class
au.gov.nehta.eps.components.Layout)
classpath:au/gov/nehta/eps/pages/patients/Detail.tml,
line 4
1 <html t:type="layout" title="sampleImpl Index"
2 t:sidebarTitle="Current Time"
3
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
4 xmlns:p="tapestry:parameter">
5
6 <h2>Patient Detail</h2>
7 <br/>
8
9 <t:beaneditform t:id="patient" object="patient"
include="patientName,ihi,born,gender"
submitLabel="Save"/><br/>
o patients/Detail:patient (class
org.apache.tapestry5.corelib.components.BeanEditForm)
classpath:au/gov/nehta/eps/pages/patients/Detail.tml,
line 9
4 xmlns:p="tapestry:parameter">
5
6 <h2>Patient Detail</h2>
7 <br/>
8
9 <t:beaneditform t:id="patient" object="patient"
include="patientName,ihi,born,gender"
submitLabel="Save"/><br/>
10 <br/>
11
12 <h2>Prescriptions</h2>
13 <br/>
14
o patients/Detail:patient.form (class
org.apache.tapestry5.corelib.components.Form)
classpath:org/apache/tapestry5/corelib/components/BeanEditForm.tml,
line 2
1 <form t:id="form" validate="object"
2
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
3 <t:errors/>
4
5 <div class="t-beaneditor">
6
7 <t:beaneditor t:id="editor" object="object"
model="model" overrides="this"/>
o patients/Detail:patient.editor (class
org.apache.tapestry5.corelib.components.BeanEditor)
classpath:org/apache/tapestry5/corelib/components/BeanEditForm.tml,
line 7
2
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
3 <t:errors/>
4
5 <div class="t-beaneditor">
6
7 <t:beaneditor t:id="editor" object="object"
model="model" overrides="this"/>
8
9 <div class="t-beaneditor-row">
10 <input type="submit" class="t-beaneditor-submit"
value="${submitLabel}"/>
11 <t:if test="cancel">
12 <t:submit t:id="cancel" mode="cancel"
value="message:cancel-label"/>
o patients/Detail:patient.editor.loop (class
org.apache.tapestry5.corelib.components.Loop)
classpath:org/apache/tapestry5/corelib/components/BeanEditor.tml,
line 2
1 <div
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"
xml:space="default" class="t-beaneditor-row"
2 t:type="loop" t:source="model.propertyNames"
t:formState="ITERATION" t:value="propertyName">
3 <t:propertyEditor property="propertyName"
object="object" model="model" overrides="overrides"/>
4 </div>
o patients/Detail:patient.editor.propertyeditor (class
org.apache.tapestry5.corelib.components.PropertyEditor)
classpath:org/apache/tapestry5/corelib/components/BeanEditor.tml,
line 3
1 <div
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"
xml:space="default" class="t-beaneditor-row"
2 t:type="loop" t:source="model.propertyNames"
t:formState="ITERATION" t:value="propertyName">
3 <t:propertyEditor property="propertyName"
object="object" model="model" overrides="overrides"/>
4 </div>
o AppPropertyEditBlocks:prefix (class
org.apache.tapestry5.corelib.components.TextField)
classpath:au/gov/nehta/eps/pages/AppPropertyEditBlocks.tml,
line 8
3
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
4 xmlns:p="tapestry:parameter">
5
6 <t:block id="personName">
7 <t:label for="prefix"/>
8 <t:textfield t:id="prefix" size="10"
t:value="personName.prefix"/>
9 <t:textfield t:id="given" size="10"
t:value="personName.given"/>
10 <t:textfield t:id="family" size="10"
t:value="personName.family"/>
11 </t:block>
12
13 </html>
I don't understand why I need a type coercer from String to PersonName.
I've read the BeanEditForm Guide here:
http://tapestry.apache.org/beaneditform-guide.html
The documentation is a little out of date as it mentions
BeanBlockContribution when it should refer to EditBlockContribution and
perhaps DisplayBlockContribution as BeanBlockContribution is deprecated.
I'd appreciate any assistance.
Regards,
Greg