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 2011/04/03 20:39:32 UTC
svn commit: r1088379 - in /tapestry/tapestry5/trunk/tapestry-ioc/src:
main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
test/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImplTest.java
Author: hlship
Date: Sun Apr 3 18:39:31 2011
New Revision: 1088379
URL: http://svn.apache.org/viewvc?rev=1088379&view=rev
Log:
TAP5-98: The TypeCoercer should be able to coerce String to Enum types, even without a specific contribution
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImplTest.java
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java?rev=1088379&r1=1088378&r2=1088379&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java Sun Apr 3 18:39:31 2011
@@ -15,12 +15,14 @@
package org.apache.tapestry5.ioc.internal.services;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
+import org.apache.tapestry5.func.F;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
@@ -30,6 +32,7 @@ import org.apache.tapestry5.ioc.services
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.ioc.util.AvailableValues;
import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.util.StringToEnumCoercion;
@SuppressWarnings("all")
public class TypeCoercerImpl implements TypeCoercer
@@ -241,7 +244,7 @@ public class TypeCoercerImpl implements
Set<CoercionTuple> consideredTuples = CollectionFactory.newSet();
LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
- seedQueue(sourceType, consideredTuples, queue);
+ seedQueue(sourceType, targetType, consideredTuples, queue);
while (!queue.isEmpty())
{
@@ -264,14 +267,14 @@ public class TypeCoercerImpl implements
// Now we're going to look for conversions from the intermediate type
// to some other type.
- queueIntermediates(sourceType, tuple, consideredTuples, queue);
+ queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
}
// Not found anywhere. Identify the source and target type and a (sorted) list of
// all the known coercions.
- throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.", sourceType
- .getName(), targetType.getName()), buildCoercionCatalog());
+ throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
+ sourceType.getName(), targetType.getName()), buildCoercionCatalog());
}
/**
@@ -285,20 +288,14 @@ public class TypeCoercerImpl implements
*/
private Coercion searchForNullCoercion(Class targetType)
{
- List<CoercionTuple> tuples = sourceTypeToTuple.get(void.class);
+ List<CoercionTuple> tuples = getTuples(void.class, targetType);
- // We know it will never be null, because we make contributions
- // to ensure this, but a little check doesn't hurt.
-
- if (tuples != null)
+ for (CoercionTuple tuple : tuples)
{
- for (CoercionTuple tuple : tuples)
- {
- Class tupleTargetType = tuple.getTargetType();
+ Class tupleTargetType = tuple.getTargetType();
- if (targetType.equals(tupleTargetType))
- return tuple.getCoercion();
- }
+ if (targetType.equals(tupleTargetType))
+ return tuple.getCoercion();
}
// Typical case: no match, this coercion passes the null through
@@ -327,13 +324,14 @@ public class TypeCoercerImpl implements
/**
* Seeds the pool with the initial set of coercions for the given type.
*/
- private void seedQueue(Class sourceType, Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
+ private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
+ LinkedList<CoercionTuple> queue)
{
// Work from the source type up looking for tuples
for (Class c : new InheritanceSearch(sourceType))
{
- List<CoercionTuple> tuples = sourceTypeToTuple.get(c);
+ List<CoercionTuple> tuples = getTuples(c, targetType);
if (tuples == null)
continue;
@@ -359,6 +357,8 @@ public class TypeCoercerImpl implements
*
* @param sourceType
* the source type of the coercion
+ * @param targetType
+ * TODO
* @param intermediateTuple
* a tuple that converts from the source type to some intermediate type (that is not
* assignable to the target type)
@@ -369,19 +369,14 @@ public class TypeCoercerImpl implements
* the work queue of tuples
*/
@SuppressWarnings("unchecked")
- private void queueIntermediates(Class sourceType, CoercionTuple intermediateTuple,
+ private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple,
Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
{
Class intermediateType = intermediateTuple.getTargetType();
for (Class c : new InheritanceSearch(intermediateType))
{
- List<CoercionTuple> tuples = sourceTypeToTuple.get(c);
-
- if (tuples == null)
- continue;
-
- for (CoercionTuple tuple : tuples)
+ for (CoercionTuple tuple : getTuples(c, targetType))
{
if (consideredTuples.contains(tuple))
continue;
@@ -406,8 +401,8 @@ public class TypeCoercerImpl implements
CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
// So, every tuple that is added to the queue can take as input the sourceType.
- // The target type may be another intermdiate type, or may be something
- // assignable to the target type, which will bring the search to a succesful
+ // The target type may be another intermediate type, or may be something
+ // assignable to the target type, which will bring the search to a successful
// conclusion.
queue.addLast(compoundTuple);
@@ -415,4 +410,38 @@ public class TypeCoercerImpl implements
}
}
}
+
+ /**
+ * Returns a non-null list of the tuples from the source type.
+ *
+ * @param sourceType
+ * used to locate tuples
+ * @param targetType
+ * used to add synthetic tuples
+ * @return non-null list of tuples
+ */
+ private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
+ {
+ List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
+
+ if (tuples == null)
+ tuples = Collections.emptyList();
+
+ // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
+ // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
+ // safe way (i.e., what if the Enum is defined by a class loader that gets discarded? Don't want to cause
+ // memory leaks by retaining an instance). In any case, there are edge cases where we may create
+ // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
+ // configuration), but on the whole, this is cheap at works.
+
+ if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
+ tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
+
+ return tuples;
+ }
+
+ private static <T> List<T> extend(List<T> list, T extraValue)
+ {
+ return F.flow(list).append(extraValue).toList();
+ }
}
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImplTest.java?rev=1088379&r1=1088378&r2=1088379&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImplTest.java Sun Apr 3 18:39:31 2011
@@ -15,6 +15,7 @@
package org.apache.tapestry5.ioc.internal.services;
import org.apache.tapestry5.func.F;
+import org.apache.tapestry5.ioc.annotations.AnnotationUseContext;
import org.apache.tapestry5.ioc.internal.IOCInternalTestCase;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.services.Coercion;
@@ -286,6 +287,10 @@ public class TypeCoercerImplTest extends
{ "{ 'fred': 1, 'barney': 2}", JSONObject.class, new JSONObject().put("fred", 1).put("barney", 2) },
+ // TAP5-98:
+
+ { "mixin", AnnotationUseContext.class, AnnotationUseContext.MIXIN },
+
// null to arbitrary object is still null
{ null, XMLReader.class, null } };