Repository: tapestry-5 Updated Branches: refs/heads/master b452c6fcd -> 737ebd64c
TAP5-1213 - Access generic type for bound parameters Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/daa27902 Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/daa27902 Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/daa27902 Branch: refs/heads/master Commit: daa279024e6b66c6c6b2c77e279f42fee50c8dc5 Parents: b452c6f Author: uklance <[email protected]> Authored: Sat May 17 18:48:27 2014 +0100 Committer: uklance <[email protected]> Committed: Mon May 19 21:34:49 2014 +0100 ---------------------------------------------------------------------- .../main/java/org/apache/tapestry5/Binding.java | 9 ++++ .../apache/tapestry5/ComponentResources.java | 13 +++++ .../org/apache/tapestry5/PropertyConduit.java | 13 +++++ .../internal/TapestryInternalUtils.java | 6 +++ .../internal/bindings/AbstractBinding.java | 10 ++++ .../internal/bindings/PropBinding.java | 11 ++++ .../CoercingPropertyConduitWrapper.java | 6 +++ .../services/LiteralPropertyConduit.java | 6 +++ .../services/PropertyConduitSourceImpl.java | 57 ++++++++++++++++++-- .../InternalComponentResourcesImpl.java | 9 ++++ .../integration/app1/CoreBehaviorsTests.java | 16 ++++++ .../app1/components/GenericTypeDisplay.java | 45 ++++++++++++++++ .../integration/app1/pages/EmptyGrid.java | 6 +++ .../integration/app1/pages/GenericTypeDemo.java | 33 ++++++++++++ .../tapestry5/integration/app1/pages/Index.java | 4 +- .../services/PropertyConduitSourceImplTest.java | 27 ++++++++++ .../integration/app1/pages/GenericTypeDemo.tml | 12 +++++ 17 files changed, 278 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/main/java/org/apache/tapestry5/Binding.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/Binding.java b/tapestry-core/src/main/java/org/apache/tapestry5/Binding.java index 8a99914..711c748 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/Binding.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/Binding.java @@ -14,6 +14,8 @@ package org.apache.tapestry5; +import java.lang.reflect.Type; + import org.apache.tapestry5.ioc.AnnotationProvider; /** @@ -53,4 +55,11 @@ public interface Binding extends AnnotationProvider * bound. */ Class getBindingType(); + + /** + * Returns the generic type of the binding, either the generic type of resource exposed by the binding, or the + * generic type of the property bound. + * @since 5.4 + */ + Type getBindingGenericType(); } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/main/java/org/apache/tapestry5/ComponentResources.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/ComponentResources.java b/tapestry-core/src/main/java/org/apache/tapestry5/ComponentResources.java index 137c43d..5c51903 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/ComponentResources.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/ComponentResources.java @@ -23,6 +23,7 @@ import org.apache.tapestry5.runtime.PageLifecycleCallbackHub; import org.apache.tapestry5.runtime.PageLifecycleListener; import java.lang.annotation.Annotation; +import java.lang.reflect.Type; import java.util.List; /** @@ -128,6 +129,18 @@ public interface ComponentResources extends ComponentResourcesCommon * @see Binding#getBindingType() */ Class getBoundType(String parameterName); + + + /** + * Returns the generic type of the bound parameter, or null if the parameter is not bound. This is useful + * for when the parameter is bound to a generic property (eg java.util.List) to determine the element type. + * + * @param parameterName + * used to select the parameter (case is ignored) + * @return the generic type of the bound parameter, or null if the parameter is not bound + * @see Binding#getBindingGenericType() + */ + Type getBoundGenericType(String parameterName); /** * Returns an annotation provider, used to obtain annotations related to the parameter. http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java index 3dbb0c0..b28293a 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java @@ -14,6 +14,8 @@ package org.apache.tapestry5; +import java.lang.reflect.Type; + import org.apache.tapestry5.ioc.AnnotationProvider; /** @@ -42,4 +44,15 @@ public interface PropertyConduit extends AnnotationProvider * Returns the type of the property read or updated by the conduit. */ Class getPropertyType(); + + /** + * Returns a Type object that represents the declared type for the property. + * If the Type is a parameterized type, the Type object returned must accurately + * reflect the actual type parameters used in the source code. If the type of the + * underlying property is a type variable or a parameterized type, it is created. + * Otherwise, it is resolved. + * + * @since 5.4 + */ + Type getPropertyGenericType(); } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java index 7c6e8b0..45da70b 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java @@ -32,6 +32,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.ref.Reference; +import java.lang.reflect.Type; import java.util.List; import java.util.Map; import java.util.regex.Pattern; @@ -491,6 +492,11 @@ public class TapestryInternalUtils return conduit.getPropertyType(); } + public Type getPropertyGenericType() + { + return conduit.getPropertyGenericType(); + } + public Object get(Object instance) { return conduit.get(instance); http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java index a2478b5..12885e1 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java @@ -20,6 +20,7 @@ import org.apache.tapestry5.ioc.Location; import org.apache.tapestry5.ioc.internal.util.TapestryException; import java.lang.annotation.Annotation; +import java.lang.reflect.Type; /** * Abstract base class for bindings. Assumes that the binding is read only and invariant. Subclasses must provide an @@ -62,6 +63,15 @@ public abstract class AbstractBinding extends BaseLocatable implements Binding { return get().getClass(); } + + /** + * Passes straight through to {@link AbstractBinding#getBindingType()}. Subclasses may override this method to + * return the generic type if it is available + */ + public Type getBindingGenericType() + { + return getBindingType(); + } /** * Always returns null. Bindings that provide access to a method or field will override this method to return the http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java index e7802bc..55ea9d8 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java @@ -21,6 +21,7 @@ import org.apache.tapestry5.ioc.Location; import org.apache.tapestry5.ioc.internal.util.TapestryException; import java.lang.annotation.Annotation; +import java.lang.reflect.Type; /** * Base class for bindings created by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}. A subclass @@ -100,6 +101,16 @@ public class PropBinding extends AbstractBinding implements InternalPropBinding { return conduit.getPropertyType(); } + + /** + * Get the generic type from the underlying field or getter. + * @see PropertyConduit#getPropertyGenericType() + */ + @Override + public Type getBindingGenericType() + { + return conduit.getPropertyGenericType(); + } @Override public <T extends Annotation> T getAnnotation(Class<T> annotationClass) http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java index e1135bf..158d4a4 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java @@ -18,6 +18,7 @@ import org.apache.tapestry5.PropertyConduit; import org.apache.tapestry5.ioc.services.TypeCoercer; import java.lang.annotation.Annotation; +import java.lang.reflect.Type; public class CoercingPropertyConduitWrapper implements PropertyConduit { @@ -45,6 +46,11 @@ public class CoercingPropertyConduitWrapper implements PropertyConduit { return conduit.getPropertyType(); } + + public Type getPropertyGenericType() + { + return conduit.getPropertyGenericType(); + } @SuppressWarnings("unchecked") public void set(Object instance, Object value) http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java index bc2eb12..1fffd4f 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java @@ -15,6 +15,7 @@ package org.apache.tapestry5.internal.services; import java.lang.annotation.Annotation; +import java.lang.reflect.Type; import org.apache.tapestry5.internal.InternalPropertyConduit; import org.apache.tapestry5.ioc.AnnotationProvider; @@ -59,6 +60,11 @@ public class LiteralPropertyConduit extends PropertyConduitDelegate implements I { return propertyType; } + + public Type getPropertyGenericType() + { + return propertyType; + } public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java index 5f41fb1..6dab120 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java @@ -63,9 +63,12 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class, "getPropertyType"); + private static final MethodDescription GET_PROPERTY_GENERIC_TYPE = getMethodDescription(PropertyConduit.class, + "getPropertyGenericType"); + private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class, "getPropertyName"); - + private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class, "getAnnotation", Class.class); @@ -245,6 +248,8 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource private Class conduitPropertyType; + private Type conduitPropertyGenericType; + private String conduitPropertyName; private AnnotationProvider annotationProvider = nullAnnotationProvider; @@ -302,6 +307,16 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource } }); + final PlasticField propertyGenericTypeField = plasticClass.introduceField(Type.class, "propertyGenericType").inject( + conduitPropertyGenericType); + + plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_GENERIC_TYPE, new InstructionBuilderCallback() + { + public void doBuild(InstructionBuilder builder) + { + builder.loadThis().getField(propertyGenericTypeField).returnResult(); + } + }); } /** @@ -424,6 +439,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource implementNoOpSetter(); conduitPropertyType = IntegerRange.class; + conduitPropertyGenericType = IntegerRange.class; return; @@ -433,7 +449,8 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource implementNoOpSetter(); conduitPropertyType = List.class; - + conduitPropertyGenericType = List.class; + return; case MAP: @@ -441,6 +458,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource implementNoOpSetter(); conduitPropertyType = Map.class; + conduitPropertyGenericType = Map.class; return; @@ -450,6 +468,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource implementNoOpSetter(); conduitPropertyType = boolean.class; + conduitPropertyGenericType = boolean.class; return; @@ -466,6 +485,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource conduitPropertyName = term.description; conduitPropertyType = term.genericType; + conduitPropertyGenericType = term.genericType; annotationProvider = term.annotationProvider; plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback() @@ -491,15 +511,39 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName); - conduitPropertyType = adapter.getType(); conduitPropertyName = propertyName; + conduitPropertyType = adapter.getType(); + conduitPropertyGenericType = getGenericType(adapter); annotationProvider = adapter; implementGetter(adapter); implementSetter(adapter); } - private void implementSetter(PropertyAdapter adapter) + private Type getGenericType(PropertyAdapter adapter) + { + Type genericType = null; + if (adapter.getField() != null) + { + genericType = adapter.getField().getGenericType(); + } + else if (adapter.getReadMethod() != null) + { + genericType = adapter.getReadMethod().getGenericReturnType(); + } + else if (adapter.getWriteMethod() != null) + { + genericType = adapter.getWriteMethod().getGenericParameterTypes()[0]; + } + else + { + throw new RuntimeException("Could not find accessor for property " + adapter.getName()); + } + + return genericType == null ? adapter.getType() : genericType; + } + + private void implementSetter(PropertyAdapter adapter) { if (adapter.getWriteMethod() != null) { @@ -1439,6 +1483,11 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource { return rootClass; } + + public Type getPropertyGenericType() + { + return rootClass; + } public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java index 39defda..5e0e440 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java @@ -41,6 +41,7 @@ import org.apache.tapestry5.services.pageload.ComponentResourceSelector; import org.slf4j.Logger; import java.lang.annotation.Annotation; +import java.lang.reflect.Type; import java.util.List; import java.util.Locale; import java.util.Map; @@ -344,6 +345,14 @@ public class InternalComponentResourcesImpl extends LockSupport implements Inter return binding == null ? null : binding.getBindingType(); } + + public Type getBoundGenericType(String parameterName) + { + Binding binding = getBinding(parameterName); + + return binding == null ? null : binding.getBindingGenericType(); + } + public Binding getBinding(String parameterName) { http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java index 2179b98..afdc002 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java @@ -1720,4 +1720,20 @@ public class CoreBehaviorsTests extends App1TestCase assertTextPresent("This page throws an exception"); } + + @Test + public void bound_generic_types() + { + openLinks("Generic bound type demo"); + + assertTextPresent("clientId=one,type=java.util.Map,genericType=java.util.Map<java.lang.String, java.lang.String>"); + assertTextPresent("clientId=two,type=java.lang.String,genericType=class java.lang.String"); + assertTextPresent("clientId=three,type=java.util.Set,genericType=java.util.Set<java.lang.Long>"); + assertTextPresent("clientId=four,type=java.util.List,genericType=java.util.List<java.util.List<java.util.Date>>"); + assertTextPresent("clientId=five,type=java.util.List,genericType=interface java.util.List"); + assertTextPresent("clientId=six,type=java.util.Date,genericType=class java.util.Date"); + assertTextPresent("clientId=seven,type=java.util.List,genericType=interface java.util.List"); + assertTextPresent("clientId=eight,type=java.util.Map,genericType=interface java.util.Map"); + assertTextPresent("clientId=nine,type=java.lang.String,genericType=class java.lang.String"); + } } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java new file mode 100644 index 0000000..ab95807 --- /dev/null +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java @@ -0,0 +1,45 @@ +// Copyright 2006-2014 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.components; + +import java.lang.reflect.Type; + +import org.apache.tapestry5.BindingConstants; +import org.apache.tapestry5.ComponentResources; +import org.apache.tapestry5.MarkupWriter; +import org.apache.tapestry5.annotations.Parameter; +import org.apache.tapestry5.ioc.annotations.Inject; + +/** + * Outputs the type and genericType of the 'value' parameter in a div + */ +public class GenericTypeDisplay { + @Inject + private ComponentResources resources; + + @Parameter(required=true, defaultPrefix=BindingConstants.LITERAL) + private String clientId; + + @Parameter(required=true) + private Object value; + + void afterRender(MarkupWriter writer) { + writer.element("div", "id", clientId); + Class<?> type = resources.getBoundType("value"); + Type genericType = resources.getBoundGenericType("value"); + String text = String.format("clientId=%s,type=%s,genericType=%s", clientId, type.getName(), genericType.toString()); + writer.write(text); + writer.end(); + } +} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/EmptyGrid.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/EmptyGrid.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/EmptyGrid.java index 522fa6a..a89c039 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/EmptyGrid.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/EmptyGrid.java @@ -15,6 +15,7 @@ package org.apache.tapestry5.integration.app1.pages; import java.lang.annotation.Annotation; +import java.lang.reflect.Type; import java.util.Collections; import java.util.List; import java.util.Random; @@ -66,6 +67,11 @@ public class EmptyGrid { return Long.class; } + + public Type getPropertyGenericType() + { + return Long.class; + } public Object get(Object instance) { http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java new file mode 100644 index 0000000..80bf40a --- /dev/null +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java @@ -0,0 +1,33 @@ +package org.apache.tapestry5.integration.app1.pages; + +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.annotations.SetupRender; + +public class GenericTypeDemo { + private Set<Long> setOfLongs; + + @Property + private Map<String, String> mapOfStrings; + + public List<List<Date>> getListOfListOfDates() { + List<Date> dates = Arrays.asList(new Date(Long.MIN_VALUE), new Date(0), new Date(Long.MAX_VALUE)); + return Arrays.asList(dates); + } + + public void setSetOfLongs(Set<Long> setOfLongs) { + this.setOfLongs = setOfLongs; + } + + @SetupRender + void setupRender() { + mapOfStrings = new HashMap<String,String>(); + mapOfStrings.put("foo", "bar"); + } +} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java index 009a97d..99f2a16 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java @@ -566,7 +566,9 @@ public class Index new Item("nested/PageThatThrowsException", "Reload on nested page", "Tests a page reload from a nested page's exception report"), - new Item("inplacegridinloopdemo", "In-Place Grid in a Loop Demo", "In-place grid in a loop") + new Item("inplacegridinloopdemo", "In-Place Grid in a Loop Demo", "In-place grid in a loop"), + + new Item("GenericTypeDemo", "Generic bound type demo", "Tests that generic type info is available for generic bindings") ); http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java index 1f550cd..5c9f88a 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java @@ -29,6 +29,8 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.Map; @@ -161,6 +163,31 @@ public class PropertyConduitSourceImplTest extends InternalBaseTestCase smart.set(bean, "Howard"); } + static class GenericBean { + public List<Date> dates; + public List<GenericBean> genericBeans; + + public List<Long> getLongs() { + return Collections.emptyList(); + } + + public void setMap(Map<String, Integer> map) { + } + } + + @Test + public void generic_types_are_determined() + { + PropertyConduit datesConduit = source.create(GenericBean.class, "dates"); + PropertyConduit longsConduit = source.create(GenericBean.class, "longs"); + PropertyConduit nestedDatesConduit = source.create(GenericBean.class, "genericBeans.get(0).dates"); + PropertyConduit mapConduit = source.create(GenericBean.class, "map"); + assertEquals(datesConduit.getPropertyGenericType().toString(), "java.util.List<java.util.Date>"); + assertEquals(longsConduit.getPropertyGenericType().toString(), "java.util.List<java.lang.Long>"); + assertEquals(nestedDatesConduit.getPropertyGenericType().toString(), "java.util.List<java.util.Date>"); + assertEquals(mapConduit.getPropertyGenericType().toString(), "java.util.Map<java.lang.String, java.lang.Integer>"); + } + @Test public void method_names_are_matched_caselessly() { http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/daa27902/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.tml ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.tml b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.tml new file mode 100644 index 0000000..c9f4b78 --- /dev/null +++ b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.tml @@ -0,0 +1,12 @@ +<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> + <h1>Generic Type Tests</h1> + <t:genericTypeDisplay clientId="one" value="mapOfStrings" /> + <t:genericTypeDisplay clientId="two" value="mapOfStrings.get('foo')" /> + <t:genericTypeDisplay clientId="three" value="setOfLongs" /> + <t:genericTypeDisplay clientId="four" value="listOfListOfDates" /> + <t:genericTypeDisplay clientId="five" value="listOfListOfDates.get(0)" /> + <t:genericTypeDisplay clientId="six" value="listOfListOfDates.get(0).get(0)" /> + <t:genericTypeDisplay clientId="seven" value="[1,2,3]" /> + <t:genericTypeDisplay clientId="eight" value="{'foo':'bar'}" /> + <t:genericTypeDisplay clientId="nine" value="literal:aaa" /> +</html>
