...
which takes a model object and a property expression. When the property model is asked for its value by the framework, it will use the property expression to access the model object's property. For example, if we have a Java Bean or "POJO" (Plain Old Java Object) like this:
Code Block |
---|
class Person { private String name; Person(String name) { this.name = name; } String getName() { return name; } } |
then the property expression "name
" can be used to access the "name
" property of any Person object via the getName()
getter method.
...
Code Block |
---|
public class Address implements Serializable { private String city; public Address() { super super(); } public String getCity() { return city; } public void setCity(String city) { this.city = city; } } public class Person implements Serializable { private String name; private int age; private Address address; public Person() { super(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } } |
The first step is to create a Wrapped Object Model for the Address and Person classes:
Code Block |
---|
public class AddressModel implements IModel { private IModel addressContainingModel; private AddressModelType type; public enum AddressModelType { CITY_MODEL; }; public AddressModel(IModel addressContainingModel, AddressModelType type) { this.addressContainingModel = addressContainingModel; this.type = type; } @Override public Object getObject() { Address address = (Address) addressContainingModel.getObject(); switch switch (type) { case CITY_MODEL: return address.getCity(); } throw new UnsupportedOperationException ("invalid AddressModelType = " + type.name()); } @Override public void setObject(Object object) { Address address = (Address) addressContainingModel.getObject(); switch (type) { case CITY_MODEL: address.setCity((String) object); break; default: throw new UnsupportedOperationException("invalid AddressModelType = break;" default: throw new UnsupportedOperationException ("invalid AddressModelType = " + type.name()); } } @Override public void detach() { addressContainingModel.detach(); } } public class PersonModel implements IModel { private IModel personContainingModel; private PersonModelType type; public enum PersonModelType { NAME_MODEL, AGE_MODEL, ADDRESS_MODEL; } public PersonModel(IModel personContainingModel, PersonModelType type) { this.personContainingModel = personContainingModel; this.type = type; } @Override public Object getObject() { Person person = (Person) personContainingModel.getObject(); switch (type) { case NAME_MODEL: return person.getName(); case AGE_MODEL: return new Integer (person.getAge()); case ADDRESS_MODEL: return person.getAddress(); } throw new UnsupportedOperationException ("invalid PersonModelType = " return person.getAddress(); } throw new UnsupportedOperationException("invalid PersonModelType = " + type.name()); } @Override public void setObject(Object object) { Person person = (Person) personContainingModel.getObject(); switch (type) { case NAME_MODEL: person.setName((String) object); person.setName((String) object); break; break; case AGE_MODEL: person.setAge((Integer) object); break; case ADDRESS_MODEL: break; case ADDRESS_MODEL: person.setAddress ((Address) object); break; default: throw new break; UnsupportedOperationException("invalid PersonModelType = " default: throw new UnsupportedOperationException ("invalid PersonModelType = " + type.name()); } } @Override public void detach() { personContainingModel.detach(); } } |
Notice how each wrapped model contains an inner model that contains the actual pojo instance. This allows for the wrapped model to be a plain Model or a LoadableDetachableModel, or even another wrapped model where its .getObject() results in a suitably typed input value (see the "address.city" field in the example below).
...
Code Block |
---|
Person p = new Person (); Form personForm = new Form("aPersonForm"); personForm.add(new RequiredTextField("name", new PersonModel (new Model (p), PersonModelType.NAME_MODEL))); personForm.add(new RequiredTextField("age", new PersonModel (new Model (p), PersonModelType.AGE_MODEL), Integer.class)); personForm.add(new RequiredTextField("address.city", new AddressModel (new PersonModel (new Model (p), PersonModelType.ADDRESS_MODEL), AddressModelType.CITY_MODEL))); add(personForm); |
A wrapped object model also makes working with DataTables's easier as one IColumn implementation can be written for each object class which makes the declaration of the table much simpler.
...
Code Block |
---|
DataTable table = new DataTable("datatable", new IColumn[] { new PersonTableColumn ("Name", PersonModelType.NAME_MODEL), new PersonTableColumn ("Age", PersonModelType.AGE_MODEL), new PersonTableColumn ("City", PersonModelType.ADDRESS_MODEL) }, new PersonProvider(), 10); |
...