You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2005/06/11 22:04:13 UTC
cvs commit: jakarta-tapestry/framework/src/test/org/apache/tapestry/junit/parse BeanInitializer.jwc TestSpecificationParser.java
hlship 2005/06/11 13:04:13
Modified: . status.xml
src/documentation/content/xdocs/UsersGuide spec.xml
annotations/src/test/org/apache/tapestry/annotations
AnnotatedPage.java Target.java
annotations/src/documentation/content/xdocs/tapestry-annotations
index.xml
annotations build.xml
framework/src/java/org/apache/tapestry/parse
Tapestry_4_0.dtd
framework/src/java/org/apache/tapestry/binding
BindingUtils.java
framework/src/java/org/apache/tapestry/spec
IParameterSpecification.java
annotations/src/descriptor/META-INF hivemodule.xml
framework/src/test/org/apache/tapestry/junit/parse
TestSpecificationParser.java
Added: annotations/src/test/org/apache/tapestry/annotations
TestParameterAnnotationWorker.java
TestAssetAnnotationWorker.java
TestBeanAnnotationWorker.java
annotations/src/java/org/apache/tapestry/annotations
Parameter.java Lifecycle.java
AssetAnnotationWorker.java
BeanAnnotationWorker.java Asset.java Bean.java
ParameterAnnotationWorker.java
framework/src/test/org/apache/tapestry/bean TargetBean.java
TestLightweightBeanInitializer.java
framework/src/test/org/apache/tapestry/junit/parse
BeanInitializer.jwc
Log:
Annotation Fever! Asset, Bean, Parameter.
Revision Changes Path
1.121 +1 -2 jakarta-tapestry/status.xml
Index: status.xml
===================================================================
RCS file: /home/cvs/jakarta-tapestry/status.xml,v
retrieving revision 1.120
retrieving revision 1.121
diff -u -r1.120 -r1.121
--- status.xml 9 Jun 2005 22:53:48 -0000 1.120
+++ status.xml 11 Jun 2005 20:04:13 -0000 1.121
@@ -69,8 +69,7 @@
<action type="add" dev="HLS">Add configuration property org.apache.tapestry.accepted-locales, used to limit localization to a finite set of locales.</action>
<action type="fix" dev="HLS" fixes-bug="TAPESTRY-335">Injection uses actual type of injected object, which may not be available (due to AOP, or due to use of JDK Proxies).</action>
<action type="add" dev="HLS">Add page listing the project voting history.</action>
- <action type="add" dev="HLS">Add InjectObject annotation and basic annotation support (in tapestry-annotation module).</action>
- <action type="add" dev="HLS">Add more annotations: InjectAsset, InjectComponent, InjectState and Persist</action>
+ <action type="add" dev="HLS">Add annotation support (in tapestry-annotation module).</action>
</release>
<release version="4.0-alpha-3" date="May 16 2005">
<action type="add" dev="HLS">Add initial support for the validator: binding prefix.</action>
1.30 +15 -4 jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/spec.xml
Index: spec.xml
===================================================================
RCS file: /home/cvs/jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/spec.xml,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- spec.xml 6 Jun 2005 22:28:19 -0000 1.29
+++ spec.xml 11 Jun 2005 20:04:13 -0000 1.30
@@ -353,10 +353,11 @@
A &bean; is used to add behaviors to a page or component via aggregation.
Each &bean; defines a named JavaBean that is instantiated on demand.
Such managed beans are accessed through the OGNL expression beans.<em>name</em>
-or via the beans: &binding-reference;.
+or via the bean: &binding-reference;.
</p>
<p>
+ Beans are only instantiated one demand, typically by using a bean: &binding-reference;.
Once a bean is instantiated and initialized, it will be retained by the page or component
for some period of time, specified by the bean's lifecycle.
</p>
@@ -375,7 +376,7 @@
<dt>render</dt>
<dd>
The bean is retained until the current render operation completes.
- This will discard the bean when a page or form finishes rewinding.
+ This will also discard the bean when a page or form finishes rewinding.
This is the default lifecycle.
</dd>
@@ -419,14 +420,14 @@
<td>string</td>
<td>yes</td>
<td/>
- <td>The name of the class to instantiate.</td>
+ <td>The name of the class to instantiate. May optionally include <em>lightweight initialization</em> (see below).</td>
</tr>
<tr>
<td>lifecycle</td>
<td>none|page|render|request</td>
<td>no</td>
<td>request</td>
- <td>As described above; duration that bean is retained.</td>
+ <td>As described above; duration that bean is retained once instantiated.</td>
</tr>
<tr>
<td>property</td>
@@ -444,6 +445,16 @@
</table>
+<p>
+<em>Lightweight intialization:</em> A concept borrowed from HiveMind where simple properties of the
+bean can be configured in-line, as a comma-separated list of property=value pairs. The values are converted to appropriate types
+automatically. For boolean values, the value may be omitted. Example:
+</p>
+
+<source>
+ <bean name="validator" class="org.apache.tapestry.valid.StringValidator,required,minimumLength=10"/>
+</source>
+
<p>&bean; Elements:</p>
<source>
1.2 +60 -1 jakarta-tapestry/annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java
Index: AnnotatedPage.java
===================================================================
RCS file: /home/cvs/jakarta-tapestry/annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- AnnotatedPage.java 9 Jun 2005 18:42:48 -0000 1.1
+++ AnnotatedPage.java 11 Jun 2005 20:04:13 -0000 1.2
@@ -14,16 +14,75 @@
package org.apache.tapestry.annotations;
+import java.lang.annotation.Target;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tapestry.IAsset;
+import org.apache.tapestry.form.TextField;
import org.apache.tapestry.html.BasePage;
/**
- * Used by {@link org.apache.tapestry.annotations.TestAnnotationEnhancementWorker}.
+ * Used by {@link org.apache.tapestry.annotations.TestAnnotationEnhancementWorker}. Also a chance
+ * to try each of the annotations out.
*
* @author Howard M. Lewis Ship
* @since 4.0
*/
public abstract class AnnotatedPage extends BasePage
{
+ @Asset("/style/global.css")
+ public abstract IAsset getGlobalStylesheet();
+
@InjectObject("barney")
public abstract Object getInjectedObject();
+
+ @Bean
+ public abstract HashMap getHashMapBean();
+
+ @Bean(HashMap.class)
+ public abstract Map getMapBean();
+
+ @Bean(initializer = "intValue=10")
+ public abstract Target getTarget();
+
+ @Bean(lifecycle = Lifecycle.RENDER)
+ public abstract Map getRenderLifecycleBean();
+
+ @Persist
+ public abstract int getPersistentProperty();
+
+ @Persist("client")
+ public abstract String getClientPersistentProperty();
+
+ @InjectAsset("stylesheet")
+ public abstract IAsset getStylesheetAsset();
+
+ @InjectComponent("fred")
+ public abstract TextField getFredField();
+
+ @InjectState("barney")
+ public abstract Map getBarney();
+
+ @Parameter
+ public abstract String getSimpleParameter();
+
+ @Parameter(required = true)
+ public abstract String getRequiredParameter();
+
+ @Parameter(defaultBinding = "bean")
+ public abstract Object getBeanDefaultParameter();
+
+ @Parameter(cache = false)
+ public abstract Object getNonCachedParameter();
+
+ @Parameter(aliases = "fred")
+ public abstract String getAliasedParameter();
+
+ @Parameter
+ @Deprecated
+ public abstract int getDeprecatedParameter();
+
+ @Parameter(name = "fred")
+ public abstract double getNamedParameter();
}
1.3 +10 -0 jakarta-tapestry/annotations/src/test/org/apache/tapestry/annotations/Target.java
Index: Target.java
===================================================================
RCS file: /home/cvs/jakarta-tapestry/annotations/src/test/org/apache/tapestry/annotations/Target.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- Target.java 9 Jun 2005 22:53:48 -0000 1.2
+++ Target.java 11 Jun 2005 20:04:13 -0000 1.3
@@ -14,6 +14,10 @@
package org.apache.tapestry.annotations;
+import java.util.ArrayList;
+import java.util.Map;
+
+import org.apache.tapestry.IAsset;
import org.apache.tapestry.IComponent;
/**
@@ -41,4 +45,10 @@
public abstract String notAGetter();
public abstract IComponent getBarney();
+
+ public abstract Map getMapBean();
+
+ public abstract ArrayList getArrayListBean();
+
+ public abstract IAsset getMyAsset();
}
1.1 jakarta-tapestry/annotations/src/test/org/apache/tapestry/annotations/TestParameterAnnotationWorker.java
Index: TestParameterAnnotationWorker.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.annotations;
import java.lang.reflect.Method;
import org.apache.tapestry.enhance.EnhancementOperation;
import org.apache.tapestry.spec.ComponentSpecification;
import org.apache.tapestry.spec.IComponentSpecification;
import org.apache.tapestry.spec.IParameterSpecification;
import org.easymock.MockControl;
/**
* Tests for {@link org.apache.tapestry.annotations.ParameterAnnotationWorker}.
*
* @author Howard Lewis Ship
* @since 4.0
*/
public class TestParameterAnnotationWorker extends BaseAnnotationTestCase
{
private IParameterSpecification attempt(String propertyName)
{
return attempt(propertyName, propertyName);
}
private IParameterSpecification attempt(String propertyName, String parameterName)
{
Method m = findMethod(AnnotatedPage.class, "get"
+ propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
MockControl opc = newControl(EnhancementOperation.class);
EnhancementOperation op = (EnhancementOperation) opc.getMock();
op.getPropertyType(propertyName);
opc.setReturnValue(m.getReturnType());
IComponentSpecification spec = new ComponentSpecification();
Parameter annotation = m.getAnnotation(Parameter.class);
replayControls();
new ParameterAnnotationWorker().performEnhancement(op, spec, annotation, m);
verifyControls();
return spec.getParameter(parameterName);
}
public void testSimple()
{
IParameterSpecification ps = attempt("simpleParameter");
assertListsEqual(new Object[] {}, ps.getAliasNames().toArray());
assertEquals(true, ps.getCache());
assertEquals("", ps.getDefaultBindingType());
assertEquals("", ps.getDefaultValue());
assertEquals(null, ps.getDescription());
assertNull(ps.getLocation());
assertEquals("simpleParameter", ps.getParameterName());
assertEquals("simpleParameter", ps.getPropertyName());
assertEquals("java.lang.String", ps.getType());
}
public void testRequired()
{
IParameterSpecification ps = attempt("requiredParameter");
assertEquals(true, ps.isRequired());
}
public void testDefaultBinding()
{
IParameterSpecification ps = attempt("beanDefaultParameter");
assertEquals("bean", ps.getDefaultBindingType());
assertEquals("java.lang.Object", ps.getType());
}
public void testCacheOff()
{
IParameterSpecification ps = attempt("nonCachedParameter");
assertEquals(false, ps.getCache());
}
public void testAliases()
{
IParameterSpecification ps = attempt("aliasedParameter");
assertListsEqual(new String[]
{ "fred" }, ps.getAliasNames().toArray());
}
public void testDeprecated()
{
IParameterSpecification ps = attempt("deprecatedParameter");
assertEquals(true, ps.isDeprecated());
}
public void testNamed()
{
IParameterSpecification ps = attempt("namedParameter", "fred");
assertEquals("fred", ps.getParameterName());
assertEquals("namedParameter", ps.getPropertyName());
}
}
1.1 jakarta-tapestry/annotations/src/test/org/apache/tapestry/annotations/TestAssetAnnotationWorker.java
Index: TestAssetAnnotationWorker.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.annotations;
import java.lang.reflect.Method;
import org.apache.tapestry.enhance.EnhancementOperation;
import org.apache.tapestry.spec.ComponentSpecification;
import org.apache.tapestry.spec.IAssetSpecification;
import org.apache.tapestry.spec.IComponentSpecification;
import org.easymock.MockControl;
/**
* Tests for {@link org.apache.tapestry.annotations.AssetAnnotationWorker}.
*
* @author Howard Lewis Ship
* @since 4.0
*/
public class TestAssetAnnotationWorker extends BaseAnnotationTestCase
{
public void testSuccess()
{
EnhancementOperation op = newOp();
IComponentSpecification spec = new ComponentSpecification();
MockControl assetc = newControl(Asset.class);
Asset asset = (Asset) assetc.getMock();
asset.value();
assetc.setReturnValue("/foo/bar.gif");
replayControls();
Method m = findMethod(Target.class, "getMyAsset");
new AssetAnnotationWorker().performEnhancement(op, spec, asset, m);
verifyControls();
IAssetSpecification as = spec.getAsset("myAsset");
assertEquals("/foo/bar.gif", as.getPath());
assertNull(as.getLocation());
assertEquals("myAsset", as.getPropertyName());
}
}
1.1 jakarta-tapestry/annotations/src/test/org/apache/tapestry/annotations/TestBeanAnnotationWorker.java
Index: TestBeanAnnotationWorker.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.annotations;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.tapestry.bean.LightweightBeanInitializer;
import org.apache.tapestry.enhance.EnhancementOperation;
import org.apache.tapestry.spec.BeanLifecycle;
import org.apache.tapestry.spec.ComponentSpecification;
import org.apache.tapestry.spec.IBeanSpecification;
import org.apache.tapestry.spec.IComponentSpecification;
import org.easymock.MockControl;
/**
* Tests for {@link org.apache.tapestry.annotations.BeanAnnotationWorker}.
*
* @author Howard M. Lewis Ship
* @since 4.0
*/
public class TestBeanAnnotationWorker extends BaseAnnotationTestCase
{
public void testBeanClassSpecified()
{
EnhancementOperation op = newOp();
IComponentSpecification spec = new ComponentSpecification();
MockControl beanc = newControl(Bean.class);
Bean bean = (Bean) beanc.getMock();
Method m = findMethod(Target.class, "getMapBean");
trainBeanClass(beanc, bean, HashMap.class);
trainLifecycle(beanc, bean, Lifecycle.RENDER);
trainInitializer(beanc, bean, "");
replayControls();
new BeanAnnotationWorker().performEnhancement(op, spec, bean, m);
verifyControls();
IBeanSpecification bs = spec.getBeanSpecification("mapBean");
assertEquals("mapBean", bs.getPropertyName());
assertEquals(HashMap.class.getName(), bs.getClassName());
assertEquals(BeanLifecycle.RENDER, bs.getLifecycle());
assertNull(bs.getLocation());
assertNull(bs.getInitializers());
}
public void testBeanClassNotSpecified()
{
MockControl opc = newControl(EnhancementOperation.class);
EnhancementOperation op = (EnhancementOperation) opc.getMock();
IComponentSpecification spec = new ComponentSpecification();
MockControl beanc = newControl(Bean.class);
Bean bean = (Bean) beanc.getMock();
Method m = findMethod(Target.class, "getArrayListBean");
trainBeanClass(beanc, bean, Object.class);
op.getPropertyType("arrayListBean");
opc.setReturnValue(ArrayList.class);
trainLifecycle(beanc, bean, Lifecycle.RENDER);
trainInitializer(beanc, bean, "");
replayControls();
new BeanAnnotationWorker().performEnhancement(op, spec, bean, m);
verifyControls();
IBeanSpecification bs = spec.getBeanSpecification("arrayListBean");
assertEquals("arrayListBean", bs.getPropertyName());
assertEquals(ArrayList.class.getName(), bs.getClassName());
assertEquals(BeanLifecycle.RENDER, bs.getLifecycle());
assertNull(bs.getLocation());
assertNull(bs.getInitializers());
}
public void testInitializer()
{
EnhancementOperation op = newOp();
IComponentSpecification spec = new ComponentSpecification();
MockControl beanc = newControl(Bean.class);
Bean bean = (Bean) beanc.getMock();
Method m = findMethod(Target.class, "getMapBean");
trainBeanClass(beanc, bean, HashMap.class);
trainLifecycle(beanc, bean, Lifecycle.PAGE);
trainInitializer(beanc, bean, "foo,bar=baz");
replayControls();
new BeanAnnotationWorker().performEnhancement(op, spec, bean, m);
verifyControls();
IBeanSpecification bs = spec.getBeanSpecification("mapBean");
assertEquals("mapBean", bs.getPropertyName());
assertEquals(BeanLifecycle.PAGE, bs.getLifecycle());
assertNull(bs.getLocation());
List l = bs.getInitializers();
LightweightBeanInitializer lbi = (LightweightBeanInitializer) l.get(0);
assertEquals("foo,bar=baz", lbi.getPropertyName());
}
private void trainInitializer(MockControl control, Bean bean, String initializer)
{
bean.initializer();
control.setReturnValue(initializer);
}
private void trainLifecycle(MockControl control, Bean bean, Lifecycle lifecycle)
{
bean.lifecycle();
control.setReturnValue(lifecycle);
}
private void trainBeanClass(MockControl beanc, Bean bean, Class beanClass)
{
bean.value();
beanc.setReturnValue(beanClass);
}
}
1.1 jakarta-tapestry/annotations/src/java/org/apache/tapestry/annotations/Parameter.java
Index: Parameter.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to define a parameter for the component.
*
* @author Howard Lewis Ship
* @since 4.0
*/
@Target(
{ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Parameter {
/**
* If true, then the parameter is required, and must be bound (there is no guarantee that a
* non-null value will be bound however, so the component may have to perform additonal checks).
* The default value, false, means the parameter is optional.
*/
boolean required() default false;
/**
* The default binding type, used when the parameter is bound without an explicit binding
* prefix. Note that this default binding will apply to the {@link #defaultValue}.
*/
String defaultBinding() default "";
/**
* The default value for the binding, as a binding reference.
*/
String defaultValue() default "";
/**
* If true (the default), then the binding will cache its value while the component is
* renderering. In some cases, it is desirable to force the binding to be re-evaluated every
* time the parameter property is accessed, in which case cache should be set to false.
*/
boolean cache() default true;
/**
* An optional list of alternate names for the parameter. The parameter may be bound using its
* true name or any alias (but not both!), but use of aliases will generate deprecation
* warnings.
*/
String aliases() default "";
/**
* The name of the parameter. If not specified, it will match the property name. Note that this
* is backwards from the logic in the XML, where the parameter name is specified and the property name
* matches.
*
*/
String name() default "";
}
1.1 jakarta-tapestry/annotations/src/java/org/apache/tapestry/annotations/Lifecycle.java
Index: Lifecycle.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.annotations;
import org.apache.tapestry.spec.BeanLifecycle;
/**
* Enum version of {@link org.apache.tapestry.spec.BeanLifecycle}.
*
* @author Howard Lewis Ship
* @since 4.0
*/
public enum Lifecycle {
// Preferred this enum as a member of the Bean interface, but Clover couldn't handle that.
NONE(BeanLifecycle.NONE), REQUEST(BeanLifecycle.REQUEST), PAGE(BeanLifecycle.PAGE), RENDER(
BeanLifecycle.RENDER);
private final BeanLifecycle _beanLifecycle;
Lifecycle(BeanLifecycle beanLifecycle)
{
_beanLifecycle = beanLifecycle;
}
public BeanLifecycle getBeanLifecycle()
{
return _beanLifecycle;
}
}
1.1 jakarta-tapestry/annotations/src/java/org/apache/tapestry/annotations/AssetAnnotationWorker.java
Index: AssetAnnotationWorker.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.annotations;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.apache.tapestry.enhance.EnhancementOperation;
import org.apache.tapestry.spec.AssetSpecification;
import org.apache.tapestry.spec.IAssetSpecification;
import org.apache.tapestry.spec.IComponentSpecification;
/**
* Uses the {@link org.apache.tapestry.annotations.Asset} annotation to create a new
* {@link org.apache.tapestry.spec.IAssetSpecification} which is then added to the
* {@link org.apache.tapestry.spec.IComponentSpecification}.
*
* @author Howard Lewis Ship
* @since 4.0
*/
public class AssetAnnotationWorker implements MethodAnnotationEnhancementWorker
{
public void performEnhancement(EnhancementOperation op, IComponentSpecification spec,
Annotation annotation, Method method)
{
Asset asset = (Asset) annotation;
String propertyName = AnnotationUtils.getPropertyName(method);
IAssetSpecification as = new AssetSpecification();
as.setPath(asset.value());
as.setPropertyName(propertyName);
spec.addAsset(propertyName, as);
}
}
1.1 jakarta-tapestry/annotations/src/java/org/apache/tapestry/annotations/BeanAnnotationWorker.java
Index: BeanAnnotationWorker.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.annotations;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.apache.hivemind.HiveMind;
import org.apache.tapestry.bean.LightweightBeanInitializer;
import org.apache.tapestry.enhance.EnhancementOperation;
import org.apache.tapestry.spec.BeanSpecification;
import org.apache.tapestry.spec.IBeanSpecification;
import org.apache.tapestry.spec.IComponentSpecification;
/**
* Creates a {@link org.apache.tapestry.spec.IBeanSpecification} from the
* {@link org.apache.tapestry.annotations.Bean} annotation.
*
* @author Howard M. Lewis Ship
* @since 4.0
*/
public class BeanAnnotationWorker implements MethodAnnotationEnhancementWorker
{
public void performEnhancement(EnhancementOperation op, IComponentSpecification spec,
Annotation annotation, Method method)
{
Bean bean = (Bean) annotation;
String propertyName = AnnotationUtils.getPropertyName(method);
Class beanClass = bean.value();
if (beanClass.equals(Object.class))
beanClass = op.getPropertyType(propertyName);
IBeanSpecification bs = new BeanSpecification();
// A shame to convert it to a string then back to
// a class later, but ...
bs.setClassName(beanClass.getName());
bs.setPropertyName(propertyName);
// Starting to like enums!
bs.setLifecycle(bean.lifecycle().getBeanLifecycle());
String initializer = bean.initializer();
if (HiveMind.isNonBlank(initializer))
bs.addInitializer(new LightweightBeanInitializer(initializer));
spec.addBeanSpecification(propertyName, bs);
}
}
1.1 jakarta-tapestry/annotations/src/java/org/apache/tapestry/annotations/Asset.java
Index: Asset.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Defines a new asset. The asset will have the same name as the property (and will be accessible
* via the "asset:" binding prefix, or using {@link org.apache.tapestry.IComponent#getAsset(String)},
* with that name).
* <p>
* Note: if we ever rename IAsset to Asset, this will cause a naming conflict. Perhaps we should
* come up with annotation names that are compatible with a potential rename.
*
* @author Howard M. Lewis Ship
* @since 4.0
*/
@Target(
{ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Asset {
/**
* The value is the asset path, which may include a prefix to define the module in which it can
* be resolved.
*/
String value();
}
1.1 jakarta-tapestry/annotations/src/java/org/apache/tapestry/annotations/Bean.java
Index: Bean.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.tapestry.spec.BeanLifecycle;
/**
* Annotation used to <em>define</em> new managed beans, including limited/lightweight
* initialization. For complex initialiation, the XML specification is necessary.
* <p>
* One of the advantages is that, on the XML side, it is always necessary to provide complete class
* names; here on the Java/annotation side, we can leverage imports.
* <p>
* The managed bean will have a name that matches the property name; this allows such a bean to be
* referenced via the "bean:" binding prefix, or via
* {@link org.apache.tapestry.IComponent#getBeans()}.
* <p>
* This annotation adds a new {@link org.apache.tapestry.spec.IBeanSpecification} to the
* {@link org.apache.tapestry.spec.IComponentSpecification}.
*
* @author Howard M. Lewis Ship
* @since 4.0
*/
@Target(
{ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
/**
* The Java class to instantiate. The default is Object.class; if a non-default value is
* specified, that will be the class to instantiate; otherwise, the bean class will be
* determined from the property type. Generally, this annotation is only used when the property
* type is an interface (or abstract base class).
*/
Class value() default Object.class;
/**
* Optional initializer string for the bean, as <em>lightweight initialization</em> (a list of
* properties and values).
*/
String initializer() default "";
/**
* The lifecycle of the bean, defaults to Lifecycle.REQUEST.
*
* @see BeanLifecycle
*/
Lifecycle lifecycle() default Lifecycle.REQUEST;
}
1.1 jakarta-tapestry/annotations/src/java/org/apache/tapestry/annotations/ParameterAnnotationWorker.java
Index: ParameterAnnotationWorker.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.annotations;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.apache.hivemind.HiveMind;
import org.apache.tapestry.enhance.EnhancementOperation;
import org.apache.tapestry.spec.IComponentSpecification;
import org.apache.tapestry.spec.IParameterSpecification;
import org.apache.tapestry.spec.ParameterSpecification;
/**
* Generates a {@link org.apache.tapestry.spec.IParameterSpecification} from a
* {@link org.apache.tapestry.annotations.Parameter} annotation and adds it to the
* {@link org.apache.tapestry.spec.IComponentSpecification}.
*
* @author Howard M. Lewis Ship
* @since 4.0
*/
public class ParameterAnnotationWorker implements MethodAnnotationEnhancementWorker
{
public void performEnhancement(EnhancementOperation op, IComponentSpecification spec,
Annotation annotation, Method method)
{
Parameter parameter = (Parameter) annotation;
String propertyName = AnnotationUtils.getPropertyName(method);
boolean deprecated = method.isAnnotationPresent(Deprecated.class);
IParameterSpecification ps = new ParameterSpecification();
String parameterName = parameter.name();
if (HiveMind.isBlank(parameterName))
parameterName = propertyName;
Class propertyType = op.getPropertyType(propertyName);
ps.setAliases(parameter.aliases());
ps.setCache(parameter.cache());
ps.setDefaultBindingType(parameter.defaultBinding());
ps.setDefaultValue(parameter.defaultValue());
ps.setDeprecated(deprecated);
ps.setParameterName(parameterName);
ps.setPropertyName(propertyName);
ps.setRequired(parameter.required());
ps.setType(propertyType.getName());
spec.addParameter(ps);
}
}
1.3 +132 -6 jakarta-tapestry/annotations/src/documentation/content/xdocs/tapestry-annotations/index.xml
Index: index.xml
===================================================================
RCS file: /home/cvs/jakarta-tapestry/annotations/src/documentation/content/xdocs/tapestry-annotations/index.xml,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- index.xml 9 Jun 2005 22:53:48 -0000 1.2
+++ index.xml 11 Jun 2005 20:04:13 -0000 1.3
@@ -28,27 +28,108 @@
</header>
<body>
- <p> This library does not contain components; instead it provides <em>annotations</em>,
+ <p> This library does not contain components; instead it provides
+ Tapestry specific <em>annotations</em> (annotations are a
a <link href="http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html">new feature
- in JDK 1.5</link>. 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. </p>
+ in JDK 1.5</link>).
+ 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. </p>
<p>
The annotations are all in the package org.apache.tapestry.annotations.
</p>
<p>
- Remember that a property should only have, at most, one of these annotations! Having multiple
- annotations, or conflicts between annotations and directives in the specification, will result
+ 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).
</p>
+
+<section>
+ <title>Asset</title>
+
+
+<p>The <link href="&javadoc;/Asset.html">Asset</link> annotation is the equivalent of the
+ <link href="&spec;#spec.asset"><asset></link> element in a specification. The value attribute
+ is the path to the asset (possibly prefixed to indicate the domain for the path):</p>
+
+<source>
+ @Asset("/style/global.css")
+ public abstract IAsset getGlobalStylesheet();
+</source>
+
+<p>
+The asset will be avaialble using the property name using the "asset:" binding prefix.
+</p>
+
+
+</section>
+
+
+<section>
+ <title>Bean</title>
+
+ <p>
+ The <link href="&javadoc;/Bean.html">Bean</link> annotation is the equivalent
+ of the <link href="&spec;#spec.bean"><bean></link> element in a specification.
+ </p>
+
+ <p>
+ 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).
+ </p>
+
+<p>
+ The examples below both define a bean of type HashMap:
+</p>
+
+<source>
+ @Bean
+ public abstract HashMap getHashMapBean();
+
+ @Bean(HashMap.class)
+ public abstract Map getMapBean();
+</source>
+
+<p>
+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.
+</p>
+
+<p>
+An additional attribute, lifecycle, controls the bean's lifecycle. The default is
+<link href="&apidoc;/Lifecycle.html">Lifecycle</link>.REQUEST,
+and additional values are NONE, PAGE, and RENDER:
+</p>
+
+<source>
+ @Bean(lifecycle = Lifecycle.RENDER)
+ public abstract Map getRenderLifecycleBean();
+</source>
+
+<p>
+Lastly, for <em>simple</em> configuration of the bean, there's the initializer attribute. This
+allows <em>lightweight initialization</em>, where the string is a series of name=value properties, seperated by
+commas (for boolean properties, the value is optional).
+</p>
+
+<source>
+ @Bean(initializer = "maxRetries=3")
+ public abstract LoginController getController();
+</source>
+
+</section>
<section>
<title>InjectAsset</title>
<p>
- The <link href="&javadoc;InjectAsset.html">InjectAsset</link> annotation
+ The <link href="&javadoc;/InjectAsset.html">InjectAsset</link> annotation
allows assets defined in the page or component specification to be exposed
as read-only properties. It is attached to an accessor method:
</p>
@@ -129,12 +210,57 @@
</section>
<section>
+ <title>Parameter</title>
+
+<p>
+ The <link href="&javadoc;/Parameter.html">Parameter</link> annotation defines a new property,
+ as with <link href="&spec;#spec.parameter"><parameter></link> element in an XML
+ component specification.
+</p>
+
+<p>
+ This most simple use of this annotation is to simply mark a property as an optional parameter:
+</p>
+
+<source>
+ @Parameter
+ public abstract void MyType getMyParameter();
+</source>
+
+<p>
+ 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:
+</p>
+
+<source>
+ @Parameter(name="page")
+ public abstract String getTargetPage();
+</source>
+
+<p>
+ Parameters may be marked as deprecated if the method is marked deprecated (using the java.lang.Deprecated
+ annotation):
+</p>
+
+<source>
+ @Deprecated @Parameter
+ public abstract int getRows();
+</source>
+
+<p>
+The annotation supports several additional attributes, consult its <link href="&javadoc;/Parameter.html">JavaDoc</link>
+ for the full details.
+</p>
+
+</section>
+
+<section>
<title>Persist</title>
<p>
The <link href="&javadoc;/Persist.html">Persist</link> annotation allows a property to be
marked as persistent. Remember that any otherwise unclaimed abstract property will become
- a <em>transient</em> property automatically (in Tapestry 4.0), so Persist is only need
+ a <em>transient</em> property automatically (in Tapestry 4.0), so Persist is only needed
to mark a property as persistent.
</p>
1.3 +1 -1 jakarta-tapestry/annotations/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/jakarta-tapestry/annotations/build.xml,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- build.xml 9 Jun 2005 22:53:48 -0000 1.2
+++ build.xml 11 Jun 2005 20:04:13 -0000 1.3
@@ -54,7 +54,7 @@
<hivedoc-report/>
<javadoc-report/>
<junit-report/>
- <clover-report/>
+ <clover-report/>
</target>
</project>
1.1 jakarta-tapestry/framework/src/test/org/apache/tapestry/bean/TargetBean.java
Index: TargetBean.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.bean;
/**
* Used by {@link org.apache.tapestry.bean.TestLightweightBeanInitializer} to verify that
* initialization does occur.
*
* @author Howard M. Lewis Ship
* @since 4.0
*/
public class TargetBean
{
private boolean _required;
private int _minLength;
public int getMinLength()
{
return _minLength;
}
public void setMinLength(int minLength)
{
_minLength = minLength;
}
public boolean isRequired()
{
return _required;
}
public void setRequired(boolean required)
{
_required = required;
}
}
1.1 jakarta-tapestry/framework/src/test/org/apache/tapestry/bean/TestLightweightBeanInitializer.java
Index: TestLightweightBeanInitializer.java
===================================================================
// Copyright 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.bean;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.Location;
import org.apache.hivemind.test.HiveMindTestCase;
/**
* Tests for {@link org.apache.tapestry.bean.LightweightBeanInitializer}.
*
* @author Howard M. Lewis Ship
* @since 4.0
*/
public class TestLightweightBeanInitializer extends HiveMindTestCase
{
public void testSuccess()
{
String initializer = "required,minLength=10";
TargetBean bean = new TargetBean();
assertEquals(false, bean.isRequired());
assertEquals(0, bean.getMinLength());
IBeanInitializer bi = new LightweightBeanInitializer(initializer);
assertEquals(initializer, bi.getPropertyName());
bi.setBeanProperty(null, bean);
assertEquals(true, bean.isRequired());
assertEquals(10, bean.getMinLength());
}
public void testFailure()
{
Location l = newLocation();
IBeanInitializer bi = new LightweightBeanInitializer("zip=zap");
bi.setLocation(l);
TargetBean bean = new TargetBean();
try
{
bi.setBeanProperty(null, bean);
unreachable();
}
catch (ApplicationRuntimeException ex)
{
assertEquals("Class org.apache.tapestry.bean.TargetBean "
+ "does not contain a property named 'zip'.", ex.getMessage());
assertSame(l, ex.getLocation());
}
}
}
1.6 +1 -1 jakarta-tapestry/framework/src/java/org/apache/tapestry/parse/Tapestry_4_0.dtd
Index: Tapestry_4_0.dtd
===================================================================
RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/parse/Tapestry_4_0.dtd,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- Tapestry_4_0.dtd 6 Jun 2005 22:28:19 -0000 1.5
+++ Tapestry_4_0.dtd 11 Jun 2005 20:04:13 -0000 1.6
@@ -104,7 +104,7 @@
"none" no lifecycle, the bean is created and returned, but not stored
"request" the bean is retained until the end of the request cycle
"page" the bean is retained for the lifespan of the page
- "render" the bean is retained until the end of the current page render
+ "render" (default) the bean is retained until the end of the current page render
property: if specified, then a read-ony property is created in the component
to access the bean.
1.3 +3 -2 jakarta-tapestry/framework/src/java/org/apache/tapestry/binding/BindingUtils.java
Index: BindingUtils.java
===================================================================
RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/binding/BindingUtils.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- BindingUtils.java 18 Apr 2005 17:06:35 -0000 1.2
+++ BindingUtils.java 11 Jun 2005 20:04:13 -0000 1.3
@@ -14,6 +14,7 @@
package org.apache.tapestry.binding;
+import org.apache.hivemind.HiveMind;
import org.apache.tapestry.spec.IComponentSpecification;
import org.apache.tapestry.spec.IParameterSpecification;
@@ -34,7 +35,7 @@
* the name of the parameter to bind which may be either the name of a formal or
* informal parameter
* @returns the default binding type defined by the matching {@link IParameterSpecification},
- * or {@link BindingConstants.LITERAL_PREFIX} for informal parameters.
+ * or {@link BindingConstants.LITERAL_PREFIX} for informal parameters.
*/
public static String getDefaultBindingType(IComponentSpecification specification,
String parameterName, String metaDefaultBindingType)
@@ -46,7 +47,7 @@
if (ps != null)
result = ps.getDefaultBindingType();
- if (result == null)
+ if (HiveMind.isBlank(result))
result = metaDefaultBindingType;
return result;
1.10 +3 -2 jakarta-tapestry/framework/src/java/org/apache/tapestry/spec/IParameterSpecification.java
Index: IParameterSpecification.java
===================================================================
RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/spec/IParameterSpecification.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- IParameterSpecification.java 6 Jun 2005 22:28:19 -0000 1.9
+++ IParameterSpecification.java 11 Jun 2005 20:04:13 -0000 1.10
@@ -86,8 +86,9 @@
/**
* Sets the default binding type, used when a parameter is bound without specifying an explicit
- * binding prefix. May be null, in which case the default binding type is determined by whether
- * the parameter is bound in an HTML template or in a page or component specification.
+ * binding prefix. May be blank (null or empty string), in which case the default binding type
+ * is determined by whether the parameter is bound in an HTML template or in a page or component
+ * specification.
*
* @see org.apache.tapestry.binding.BindingConstants
* @see org.apache.tapestry.binding.BindingUtils#getDefaultBindingType(IComponentSpecification,
1.3 +3 -0 jakarta-tapestry/annotations/src/descriptor/META-INF/hivemodule.xml
Index: hivemodule.xml
===================================================================
RCS file: /home/cvs/jakarta-tapestry/annotations/src/descriptor/META-INF/hivemodule.xml,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- hivemodule.xml 9 Jun 2005 22:53:48 -0000 1.2
+++ hivemodule.xml 11 Jun 2005 20:04:13 -0000 1.3
@@ -71,6 +71,9 @@
<worker annotation="InjectState" object="instance:InjectStateAnnotationWorker"/>
<worker annotation="InjectAsset" object="instance:InjectAssetAnnotationWorker"/>
<worker annotation="Persist" object="instance:PersistAnnotationWorker"/>
+ <worker annotation="Bean" object="instance:BeanAnnotationWorker"/>
+ <worker annotation="Asset" object="instance:AssetAnnotationWorker"/>
+ <worker annotation="Parameter" object="instance:ParameterAnnotationWorker"/>
</contribution>
1.19 +16 -0 jakarta-tapestry/framework/src/test/org/apache/tapestry/junit/parse/TestSpecificationParser.java
Index: TestSpecificationParser.java
===================================================================
RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/junit/parse/TestSpecificationParser.java,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- TestSpecificationParser.java 6 Jun 2005 22:28:19 -0000 1.18
+++ TestSpecificationParser.java 11 Jun 2005 20:04:13 -0000 1.19
@@ -18,6 +18,7 @@
import org.apache.hivemind.Locatable;
import org.apache.tapestry.bean.BindingBeanInitializer;
+import org.apache.tapestry.bean.LightweightBeanInitializer;
import org.apache.tapestry.junit.TapestryTestCase;
import org.apache.tapestry.spec.BindingType;
import org.apache.tapestry.spec.IApplicationSpecification;
@@ -705,6 +706,21 @@
assertEquals("myProperty", bs.getPropertyName());
}
+ /**
+ * @since 4.0
+ */
+
+ public void testBeanInitializer() throws Exception
+ {
+ IComponentSpecification cs = parseComponent("BeanInitializer.jwc");
+ IBeanSpecification bs = cs.getBeanSpecification("bean");
+
+ List l = bs.getInitializers();
+ LightweightBeanInitializer lbi = (LightweightBeanInitializer) l.get(0);
+
+ assertEquals("foo=bar", lbi.getPropertyName());
+ }
+
/** @since 4.0 */
public void testLibraryDescription() throws Exception
1.1 jakarta-tapestry/framework/src/test/org/apache/tapestry/junit/parse/BeanInitializer.jwc
Index: BeanInitializer.jwc
===================================================================
<?xml version="1.0"?>
<!--
Copyright 2005 The Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE component-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 4.0//EN"
"http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
<component-specification>
<bean name="bean" class="java.util.HashMap,foo=bar"/>
</component-specification>
---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org