Tapestry 4.0 introduces an entirely new concept into Tapestry application development: property injection. By use of the <inject> element in page and component specifications, it is possible to add new properties to pages or components, using the <inject> element in the page or component specification.
The new properties that are created often are more than just wrappers around an instance variable; in many cases they create complex synthetic accessor methods.
There are different types of injected properties, defined by the type attribute of the <inject> element. The type determines how the object attribute is interpreted, and otherwise guides how code for the property is generated at runtime. The default type is object .
Like so much in Tapestry, this list is open to extension. The tapestry.enhance.InjectWorkers configuration point defines the available types of injection. The tapestry.enhance.EnhancementWorkers configuration point defines an entire pipeline used to perform runtime code enhancement (of which property injection is a critical phase).
In addition, many other elements support a property attribute; this is the name of a property to create that holds the corresponding object. For example, the <bean> element's property allows access to a managed bean; the bean is still created on first reference. Components and assets may also be injected in this way.
The meta injection type provides a page or component with access to its meta data. Meta data for a component is primarily provided as <meta> tags in the component or page specification.
However, meta-data may be specified elsewhere; the search starts in the component (or page) specification, but if not defined there, the search continues inside the component's namespace (its application or library specification). If no value is found there, the search continues in the list of application property sources. In other words, there are multiple places to set defaults, which can be overridden.
Beyond wide searching, the other added value for the meta property injection is type coercion . Meta data always starts as simple strings, but your properties may be of any type. Tapestry will attempt to coerce the string value to your desired type.
For example, perhaps you want to use meta-data to control the number of items from some large list that is displayed on a single page. You can define the meta-data, and the property in your page or component specification:
<meta key="page.size" value="15"/> <inject property="pageSize" type="meta" object="page.size"/>
You can access the this meta data value in code by defining a property:
public abstract int getPageSize();
The most common kind of injection, because "object" is the default injection type. The object is a HiveMind object. The HiveMind integration documentation covers this type of injection in more detail.
Page injection allows a page to be injected into another page (or component). Beneather the covers, the logic simply accesses the IRequestCycle object and obtains the page from it, and adds a cast if necessary.
The property type can be Object, IPage , or any type assignable to IPage .
This is often used with listener method s. For example:
<inject property="detailsPage" type="page" object="Details"/>
public abstract Details getDetailsPage(); public IPage doShowDetails(long productId) { Details details = getDetailsPage(); details.setProductId(productId); return details; }
This is a common idiom: getting a page and casting it to its real type, invoking methods upon it, then returning it (from the listener method), so that it is activated to render the response.
Tapestry includes extensive support for creating client-side JavaScript. At the core of this are specialized script templates. These templates must be parsed into IScript objects in order to be used. The script injection type hides the details of this process, and simply represents the parsed script template as a read-only property.
The object is the relative path to the script template; it is evaluated relative to the page or component specification (typically, it is another file in the same folder).
This example is from the Palette component:
<inject property="script" type="script" object="Palette.script"/>
The script can then be executed from the Java code:
public abstract IScript getScript(); . . . PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle, this); getScript().execute(cycle, pageRenderSupport, _symbols);
This style of injection allows easy access to Application State Objects , objects which store various kinds of global information (information needed on many pages).
Using the state injection can force the creation of an application state object; this type of injection will create a read only boolean property that indicates if an application state object already exists.
This is used to prevent the creation of an application state object until it is absolutely needed.
For example; in a situtation where the user may or may not be logged in, you would inject a state flag and the state in two properties and check the state flag first :
// <inject> type state-flag in the XML public abstract boolean getUserIdentityExists(); // <inject> type state in the XML public abstract WizardState getUserIdentity(); public void doOperation() { if (getUserIdentityExists() && getUserIdentity().isLoggedIn()) { . . . } else { . . . } }