Return-Path: Delivered-To: apmail-tapestry-commits-archive@minotaur.apache.org Received: (qmail 48300 invoked from network); 19 Feb 2010 18:54:17 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 19 Feb 2010 18:54:17 -0000 Received: (qmail 94775 invoked by uid 500); 19 Feb 2010 18:54:17 -0000 Delivered-To: apmail-tapestry-commits-archive@tapestry.apache.org Received: (qmail 94735 invoked by uid 500); 19 Feb 2010 18:54:17 -0000 Mailing-List: contact commits-help@tapestry.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@tapestry.apache.org Delivered-To: mailing list commits@tapestry.apache.org Received: (qmail 94726 invoked by uid 99); 19 Feb 2010 18:54:17 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 19 Feb 2010 18:54:17 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 19 Feb 2010 18:54:16 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 351AF2388ABC; Fri, 19 Feb 2010 18:53:56 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r911922 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/internal/transform/ main/resources/org/apache/tapestry5/internal/transform/ test/app1/ test/java/org/apache/tapestry5/integration/app1/ test/java/org/a... Date: Fri, 19 Feb 2010 18:53:56 -0000 To: commits@tapestry.apache.org From: hlship@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100219185356.351AF2388ABC@eris.apache.org> Author: hlship Date: Fri Feb 19 18:53:55 2010 New Revision: 911922 URL: http://svn.apache.org/viewvc?rev=911922&view=rev Log: Re-implement CachedWorker using TransformMethod APIs Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CacheTests.java (with props) tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ParamsMethodWithCached.java (with props) tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/VoidMethodWithCached.java (with props) Removed: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/transform/CachedWorkerTest.java Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/CachedWorker.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/TransformMessages.java tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/transform/TransformStrings.properties tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Index.tml tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/CachedWorker.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/CachedWorker.java?rev=911922&r1=911921&r2=911922&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/CachedWorker.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/CachedWorker.java Fri Feb 19 18:53:55 2010 @@ -1,10 +1,10 @@ -// Copyright 2008 The Apache Software Foundation +// Copyright 2008, 2010 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 +// 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, @@ -14,15 +14,25 @@ package org.apache.tapestry5.internal.transform; +import java.lang.reflect.Modifier; +import java.util.List; + import org.apache.tapestry5.Binding; import org.apache.tapestry5.BindingConstants; +import org.apache.tapestry5.ComponentResources; import org.apache.tapestry5.annotations.Cached; -import org.apache.tapestry5.ioc.util.BodyBuilder; +import org.apache.tapestry5.internal.TapestryInternalUtils; import org.apache.tapestry5.model.MutableComponentModel; -import org.apache.tapestry5.services.*; - -import static java.lang.reflect.Modifier.PRIVATE; -import java.util.List; +import org.apache.tapestry5.runtime.PageLifecycleAdapter; +import org.apache.tapestry5.services.BindingSource; +import org.apache.tapestry5.services.ClassTransformation; +import org.apache.tapestry5.services.ComponentClassTransformWorker; +import org.apache.tapestry5.services.ComponentMethodAdvice; +import org.apache.tapestry5.services.ComponentMethodInvocation; +import org.apache.tapestry5.services.FieldAccess; +import org.apache.tapestry5.services.TransformField; +import org.apache.tapestry5.services.TransformMethod; +import org.apache.tapestry5.services.TransformMethodSignature; /** * Caches method return values for methods annotated with {@link Cached}. @@ -31,6 +41,83 @@ { private final BindingSource bindingSource; + /** + * Manages a cache value as the result of invoking a no-arguments method. + */ + public interface MethodResultCache + { + /** Returns true if the cache contains a cached value. May also check to see if the cached value is valid. */ + boolean isCached(); + + /** Stores a new cached value for later reference. */ + void set(Object cachedValue); + + /** Returns the previously cached value, if any. */ + Object get(); + + /** Resets the cache, discarding the cached value. */ + void reset(); + } + + /** + * Handles the watching of a binding (usually a property or property expression), invalidating the + * cache early if the watched binding's value changes. + */ + private class SimpleMethodResultCache implements MethodResultCache + { + private boolean cached; + private Object cachedValue; + + public void set(Object cachedValue) + { + cached = true; + this.cachedValue = cachedValue; + } + + public void reset() + { + cached = false; + cachedValue = null; + } + + public boolean isCached() + { + return cached; + } + + public Object get() + { + return cachedValue; + } + } + + private class WatchedBindingMethodResultCache extends SimpleMethodResultCache + { + private final Binding binding; + + private Object cachedBindingValue; + + public WatchedBindingMethodResultCache(Binding binding) + { + this.binding = binding; + } + + @Override + public boolean isCached() + { + Object currentBindingValue = binding.get(); + + if (!TapestryInternalUtils.isEqual(cachedBindingValue, currentBindingValue)) + { + reset(); + + cachedBindingValue = currentBindingValue; + } + + return super.isCached(); + } + } + public CachedWorker(BindingSource bindingSource) { this.bindingSource = bindingSource; @@ -38,103 +125,108 @@ public void transform(ClassTransformation transformation, MutableComponentModel model) { - List methods = transformation.findMethodsWithAnnotation(Cached.class); - if (methods.isEmpty()) - return; + List methods = transformation.matchMethodsWithAnnotation(Cached.class); - for (TransformMethodSignature method : methods) + for (TransformMethod method : methods) { - if (method.getReturnType().equals("void")) - throw new IllegalArgumentException(TransformMessages.cachedMethodMustHaveReturnValue(method)); + validateMethod(method); - if (method.getParameterTypes().length != 0) - throw new IllegalArgumentException(TransformMessages.cachedMethodsHaveNoParameters(method)); + adviseMethod(transformation, method); + } + } - String propertyName = method.getMethodName(); + private void adviseMethod(ClassTransformation transformation, TransformMethod method) + { + FieldAccess resultCacheAccess = createMethodResultCacheField(transformation, method); - // add a property to store whether or not the method has been called - String fieldName = transformation.addField(PRIVATE, method.getReturnType(), propertyName); - String calledField = transformation.addField(PRIVATE, "boolean", fieldName + "$called"); + Cached annotation = method.getAnnotation(Cached.class); - Cached once = transformation.getMethodAnnotation(method, Cached.class); - String bindingField = null; - String bindingValueField = null; - boolean watching = once.watch().length() > 0; + ComponentMethodAdvice advice = createAdvice(resultCacheAccess, annotation.watch()); - if (watching) + method.addAdvice(advice); + } + + private FieldAccess createMethodResultCacheField(ClassTransformation transformation, TransformMethod method) + { + TransformField resultCacheField = transformation.createField(Modifier.PRIVATE, MethodResultCache.class + .getName(), "cache$" + method.getName()); + + return resultCacheField.getAccess(); + } + + private ComponentMethodAdvice createAdvice(final FieldAccess resultCacheAccess, final String watch) + { + ComponentMethodAdvice advice = new ComponentMethodAdvice() + { + public void advise(ComponentMethodInvocation invocation) { - // add fields to store the binding and the value - bindingField = transformation.addField(PRIVATE, Binding.class.getCanonicalName(), - fieldName + "$binding"); - bindingValueField = transformation.addField(PRIVATE, "java.lang.Object", fieldName + "$bindingValue"); - - String bindingSourceField = transformation.addInjectedField(BindingSource.class, - fieldName + "$bindingsource", - bindingSource); - - String body = String.format("%s = %s.newBinding(\"Watch expression\", %s, \"%s\", \"%s\");", - bindingField, - bindingSourceField, - transformation.getResourcesFieldName(), - BindingConstants.PROP, - once.watch()); + MethodResultCache cache = getOrCreateCache(invocation); - transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, body); + if (cache.isCached()) + { + invocation.overrideResult(cache.get()); + return; + } + + invocation.proceed(); + + invocation.rethrow(); + + cache.set(invocation.getResult()); } - BodyBuilder b = new BodyBuilder(); + private MethodResultCache getOrCreateCache(ComponentMethodInvocation invocation) + { + MethodResultCache cache = (MethodResultCache) resultCacheAccess.read(invocation.getInstance()); - // on cleanup, reset the field values - b.begin(); + if (cache == null) + cache = createAndStoreCache(invocation); - if (!TransformUtils.isPrimitive(method.getReturnType())) - b.addln("%s = null;", fieldName); - b.addln("%s = false;", calledField); - - if (watching) - b.addln("%s = null;", bindingValueField); - - b.end(); - - // TAPESTRY-2338: Cleanup at page detach, not render cleanup. In an Ajax request, the rendering - // objects may reference properties of components that don't render and so won't execute the - // PostCleanupRender phase. - - transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE, b.toString()); - - // prefix the existing method to cache the result - b.clear(); - b.begin(); - - // if it has been called and watch is set and the old value is the same as the new value then return - // get the old value and cache it - /* NOTE: evaluates the binding twice when checking the new value. - * this is probably not a problem because in most cases properties - * that are being watched are not expensive operations. plus, we - * never guaranteed that it would be called exactly once when - * watching. - */ - if (watching) + return cache; + } + + private MethodResultCache createAndStoreCache(ComponentMethodInvocation invocation) { - b.addln("if (%s && %s == %s.get()) return %s;", - calledField, bindingValueField, bindingField, fieldName); - b.addln("%s = %s.get();", bindingValueField, bindingField); + final MethodResultCache cache = createMethodResultCache(invocation.getComponentResources()); + + invocation.getComponentResources().addPageLifecycleListener(new PageLifecycleAdapter() + { + @Override + public void containingPageDidDetach() + { + cache.reset(); + } + }); + + resultCacheAccess.write(invocation.getInstance(), cache); + + return cache; } - else + + private SimpleMethodResultCache createMethodResultCache(ComponentResources resources) { - b.addln("if (%s) return %s;", calledField, fieldName); + if (watch.equals("")) + return new SimpleMethodResultCache(); + + Binding binding = bindingSource.newBinding("@Cached watch", resources, BindingConstants.PROP, watch); + + return new WatchedBindingMethodResultCache(binding); } + }; - b.addln("%s = true;", calledField); - b.end(); - transformation.prefixMethod(method, b.toString()); - - // cache the return value - b.clear(); - b.begin(); - b.addln("%s = $_;", fieldName); - b.end(); - transformation.extendExistingMethod(method, b.toString()); - } + return advice; + } + + private void validateMethod(TransformMethod method) + { + TransformMethodSignature signature = method.getSignature(); + + if (signature.getReturnType().equals("void")) + throw new IllegalArgumentException(String.format( + "Method %s may not be used with @Cached because it returns void.", method.getMethodIdentifier())); + + if (signature.getParameterTypes().length != 0) + throw new IllegalArgumentException(String.format( + "Method %s may not be used with @Cached because it has parameters.", method.getMethodIdentifier())); } } Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/TransformMessages.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/TransformMessages.java?rev=911922&r1=911921&r2=911922&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/TransformMessages.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/TransformMessages.java Fri Feb 19 18:53:55 2010 @@ -18,12 +18,12 @@ import org.apache.tapestry5.ComponentResources; import org.apache.tapestry5.annotations.MixinClasses; -import org.apache.tapestry5.internal.structure.InternalComponentResourcesImpl; import org.apache.tapestry5.ioc.Messages; import org.apache.tapestry5.ioc.internal.util.CollectionFactory; import org.apache.tapestry5.ioc.internal.util.InternalUtils; import org.apache.tapestry5.ioc.internal.util.MessagesImpl; import org.apache.tapestry5.services.TransformField; +import org.apache.tapestry5.services.TransformMethod; import org.apache.tapestry5.services.TransformMethodSignature; class TransformMessages @@ -35,16 +35,6 @@ return MESSAGES.format("field-injection-error", className, fieldName, cause); } - static String cachedMethodMustHaveReturnValue(TransformMethodSignature method) - { - return MESSAGES.format("cached-no-return-value", method); - } - - static String cachedMethodsHaveNoParameters(TransformMethodSignature method) - { - return MESSAGES.format("cached-no-parameters", method); - } - static String illegalNumberOfPageActivationContextHandlers(List fields) { List names = CollectionFactory.newList(); Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/transform/TransformStrings.properties URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/transform/TransformStrings.properties?rev=911922&r1=911921&r2=911922&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/transform/TransformStrings.properties (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/transform/TransformStrings.properties Fri Feb 19 18:53:55 2010 @@ -13,8 +13,6 @@ # limitations under the License. field-injection-error=Error obtaining injected value for field %s.%s: %s -cached-no-return-value=@Cached may only be used with methods that return values: %s -cached-no-parameters=@Cached cannot be used with methods that accept parameters: %s illegal-number-of-page-activation-context-handlers=Illegal number of fields annotated with @PageActivationContext: %s. Only one field is allowed. bad-mixin-constraint-length=%d mixins defined via @MixinClasses on field '%s', but %d ordering constraints \ specified (expected 0 or %1$d). Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Index.tml URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Index.tml?rev=911922&r1=911921&r2=911922&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Index.tml (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Index.tml Fri Feb 19 18:53:55 2010 @@ -132,6 +132,16 @@ PageReset Annotation Failure -- error when @PageReset is on a method with parameters + +
  • + @Cached on void method + -- error when @Cached is used on a method that returns void +
  • + +
  • + @Cached on method with parameters + -- error when @cached is used on a method that has parameters +
  • Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CacheTests.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CacheTests.java?rev=911922&view=auto ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CacheTests.java (added) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CacheTests.java Fri Feb 19 18:53:55 2010 @@ -0,0 +1,70 @@ +// Copyright 2010 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.tapestry5.integration.app1; + +import org.apache.tapestry5.integration.TapestryCoreTestCase; +import org.testng.annotations.Test; + +public class CacheTests extends TapestryCoreTestCase +{ + /** + * TAPESTRY-2338 + */ + @Test + public void cached_properties_cleared_at_end_of_request() + { + clickThru("Clean Cache Demo"); + + String time1_1 = getText("time1"); + String time1_2 = getText("time1"); + + // Don't know what they are but they should be the same. + + assertEquals(time1_2, time1_1); + + click("link=update"); + + sleep(250); + + String time2_1 = getText("time1"); + String time2_2 = getText("time1"); + + // Check that @Cache is still working + + assertEquals(time2_2, time2_1); + + assertFalse(time2_1.equals(time1_1), + "After update the nanoseconds time did not change, meaning @Cache was broken."); + } + + @Test + public void void_method_is_error_with_cached() + { + clickThru("@Cached on void method"); + + assertTextPresent("Method org.apache.tapestry5.integration.app1.pages.VoidMethodWithCached.invalidMethod()", + "may not be used with @Cached because it returns void."); + } + + @Test + public void parameters_not_allowed_with_cached_method() + { + clickThru("@Cached on method with parameters"); + + assertTextPresent( + "Method org.apache.tapestry5.integration.app1.pages.ParamsMethodWithCached.invalidMethod(java.lang.String)", + "may not be used with @Cached because it has parameters."); + } +} Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CacheTests.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java?rev=911922&r1=911921&r2=911922&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java Fri Feb 19 18:53:55 2010 @@ -813,35 +813,6 @@ assertTextPresent("Class org.apache.tapestry5.integration.app1.pages.Datum contains field(s) (_value) that are not private. You should change these fields to private, and add accessor methods if needed."); } - /** - * TAPESTRY-2338 - */ - @Test - public void cached_properties_cleared_at_end_of_request() - { - clickThru("Clean Cache Demo"); - - String time1_1 = getText("time1"); - String time1_2 = getText("time1"); - - // Don't know what they are but they should be the same. - - assertEquals(time1_2, time1_1); - - click("link=update"); - - sleep(250); - - String time2_1 = getText("time1"); - String time2_2 = getText("time1"); - - // Check that @Cache is still working - - assertEquals(time2_2, time2_1); - - assertFalse(time2_1.equals(time1_1), - "After update the nanoseconds time did not change, meaning @Cache was broken."); - } @Test public void method_advice() Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ParamsMethodWithCached.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ParamsMethodWithCached.java?rev=911922&view=auto ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ParamsMethodWithCached.java (added) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ParamsMethodWithCached.java Fri Feb 19 18:53:55 2010 @@ -0,0 +1,26 @@ +// Copyright 2010 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.tapestry5.integration.app1.pages; + +import org.apache.tapestry5.annotations.Cached; + +public class ParamsMethodWithCached +{ + @Cached + public int invalidMethod(String parameter) + { + return 0; + } +} Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ParamsMethodWithCached.java ------------------------------------------------------------------------------ svn:eol-style = native Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/VoidMethodWithCached.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/VoidMethodWithCached.java?rev=911922&view=auto ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/VoidMethodWithCached.java (added) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/VoidMethodWithCached.java Fri Feb 19 18:53:55 2010 @@ -0,0 +1,25 @@ +// Copyright 2010 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.tapestry5.integration.app1.pages; + +import org.apache.tapestry5.annotations.Cached; + +public class VoidMethodWithCached +{ + @Cached + public void invalidMethod() + { + } +} Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/VoidMethodWithCached.java ------------------------------------------------------------------------------ svn:eol-style = native