Now after all the theoretical stuff and preparations from the previous chapters we are ready to finally dig into some code and explain how these things are controlled exactly.
5.1) JavaBeans
When working with this framework, it is important to follow the JavaBean conventions for accessing attributes. An "attribute" is a data member of a Java class which - according to the JavaBean convention - is accessed by appropriate getter and setter methods. It is best practice that the identifier following the "get"- and "set"-prefix corresponds to the name of the attribute, whereby the first letter is capitalized.
An attribute:
private String name;
is accessed from outside the class: by the member functions
public String getName();
public void setName(String name);
The notation with the leading capital letter is often referred to as a property of the class. A class may very well contain virtual properties, i.e. properties that do not refer to an attribute of the corresponding name but e.g. to an assembly or type conversion of other attributes. The actual names of attributes are therefore a secondary aspect. Many frameworks that are based on Java reflection, work with the JavaBean convention and assume its correct usage by the developers. This is also true for invesdwin-NoWicket. So if this documentation uses the term "property", it refers to the convention above. The term "component" refers to components on the screen, i.e. a text field, a check box, a combo box etc.
5.2) The First Generated UI
To display a first generic user interface, we simply need a pure Java bean (a "POJO" if you like that term).
public class Car implements Serializable {
private String state;
private String licenseNumber;
private String brand;
public Car() {
this.state = "off";
}
public String getLicenseNumber() { return licenseNumber; }
public String getBrand() { return brand; }
public String getState() { return state; }
public void setLicenseNumber(String licenseNumber) { this.licenseNumber = licenseNumber; }
public void setBrand(String brand) { this.brand = brand; }
public void setState(String state) { this.state = state; }
}
This is what it looks like when it is used as a panel:
So the Java class was visualized in a straight-forward way. The HTML generator sorts the components per default in alphabetical order, but you can rearrange them later. The only GUI code required was the panel declaration (which could also have been a page as in the previous chapter):
public class CarPanel extends Panel {
public CarPanel(final String id, final IModel<Car> model) {
super(id, model);
new GeneratedBinding(this).bind();
}
}
5.3) Adding Actions
The state of the car was arbitrarily changeable in the last example. Now the car should better provide methods for reasonable state changes. The methods should only allow to turn the car off and on.
public class Car implements Serializable {
// attribute definitions, constructor, getters/setters omitted here
public void turnOn() {
this.state = "on";
}
public void turnOff() {
this.state = "off";
}
}
To ensure that the state is not modified interactively without activating the methods, we remove the setter method for the attribute. This results in the following panel:
The buttons were aligned manually after the HTML file was generated. The framework adds buttons only for methods without parameters. If a method throws a checked exception, the exception text is displayed in an error message box. The exception text automatically walks through localization, so you may as well just provide a localization key that refers to a translation in a Wicket property file. Throwing an exception without a message will silently be swallowed, assuming that the originating problem has already been handled in the code and does not need to be reported graphically. Runtime exceptions will be handled via the default Wicket exception handling, thus an internal error page will be displayed. You can change this behavior by setting a custom ISubmitButtonExceptionHandler in the GeneratedBindingDefaults class.
5.4) Next Steps
The two sections above demonstrate that it is fairly simple to display a domain object. Nevertheless there arise various questions from the examples:
- How can I avoid the activation of turnOn for an already running car?
- Is there a different way to disable fields rather than by removing or renaming the setter?
- How can I limit the brand to a particular set of reasonable values?
- Which other data types can be displayed by the framework?
- How can I ensure that the license number follows a particular format?
- May domain objects be nested?
The following chapters give answers to these and many other questions.