Author: hlship
Date: Wed Dec 20 16:27:14 2006
New Revision: 489232
URL: http://svn.apache.org/viewvc?view=rev&rev=489232
Log:
Allow render phase methods to be identified simply by specific names, in
addition to arbitrary names with annotations
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/MethodFilter.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorker.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Output.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Strong.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorker.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorker.java?view=diff&rev=489232&r1=489231&r2=489232
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorker.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorker.java
Wed Dec 20 16:27:14 2006
@@ -12,136 +12,157 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.internal.services;
-
-import java.lang.annotation.Annotation;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.tapestry.MarkupWriter;
+package org.apache.tapestry.internal.services;
+
+import java.lang.annotation.Annotation;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.internal.util.MethodInvocationBuilder;
import org.apache.tapestry.ioc.internal.util.InternalUtils;
import org.apache.tapestry.ioc.util.BodyBuilder;
-import org.apache.tapestry.model.MutableComponentModel;
-import org.apache.tapestry.services.ClassTransformation;
-import org.apache.tapestry.services.ComponentClassTransformWorker;
-import org.apache.tapestry.services.MethodSignature;
-
-/**
- * Converts one of the methods of [EMAIL PROTECTED]
org.apache.tapestry.runtime.Component} into a
- * chain of command that, itself, invokes certain methods marked with an
annotation.
- */
-public class ComponentLifecycleMethodWorker implements
ComponentClassTransformWorker
-{
- private static final String CHECK_ABORT_FLAG = "if ($2.isAborted())
return;";
-
- private final Class<? extends Annotation> _methodAnnotation;
-
- private final MethodSignature _lifecycleMethodSignature;
-
- private final String _lifecycleMethodName;
-
- private final boolean _reverse;
-
- private final MethodInvocationBuilder _invocationBuilder = new
MethodInvocationBuilder();
-
- /**
- * Normal method invocation: parent class, then methods in ascending
alphabetical order. Reverse
- * order: method in descending alphabetical order, then parent class.
- *
- * @param lifecycleMethodSignature
- * the signature of the method to be implemented in the
component class
- * @param methodAnnotation
- * the class of the corresponding annotation
- * @param reverse
- * if true, the normal method invocation order is reversed
- */
- public ComponentLifecycleMethodWorker(MethodSignature
lifecycleMethodSignature,
- Class<? extends Annotation> methodAnnotation, boolean reverse)
- {
- _lifecycleMethodSignature = lifecycleMethodSignature;
- _methodAnnotation = methodAnnotation;
- _reverse = reverse;
- _lifecycleMethodName = lifecycleMethodSignature.getMethodName();
-
- _invocationBuilder.addParameter(MarkupWriter.class.getName(), "$1");
- }
-
- @Override
- public String toString()
- {
- return String.format("ComponentLifecycleMethodWorker[%s]",
_methodAnnotation.getName());
- }
-
- public void transform(ClassTransformation transformation,
MutableComponentModel model)
- {
- List<MethodSignature> methods =
transformation.findMethodsWithAnnotation(_methodAnnotation);
-
- // Except in the root class, don't bother to add a new method unless
there's something to
- // call (beside super).
-
- if (methods.isEmpty())
- return;
-
- BodyBuilder builder = new BodyBuilder();
- builder.begin();
-
- // If in a subclass, and in normal order mode, invoke the super class
version first.
-
- if (!(_reverse || model.isRootClass()))
- {
- builder.addln("super.%s($$);", _lifecycleMethodName);
- builder.addln(CHECK_ABORT_FLAG);
- }
-
- Iterator<MethodSignature> i = _reverse ?
InternalUtils.reverseIterator(methods) : methods
- .iterator();
-
- while (i.hasNext())
- addMethodCallToBody(builder, i.next(), transformation);
-
- // In reverse order in a a subclass, invoke the super method last.
-
- if (_reverse && !model.isRootClass())
- builder.addln("super.%s($$);", _lifecycleMethodName);
-
- builder.end();
-
- // Let's see if this works; for base classes, we are adding an empty
method the adding a
- // non-empty
- // method "on top of it".
-
- transformation.addMethod(_lifecycleMethodSignature,
builder.toString());
- }
-
- private void addMethodCallToBody(BodyBuilder builder, MethodSignature sig,
- ClassTransformation transformation)
- {
- boolean isVoid = sig.getReturnType().equals("void");
-
- if (!isVoid)
- builder.add("if ($2.storeResult(($w) ");
-
- // This is the best part; the method can even be private and this
still works. It's a lot
- // like how javac enables access to private members for inner classes
(by introducing
- // synthetic, static methods).
-
- builder.add(_invocationBuilder.buildMethodInvocation(sig,
transformation));
-
- // Now, if non void ...
-
- if (!isVoid)
- {
- // Complete the call to storeResult(), with a string that
- // identifies the class and the method. Finish off the if(...) that
- // checks the return value and returns early. The return value of
- // LifecycleEvent.storeResult() is true if the event is aborted by
the call.
-
- builder.addln(", \"%s.%s\")) return;",
transformation.getClassName(), sig
- .getMediumDescription());
- }
- else
- builder.addln(";");
- }
-
-}
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
+import org.apache.tapestry.services.MethodFilter;
+import org.apache.tapestry.services.MethodSignature;
+
+/**
+ * Converts one of the methods of [EMAIL PROTECTED]
org.apache.tapestry.runtime.Component} into a chain of
+ * command that, itself, invokes certain methods (render phase methods) marked
with an annotation,
+ * or named in a specific way.
+ */
+public class ComponentLifecycleMethodWorker implements
ComponentClassTransformWorker
+{
+ private static final String CHECK_ABORT_FLAG = "if ($2.isAborted())
return;";
+
+ private final Class<? extends Annotation> _methodAnnotation;
+
+ private final MethodSignature _lifecycleMethodSignature;
+
+ private final String _lifecycleMethodName;
+
+ private final boolean _reverse;
+
+ private final MethodInvocationBuilder _invocationBuilder = new
MethodInvocationBuilder();
+
+ /**
+ * Normal method invocation: parent class, then methods in ascending
alphabetical order. Reverse
+ * order: method in descending alphabetical order, then parent class.
+ *
+ * @param lifecycleMethodSignature
+ * the signature of the method to be implemented in the
component class
+ * @param methodAnnotation
+ * the class of the corresponding annotation
+ * @param reverse
+ * if true, the normal method invocation order is reversed
+ */
+ public ComponentLifecycleMethodWorker(MethodSignature
lifecycleMethodSignature,
+ Class<? extends Annotation> methodAnnotation, boolean reverse)
+ {
+ _lifecycleMethodSignature = lifecycleMethodSignature;
+ _methodAnnotation = methodAnnotation;
+ _reverse = reverse;
+ _lifecycleMethodName = lifecycleMethodSignature.getMethodName();
+
+ _invocationBuilder.addParameter(MarkupWriter.class.getName(), "$1");
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("ComponentLifecycleMethodWorker[%s]",
_methodAnnotation.getName());
+ }
+
+ public void transform(final ClassTransformation transformation,
MutableComponentModel model)
+ {
+ MethodFilter filter = new MethodFilter()
+ {
+ public boolean accept(MethodSignature signature)
+ {
+ // These methods get added to base classes and otherwise fall
into this filter. If we don't
+ // include this filter, then we get endless loops.
+
+ if (signature.equals(_lifecycleMethodSignature))
+ return false;
+
+ // A degenerate case would be a method, say beginRender(),
with an conflicting
+ // annotation, say @AfterRender. In that case, this code is
broken, as the method
+ // will be invoked for both phases!
+
+ return signature.getMethodName().equals(_lifecycleMethodName)
+ || transformation.getMethodAnnotation(signature,
_methodAnnotation) != null;
+ }
+ };
+
+ List<MethodSignature> methods = transformation.findMethods(filter);
+
+ // Except in the root class, don't bother to add a new method unless
there's something to
+ // call (beside super).
+
+ if (methods.isEmpty())
+ return;
+
+ BodyBuilder builder = new BodyBuilder();
+ builder.begin();
+
+ // If in a subclass, and in normal order mode, invoke the super class
version first.
+
+ if (!(_reverse || model.isRootClass()))
+ {
+ builder.addln("super.%s($$);", _lifecycleMethodName);
+ builder.addln(CHECK_ABORT_FLAG);
+ }
+
+ Iterator<MethodSignature> i = _reverse ?
InternalUtils.reverseIterator(methods) : methods
+ .iterator();
+
+ while (i.hasNext())
+ addMethodCallToBody(builder, i.next(), transformation);
+
+ // In reverse order in a a subclass, invoke the super method last.
+
+ if (_reverse && !model.isRootClass())
+ builder.addln("super.%s($$);", _lifecycleMethodName);
+
+ builder.end();
+
+ // Let's see if this works; for base classes, we are adding an empty
method the adding a
+ // non-empty
+ // method "on top of it".
+
+ transformation.addMethod(_lifecycleMethodSignature,
builder.toString());
+ }
+
+ private void addMethodCallToBody(BodyBuilder builder, MethodSignature sig,
+ ClassTransformation transformation)
+ {
+ boolean isVoid = sig.getReturnType().equals("void");
+
+ if (!isVoid)
+ builder.add("if ($2.storeResult(($w) ");
+
+ // This is the best part; the method can even be private and this
still works. It's a lot
+ // like how javac enables access to private members for inner classes
(by introducing
+ // synthetic, static methods).
+
+ builder.add(_invocationBuilder.buildMethodInvocation(sig,
transformation));
+
+ // Now, if non void ...
+
+ if (!isVoid)
+ {
+ // Complete the call to storeResult(), with a string that
+ // identifies the class and the method. Finish off the if(...) that
+ // checks the return value and returns early. The return value of
+ // LifecycleEvent.storeResult() is true if the event is aborted by
the call.
+
+ builder.addln(", \"%s.%s\")) return;",
transformation.getClassName(), sig
+ .getMediumDescription());
+ }
+ else
+ builder.addln(";");
+ }
+
+}
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java?view=diff&rev=489232&r1=489231&r2=489232
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
Wed Dec 20 16:27:14 2006
@@ -52,6 +52,7 @@
import org.apache.tapestry.ioc.internal.util.InternalUtils;
import org.apache.tapestry.model.ComponentModel;
import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.services.MethodFilter;
import org.apache.tapestry.services.MethodSignature;
import org.apache.tapestry.services.TransformUtils;
@@ -866,6 +867,25 @@
MethodSignature sig = getMethodSignature(method);
result.add(sig);
}
+ }
+
+ Collections.sort(result);
+
+ return result;
+ }
+
+ public List<MethodSignature> findMethods(MethodFilter filter)
+ {
+ notNull(filter, "filter");
+
+ List<MethodSignature> result = newList();
+
+ for (CtMethod method : _ctClass.getDeclaredMethods())
+ {
+ MethodSignature sig = getMethodSignature(method);
+
+ if (filter.accept(sig))
+ result.add(sig);
}
Collections.sort(result);
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java?view=diff&rev=489232&r1=489231&r2=489232
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java
Wed Dec 20 16:27:14 2006
@@ -79,6 +79,15 @@
List<MethodSignature> findMethodsWithAnnotation(Class<? extends
Annotation> annotationClass);
/**
+ * Finds all methods matched by the provided filter.
+ *
+ * @param filter
+ * Passed each method signature, it may include or exclude each
potential
+ * @return a list of matching method signatures (which may be empty) in
ascending order
+ */
+ List<MethodSignature> findMethods(MethodFilter filter);
+
+ /**
* Finds an annotation for the class itself, including any annotations
inherited from parent
* classes.
*
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/MethodFilter.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/MethodFilter.java?view=auto&rev=489232
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/MethodFilter.java
(added)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/MethodFilter.java
Wed Dec 20 16:27:14 2006
@@ -0,0 +1,13 @@
+package org.apache.tapestry.services;
+
+/**
+ * Used by [EMAIL PROTECTED] ClassTransformation#findMethods(MethodFilter)} to
accept or reject each method.
+ */
+public interface MethodFilter
+{
+ /**
+ * Passed each signature in turn, only signatures for which this method
returns true will be
+ * included in the final result.
+ */
+ boolean accept(MethodSignature signature);
+}
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java?view=diff&rev=489232&r1=489231&r2=489232
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
Wed Dec 20 16:27:14 2006
@@ -16,6 +16,7 @@
import static java.lang.Thread.sleep;
import static org.apache.tapestry.internal.test.CodeEq.codeEq;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
import static org.easymock.EasyMock.eq;
import java.io.File;
@@ -56,6 +57,7 @@
import org.apache.tapestry.services.ClasspathAssetAliasManager;
import org.apache.tapestry.services.ComponentClassResolver;
import org.apache.tapestry.services.InjectionProvider;
+import org.apache.tapestry.services.MethodFilter;
import org.apache.tapestry.services.MethodSignature;
import org.apache.tapestry.services.ResourceDigestGenerator;
import org.apache.tapestry.services.Context;
@@ -63,6 +65,8 @@
import org.apache.tapestry.services.RequestHandler;
import org.apache.tapestry.services.Response;
import org.apache.tapestry.services.Session;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
/**
* Base test case that adds a number of convienience factory and training
methods for the public
@@ -511,5 +515,39 @@
protected final void train_getDateHeader(Request request, String name,
long value)
{
expect(request.getDateHeader(name)).andReturn(value).atLeastOnce();
+ }
+
+ protected final void train_findMethods(ClassTransformation transformation,
final MethodSignature... signatures)
+ {
+ IAnswer<List<MethodSignature>> answer = new
IAnswer<List<MethodSignature>>()
+ {
+ public List<MethodSignature> answer() throws Throwable
+ {
+ // Can't think of a way to do this without duplicating some
code out of
+ // InternalClassTransformationImpl
+
+ List<MethodSignature> result = newList();
+ MethodFilter filter = (MethodFilter)
EasyMock.getCurrentArguments()[0];
+
+ for (MethodSignature sig : signatures)
+ {
+ if (filter.accept(sig))
+ result.add(sig);
+ }
+
+ // We don't have to sort them for testing purposes. Usually
there's just going to be
+ // one in there.
+
+ return result;
+ }
+
+ };
+
+
expect(transformation.findMethods(EasyMock.isA(MethodFilter.class))).andAnswer(answer);
+ }
+
+ protected final void train_isRootClass(MutableComponentModel model,
boolean isRootClass)
+ {
+ expect(model.isRootClass()).andReturn(isRootClass);
}
}
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt?view=diff&rev=489232&r1=489231&r2=489232
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt Wed
Dec 20 16:27:14 2006
@@ -194,6 +194,75 @@
*
{{{../apidocs/org/apache/tapestry/annotations/CleanupRender.html}CleanupRender}}
The counterpart to SetupRender, this allows final cleanups to occur.
+
+Using Method Names instead of Annotations
+
+ If you prefer to avoid using annotations on your methods, you may do so by
providing specific names for your methods.
+ The required method name is the annotation name, with the first character
decapitalized: setupRender(), beginRender(), etc.
+ As with annotated render phase methods, Tapestry is flexible about
visibility, return type and parameters.
+
+ Using this mechanism, the earlier example can be rewritten as:
+
++---+
+package org.example.app.components;
+
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Parameter;
+
[EMAIL PROTECTED]
+public class Count
+{
+ @Parameter
+ private int _start = 1;
+
+ @Parameter(required = true)
+ private int _end;
+
+ @Parameter
+ private int _value;
+
+ private boolean _increment;
+
+ void setupRender()
+ {
+ _value = _start;
+
+ _increment = _start < _end;
+ }
+
+ boolean afterRender()
+ {
+ if (_increment)
+ {
+ int newValue = _value + 1;
+
+ if (newValue <= _end)
+ {
+ _value = newValue;
+ return true;
+ }
+ }
+ else
+ {
+ int newValue = _value - 1;
+
+ if (newValue >= _end)
+ {
+ _value = newValue;
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
++---+
+
+ This style is a tradeoff: on the gain side, the code is <even> simpler and
shorter, and the method names will, by design, be more consistent from one
class to the next.
+ The down side is that the names are very generic, and may in some cases, be
less descriptive than using annotated methods (<<<initializeValue()>>> and
<<<next()>>> are,
+ to some eyes, more descriptive).
+
+ You can, of course, mix and match, using specifically named render phase
methods in some cases, and annotated render phase methods in other cases.
Method Conflicts and Ordering
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Output.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Output.java?view=diff&rev=489232&r1=489231&r2=489232
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Output.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Output.java
Wed Dec 20 16:27:14 2006
@@ -12,30 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.integration.app1.components;
-
-import java.text.Format;
-
-import org.apache.tapestry.MarkupWriter;
-import org.apache.tapestry.annotations.BeginRender;
-import org.apache.tapestry.annotations.ComponentClass;
-import org.apache.tapestry.annotations.Parameter;
-
-/** component that formats a value and outputs it. */
[EMAIL PROTECTED]
-public class Output
-{
- @Parameter(required = true)
- private Object _value;
-
- @Parameter(required = true)
- private Format _format;
-
- @BeginRender
- void render(MarkupWriter writer)
- {
- String formatted = _format.format(_value);
-
- writer.write(formatted);
- }
-}
+package org.apache.tapestry.integration.app1.components;
+
+import java.text.Format;
+
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Parameter;
+
+/** component that formats a value and outputs it. */
[EMAIL PROTECTED]
+public class Output
+{
+ @Parameter(required = true)
+ private Object _value;
+
+ @Parameter(required = true)
+ private Format _format;
+
+ void beginRender(MarkupWriter writer)
+ {
+ String formatted = _format.format(_value);
+
+ writer.write(formatted);
+ }
+}
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Strong.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Strong.java?view=diff&rev=489232&r1=489231&r2=489232
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Strong.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Strong.java
Wed Dec 20 16:27:14 2006
@@ -12,25 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.integration.app1.components;
-
-import org.apache.tapestry.MarkupWriter;
-import org.apache.tapestry.annotations.AfterRender;
-import org.apache.tapestry.annotations.BeginRender;
-import org.apache.tapestry.annotations.ComponentClass;
-
[EMAIL PROTECTED]
-public class Strong
-{
- @BeginRender
- public void start(MarkupWriter writer)
- {
- writer.element("strong");
- }
-
- @AfterRender
- public void end(MarkupWriter writer)
- {
- writer.end();
- }
-}
+package org.apache.tapestry.integration.app1.components;
+
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.annotations.ComponentClass;
+
[EMAIL PROTECTED]
+public class Strong
+{
+ void beginRender(MarkupWriter writer)
+ {
+ writer.element("strong");
+ }
+
+ void afterRender(MarkupWriter writer)
+ {
+ writer.end();
+ }
+}
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java?view=diff&rev=489232&r1=489231&r2=489232
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java
Wed Dec 20 16:27:14 2006
@@ -14,10 +14,7 @@
package org.apache.tapestry.internal.services;
-import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
-
import java.lang.reflect.Modifier;
-import java.util.List;
import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.annotations.SetupRender;
@@ -29,9 +26,6 @@
import org.apache.tapestry.test.TapestryTestCase;
import org.testng.annotations.Test;
-/**
- *
- */
public class ComponentLifecycleMethodWorkerTest extends TapestryTestCase
{
@Test
@@ -40,9 +34,29 @@
ClassTransformation tf = newClassTransformation();
MutableComponentModel model = newMutableComponentModel();
- List<MethodSignature> sigs = newList();
+ MethodSignature sig = new MethodSignature("someRandomMethod");
+
+ train_findMethods(tf, sig);
+
+ train_getMethodAnnotation(tf, sig, SetupRender.class, null);
+
+ replay();
+
+ ComponentClassTransformWorker worker = new
ComponentLifecycleMethodWorker(
+ TransformConstants.SETUP_RENDER_SIGNATURE, SetupRender.class,
false);
+
+ worker.transform(tf, model);
+
+ verify();
+ }
+
+ @Test
+ public void added_lifecycle_method_is_ignored()
+ {
+ ClassTransformation tf = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
- train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
+ train_findMethods(tf, TransformConstants.SETUP_RENDER_SIGNATURE);
replay();
@@ -59,12 +73,13 @@
{
ClassTransformation tf = newClassTransformation();
MutableComponentModel model = newMutableComponentModel();
+ SetupRender annotation = newSetupRender();
- List<MethodSignature> sigs = newList();
+ MethodSignature sig = new MethodSignature("aMethod");
- sigs.add(new MethodSignature("aMethod"));
+ train_findMethods(tf, sig);
- train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
+ train_getMethodAnnotation(tf, sig, SetupRender.class, annotation);
train_isRootClass(model, false);
@@ -84,17 +99,51 @@
}
@Test
+ public void match_on_method_name()
+ {
+ ClassTransformation tf = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+
+ MethodSignature sig = new MethodSignature("setupRender");
+
+ train_findMethods(tf, sig);
+
+ train_isRootClass(model, false);
+
+ train_addMethod(
+ tf,
+ TransformConstants.SETUP_RENDER_SIGNATURE,
+ "{ super.setupRender($$); if ($2.isAborted()) return;
setupRender(); }");
+
+ replay();
+
+ ComponentClassTransformWorker worker = new
ComponentLifecycleMethodWorker(
+ TransformConstants.SETUP_RENDER_SIGNATURE, SetupRender.class,
false);
+
+ worker.transform(tf, model);
+
+ verify();
+ }
+
+ protected final SetupRender newSetupRender()
+ {
+ return newMock(SetupRender.class);
+ }
+
+ @Test
public void multiple_methods_reverse_order()
{
ClassTransformation tf = newClassTransformation();
MutableComponentModel model = newMutableComponentModel();
+ SetupRender annotation = newSetupRender();
- List<MethodSignature> sigs = newList();
+ MethodSignature siga = new MethodSignature("aMethod");
+ MethodSignature sigb = new MethodSignature("bMethod");
- sigs.add(new MethodSignature("aMethod"));
- sigs.add(new MethodSignature("bMethod"));
+ train_findMethods(tf, siga, sigb);
- train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
+ train_getMethodAnnotation(tf, siga, SetupRender.class, annotation);
+ train_getMethodAnnotation(tf, sigb, SetupRender.class, annotation);
train_isRootClass(model, false);
@@ -118,13 +167,16 @@
{
ClassTransformation tf = newClassTransformation();
MutableComponentModel model = newMutableComponentModel();
+ SetupRender annotation = newSetupRender();
+
+ MethodSignature siga = new MethodSignature("aMethod");
+ MethodSignature sigb = new MethodSignature("bMethod");
- List<MethodSignature> sigs = newList();
+ train_findMethods(tf, siga, sigb);
- sigs.add(new MethodSignature("aMethod"));
- sigs.add(new MethodSignature("bMethod"));
+ train_getMethodAnnotation(tf, siga, SetupRender.class, annotation);
+ train_getMethodAnnotation(tf, sigb, SetupRender.class, annotation);
- train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
train_isRootClass(model, true);
train_addMethod(tf, TransformConstants.SETUP_RENDER_SIGNATURE, "{
bMethod(); aMethod(); }");
@@ -145,14 +197,15 @@
{
ClassTransformation tf = newClassTransformation();
MutableComponentModel model = newMutableComponentModel();
+ SetupRender annotation = newSetupRender();
- train_isRootClass(model, true);
+ MethodSignature sig = new MethodSignature("aMethod");
- List<MethodSignature> sigs = newList();
+ train_findMethods(tf, sig);
- sigs.add(new MethodSignature("aMethod"));
+ train_getMethodAnnotation(tf, sig, SetupRender.class, annotation);
- train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
+ train_isRootClass(model, true);
train_addMethod(tf, TransformConstants.SETUP_RENDER_SIGNATURE, "{
aMethod(); }");
@@ -167,23 +220,19 @@
}
- protected final void train_isRootClass(MutableComponentModel model,
boolean isRootClass)
- {
- expect(model.isRootClass()).andReturn(isRootClass);
- }
-
@Test
public void method_with_markup_writer_parameter()
{
ClassTransformation tf = newClassTransformation();
MutableComponentModel model = newMutableComponentModel();
+ SetupRender annotation = newSetupRender();
- List<MethodSignature> sigs = newList();
+ MethodSignature sig = new MethodSignature(Modifier.PUBLIC, "void",
"aMethod", new String[]
+ { MarkupWriter.class.getName() }, null);
- sigs.add(new MethodSignature(Modifier.PUBLIC, "void", "aMethod", new
String[]
- { MarkupWriter.class.getName() }, null));
+ train_findMethods(tf, sig);
- train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
+ train_getMethodAnnotation(tf, sig, SetupRender.class, annotation);
train_isRootClass(model, false);
@@ -208,12 +257,14 @@
{
ClassTransformation tf = newClassTransformation();
MutableComponentModel model = newMutableComponentModel();
+ SetupRender annotation = newSetupRender();
- List<MethodSignature> sigs = newList();
+ MethodSignature sig = new MethodSignature(Modifier.PROTECTED,
"boolean", "aMethod", null,
+ null);
- sigs.add(new MethodSignature(Modifier.PROTECTED, "boolean", "aMethod",
null, null));
+ train_findMethods(tf, sig);
- train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
+ train_getMethodAnnotation(tf, sig, SetupRender.class, annotation);
train_getClassName(tf, "biff.Baz");
@@ -243,15 +294,20 @@
{
ClassTransformation tf = newClassTransformation();
MutableComponentModel model = newMutableComponentModel();
+ SetupRender annotation = newSetupRender();
+
+ MethodSignature siga = new MethodSignature(Modifier.PROTECTED,
"boolean", "aMethod", null,
+ null);
+ MethodSignature sigb = new MethodSignature(Modifier.PUBLIC, "void",
"bMethod", new String[]
+ { MarkupWriter.class.getName() }, null);
- List<MethodSignature> sigs = newList();
+ train_findMethods(tf, siga, sigb);
- sigs.add(new MethodSignature(Modifier.PROTECTED, "boolean", "aMethod",
null, null));
- sigs.add(new MethodSignature(Modifier.PUBLIC, "void", "bMethod", new
String[]
- { MarkupWriter.class.getName() }, null));
+ train_getMethodAnnotation(tf, siga, SetupRender.class, annotation);
+ train_getMethodAnnotation(tf, sigb, SetupRender.class, annotation);
- train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
train_isRootClass(model, false);
+
train_getClassName(tf, "foo.Bar");
train_addMethod(
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java?view=diff&rev=489232&r1=489231&r2=489232
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
Wed Dec 20 16:27:14 2006
@@ -54,6 +54,7 @@
import org.apache.tapestry.runtime.Component;
import org.apache.tapestry.runtime.ComponentResourcesAware;
import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.MethodFilter;
import org.apache.tapestry.services.MethodSignature;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@@ -818,6 +819,44 @@
ClassTransformation ct =
createClassTransformation(AnnotatedPage.class, log);
List<MethodSignature> l =
ct.findMethodsWithAnnotation(SetupRender.class);
+
+ // Check order
+
+ assertEquals(l.size(), 2);
+ assertEquals(l.get(0).toString(), "void beforeRender()");
+ assertEquals(l.get(1).toString(), "boolean
earlyRender(org.apache.tapestry.MarkupWriter)");
+
+ // Check up on cacheing
+
+ assertEquals(ct.findMethodsWithAnnotation(SetupRender.class), l);
+
+ // Check up on no match.
+
+ assertTrue(ct.findFieldsWithAnnotation(Deprecated.class).isEmpty());
+
+ verify();
+ }
+
+ @Test
+ public void find_methods_using_filter() throws Exception
+ {
+ Log log = newLog();
+
+ replay();
+
+ final ClassTransformation ct =
createClassTransformation(AnnotatedPage.class, log);
+
+ // Duplicates, somewhat less efficiently, the logic in
find_methods_with_annotation().
+
+ MethodFilter filter = new MethodFilter()
+ {
+ public boolean accept(MethodSignature signature)
+ {
+ return ct.getMethodAnnotation(signature, SetupRender.class) !=
null;
+ }
+ };
+
+ List<MethodSignature> l = ct.findMethods(filter);
// Check order