This library does not contain components; instead it provides Tapestry specific annotations (annotations are a a new feature in JDK 1.5 ). These annotations allow you to perform some operations inside Java code that otherwise would be specified in the page or component specification. This is very useful when using inheritance, because base classes can provide annotations that are inherited by subclasses.
The annotations are all in the package org.apache.tapestry.annotations.
Remember that a single method should only have, at most, one of these annotations! Having multiple annotations, or conflicts between method annotations and directives in the specification, will result in runtime exceptions. In addition, annotations don't provide the kind of line precise location data that the XML specifications or the templates do (but most exceptions will clearly identify the class and method, which should be sufficient).
The Asset annotation is the equivalent of the <asset> element in a specification. The value attribute is the path to the asset (possibly prefixed to indicate the domain for the path):
@Asset("/style/global.css") public abstract IAsset getGlobalStylesheet();
The asset will be available using the property name using the "asset:" binding prefix.
The Bean annotation is the equivalent of the <bean> element in a specification.
The property type will be used as the Java class to instantiate for the bean; alternately, the value attribute may be specified (this is useful when, for example, the property type is an interface).
The examples below both define a bean of type HashMap:
@Bean public abstract HashMap getHashMapBean(); @Bean(HashMap.class) public abstract Map getMapBean();
A bean defined this way will be stored into the component's beans property, exactly as if specified using XML; its name will be the property name.
An additional attribute, lifecycle, controls the bean's lifecycle. The default is Lifecycle .REQUEST, and additional values are NONE, PAGE, and RENDER:
@Bean(lifecycle = Lifecycle.RENDER) public abstract Map getRenderLifecycleBean();
Lastly, for simple configuration of the bean, there's the initializer attribute. This allows lightweight initialization , where the string is a series of name=value properties, seperated by commas (for boolean properties, the value is optional).
@Bean(initializer = "maxRetries=3") public abstract LoginController getController();
The Component annotation is attached to an accessor method and allows a component type to be defined in place, as with the <component> element.
By default, the component type will match the return type and the component id will match the property name:
@Component public abstract TextField getEmail();
When component type and return type differ, then the type attibute should be specified:
@Component(type = "contrib:Table") public abstract Table getResultsTable();
Additionally, when component id and property name differ, then the id attibute can be specified:
@Component(id = "email") public abstract TextField getEmailField();
Component bindings are specified with an array of strings. The individual strings identify the parameter name and the binding reference:
@Component(type = "Conditional", bindings = { "condition=message", "element=div" }) public abstract IComponent getIfMessage();
Component copies can be created by specifying the copyOf attribute. It should contain the name of another defined component. The type and bindings of that component will be copied to this component. The following code creates a copy of the previous component:
@Component(copyOf = "ifMessage") public abstract IComponent getIfMessageCopy();
The ComponentClass annotation is used to mark a Java class as a component, and allows several properties normally specified using the <component-specification> element.
@ComponentClass public abstract class MyComponent extends BaseComponent { ...
The defaults for allowBody and allowInformalParameters are true; components may override:
@ComponentClass(allowBody = false, allowInformalParameters = false) { ...
Note that simply having a @ComponentClass annotation will override those two properties.
If a component has reserved parameters, they can be specified as well:
@ComponentClass(reservedParameters = "href,name") public abstract class LinkWriter extends BaseComponent { ...
Finally, the presence of the @Deprecated annotation will mark the component as deprecated (and cause a warning to be output whenever the component is referenced):
@ComponentClass @Deprecated public abstact class YeOldeComponent extends AbstractComponent { ...
The EventListener annotation is attached to listener methods to dynamically bind and listen to client side browser events.
This annotation is capable of a variety of tasks, but most of them are centered around the dojo javascript toolkit event API for binding and listening to javascript events in an AOP fashion.
As an example, this page form listener method will be called when the component
with id "projectChoose" has it's javascript functional equivalent
selectOption
function called:
@EventListener(events = "onValueChanged", targets = "projectChoose") public void projectSelected(IRequestCycle cycle) { cycle.getResponseBuilder().updateComponent("projectDescription"); cycle.getResponseBuilder().updateComponent("feedbackBlock"); }
Name | Type | Required | Default | Description |
---|---|---|---|---|
targets | String[],String | no |
Specifies the components/widgets to listen to events on, in the form of unique
component ids. One of either elements OR targets must be supplied. This is supposed to
be the id as returned by IComponent.getClientId() .
|
|
elements | String[],String | no | Specifies the unique html element dom node ID's to listen to events on. One of either elements OR targets must be supplied. | |
events | String[],String | yes |
Specifies which javascript "events" to listen for. Just as with the dojo api, these
events can be simple things like onclick or onsubmit , but can
also be bound to specific functions if they exist on the component/widget you are targeting.
For example, the Autocomplete component wraps a dojo ComboBox widget that has a function named onValueChanged that is called when an item in the list is selected.
|
|
submitForm | String | no |
If specified, the form matching the passed in form ID will be submitted before calling your
listener method.
Information:
In almost all instances you will not want to use this parameter as any component target implementing IFormComponent will automatically submit the form containing it for you. This only needs to be used in the rare instance where you want to submit a different form. |
|
validateForm | boolean | no | false | When targeting a component implementing IFormComponent, optionally enables/disables both client side validation and server side validation when the form is submitted. |
async | boolean | no | true | When components implementing IFormComponent are targeted and will cause a form submission this parameter can additionally be used to cause the submission to happen with or without asynchronous (ajax) IO calls. |
autoSubmit | boolean | no | true |
When components implementing IFormComponent are targeted they will normally automatically cause a form
submission to happen so that the property they manage on your form is updated when your listener method
is called - this parameter can be used to disable the automatic submission of the enclosing form.
Warning:
Use at your own risk, this is no guarantee what kind of state your properties will be in when this method is invoked. If you aren't relying on form specific properties to do things everything should be fine - just be careful. |
focus | boolean | no | false | When components implementing IFormComponent are targeted and will cause a form submission this parameter can additionally be used to turn on/off the normal client side form element focusing that normally happens in Tapestry forms to focus the most important / first field in error. This can be annoying on AJAX IO calls and so is turned off by default. |
The InitialValue annotation allows a default value to be specified for a property. The property may also be persistent (via the @Persist annotation).
The value is a binding reference; the reference will be evaluated when the page is first loaded, and again when the page is detached and returned to the page pool. The default binding prefix is "ognl:".
The annotation is attached to an accessor method:
@InitialValue("request.serverName") public abstract String getServerName();
In many cases, where the initial value is a constant, a better approach is to set the initial value from the component's finishLoad() method.
public abstract int getMaxAttempts(); public abstract void setMaxAttempts(int maxAttempts); protected void finishLoad() { setMaxAttempts(5); }
The InjectAsset annotation allows assets defined in the page or component specification to be exposed as read-only properties. It is attached to an accessor method:
@InjectAsset("stylesheet") public abstract IAsset getStylesheet();
This is equivalent to specifying the property attribute of the <asset> element.
The InjectComponent annotation allows nested components to be injected as read-only properties. It is attached to an accessor method:
@InjectComponent("inputUserName") public abstract TextField getUserInput();
This is functionally the same as providing the property attribute of the <component> element.
The InjectMeta annotation allows meta data from the specification ( <meta> elements ) to be exposed as properties.
@InjectMeta("page-title") public abstract String getPageTitle();
The new property does not have to be type String; an automatic type conversion takes place.
The InjectMeta annotation can also be used alone - the method name is converted into a property key using the rules described at the Message annotation. Here's an equivalent to the previous example.
@InjectMeta public abstract String getPageTitle();
The InjectObject annotation allows HiveMind objects to be injected. It is attached to an accessor method:
@InjectObject("infrastructure:request") public abstract WebRequest getRequest();
The end result is the same as using the <inject> element, with the default type of "object".
The InjectPage annotation allows a page to be injected into another page or component. It is attached to an accessor method:
@InjectPage("Details") public abstract Details getDetailsPage();
Injecting other pages is most commonly used as part of a listener method.
The InjectScript annotation allows JavaScript templates to be exposed as properties. The annotation's value is the path to the script (relative to the page or component specification, if it exists, or relative to the template otherwise).
@InjectScript("scripts/VerifyAccountId.script") public abstract IScript getVerifyAccountIdScript();
The InjectState annotation allows an Application State Object to be injected and a read/write property. It is attached to an accessor method:
@InjectState("visit") public abstract MyAppVisit getVisit();
The end result is equivalent to using the <inject> element, with a type of "state".
The InjectState annotation can also be used alone - the method name is converted into a key using the rules described at the Message annotation. Here's an equivalent to the previous example.
@InjectState public abstract MyAppVisit getVisit();
The InjectStateFlag annotation implements a read-only boolean property that returns true if the identified application state object exists. This is useful for avoiding the accidental creation of the ASO, which helps avoid the unneccessary creation of the HttpSession.
@InjectStateFlag("visit") public abstract boolean getVisitExists();
The end result is equivalent to using the <inject> element, with a type of "state-flag".
The InjectStateFlag annotation can also be used alone - the method name is converted into a key using the rules described at the Message annotation ( with the addition that any trailing "exists" is stripped ). Here's an equivalent to the previous example. It also injects the flag for the visit ASO.
@InjectStateFlag public abstract boolean getVisitExists();
The Message annotation provides easy access to localized messages. It is attached to a method that returns a String, and takes any number of parameters. In its most basic form, it is used alone:
@Message public abstract String getPageTitle();
As used here, the method name is converted into a message property key:
page-title
:
public String getPageTitle() { return getMessages().getMessage("page-title"); }
@Message("get-a-life") public abstract String getALife();
@Message public abstract String getLineTotal(BigDecimal total);
This is equivalent to:
public String getLineTotal(BigDecimal total) { return getMessages().format("line-total", new Object[] { total }); }
Primitive types passed in as parameters are automatically converted to wrapper types.
The Meta annotation is used to define a meta data value on a page or component class, as with the <meta> element in an XML component or page specification.
Meta data from base classes is merged into subclasses; when there's a name conflict, the subclass overrides the base class. This allows a base class to set a default that can be naturally overriden in a subclass.
@Meta({ "requires-login=false", "show-ad-banner=true" }) public abstract class AppBasePage extends BasePage { ...
Subclasses of AppBasePage could provide a @Meta annotatioun that defines new meta data, or overrides either of these values.
Often, you only want to define a single meta value; the compiler allows you to omit the curly braces for this case:
@Meta("org.apache.tapestry.jwcid-attribute-name=id") public abstract class MyComponent extends BaseComponent { ...
The Parameter annotation defines a new property, as with <parameter> element in an XML component specification.
This most simple use of this annotation is to simply mark a property as an optional parameter:
@Parameter public abstract void MyType getMyParameter();
The parameter name will generally match the property name (as determined from the method to which the annotation is attached). This can be overriden with the name attribute:
@Parameter(name = "page") public abstract String getTargetPage();
Parameters may be marked as deprecated if the method is marked deprecated (using the java.lang.Deprecated annotation):
@Deprecated @Parameter public abstract int getRows();
The annotation supports several additional attributes, consult its JavaDoc for the full details.
The Persist annotation allows a property to be marked as persistent. Remember that any otherwise unclaimed abstract property will become a transient property automatically (in Tapestry 4.0), so Persist is only needed to mark a property as persistent.
The value of the Persist annotation defaults to "session":
@Persist public abstract int getSessionPersistentProperty(); @Persist("client") public abstract double getClientPersistentProperty();
This annotation works exactly like a <property> element, except that the initial-value attribute can't be specified. Use the @InitialValue annotation to set the property's initial value.