Author: hlship
Date: Tue Feb 13 10:35:46 2007
New Revision: 507150

URL: http://svn.apache.org/viewvc?view=rev&rev=507150
Log:
Improve exception reporting when a type coercion fails, to identify the exact 
chain of coercions used

Modified:
    
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/CompoundCoercion.java
    
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ServiceMessages.java
    
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImpl.java
    
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/CoercionTuple.java
    
tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/internal/services/ServiceStrings.properties
    
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImplTest.java

Modified: 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/CompoundCoercion.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/CompoundCoercion.java?view=diff&rev=507150&r1=507149&r2=507150
==============================================================================
--- 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/CompoundCoercion.java
 (original)
+++ 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/CompoundCoercion.java
 Tue Feb 13 10:35:46 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -12,44 +12,45 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.ioc.internal.services;
-
-import org.apache.tapestry.ioc.services.Coercion;
-
-/**
- * Combines two coercions to create a coercsion through an intermediate type.
- * 
- * 
- * @param <S>
- *            The source (input) type
- * @param <I>
- *            The intermediate type
- * @param <T>
- *            The target (output) type
- */
-public class CompoundCoercion<S, I, T> implements Coercion<S, T>
-{
-    private final Coercion<S, I> _op1;
-
-    private final Coercion<I, T> _op2;
-
-    public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
-    {
-        _op1 = op1;
-        _op2 = op2;
-    }
-
-    public T coerce(S input)
-    {
-        // Run the input through the first operation (S --> I), then run the 
result of that through
-        // the second operation (I --> T).
-
-        return _op2.coerce(_op1.coerce(input));
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("CompoundCoercion[%s %s]", _op1, _op2);
-    }
-}
+package org.apache.tapestry.ioc.internal.services;
+
+import org.apache.tapestry.ioc.services.Coercion;
+
+/**
+ * Combines two coercions to create a coercsion through an intermediate type.
+ * 
+ * @param <S>
+ *            The source (input) type
+ * @param <I>
+ *            The intermediate type
+ * @param <T>
+ *            The target (output) type
+ */
+public class CompoundCoercion<S, I, T> implements Coercion<S, T>
+{
+    private final Coercion<S, I> _op1;
+
+    private final Coercion<I, T> _op2;
+
+    public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
+    {
+        _op1 = op1;
+        _op2 = op2;
+    }
+
+    public T coerce(S input)
+    {
+        // Run the input through the first operation (S --> I), then run the 
result of that through
+        // the second operation (I --> T).
+
+        I intermediate = _op1.coerce(input);
+        
+        return _op2.coerce(intermediate);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s, %s", _op1, _op2);
+    }
+}

Modified: 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ServiceMessages.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ServiceMessages.java?view=diff&rev=507150&r1=507149&r2=507150
==============================================================================
--- 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ServiceMessages.java
 (original)
+++ 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/ServiceMessages.java
 Tue Feb 13 10:35:46 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -18,6 +18,8 @@
 
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.ioc.internal.util.MessagesImpl;
+import org.apache.tapestry.ioc.services.ClassFabUtils;
+import org.apache.tapestry.ioc.services.Coercion;
 import org.apache.tapestry.ioc.services.MethodSignature;
 import org.apache.tapestry.ioc.services.ThreadCleanupListener;
 
@@ -167,5 +169,11 @@
     static String missingSymbolCloseBraceInPath(String input, String path)
     {
         return MESSAGES.format("missing-symbol-close-brace-in-path", input, 
path);
+    }
+
+    static String failedCoercion(Object input, Class targetType, Coercion 
coercion, Throwable cause)
+    {
+        return MESSAGES.format("failed-coercion", String.valueOf(input), 
ClassFabUtils
+                .getJavaClassName(targetType), coercion, cause);
     }
 }

Modified: 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImpl.java?view=diff&rev=507150&r1=507149&r2=507150
==============================================================================
--- 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImpl.java
 (original)
+++ 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImpl.java
 Tue Feb 13 10:35:46 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -101,6 +101,8 @@
         }
     }
 
+    @SuppressWarnings(
+    { "unchecked", "unchecked" })
     private void addTuple(Class key, CoercionTuple tuple)
     {
         List<CoercionTuple> list = _sourceTypeToTuple.get(key);
@@ -133,16 +135,29 @@
 
         if (effectiveTargetType.isAssignableFrom(sourceType)) return input;
 
-        Coercion coercer = findCoercer(sourceType, effectiveTargetType);
+        Coercion coercion = findCoercion(sourceType, effectiveTargetType);
 
-        Object result = coercer.coerce(input);
+        Object result;
+
+        try
+        {
+            result = coercion.coerce(input);
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(ServiceMessages.failedCoercion(
+                    input,
+                    targetType,
+                    coercion,
+                    ex), ex);
+        }
 
         // Double check that the coercer provided a result of the correct type
 
         return effectiveTargetType.cast(result);
     }
 
-    private Coercion findCoercer(Class sourceType, Class targetType)
+    private Coercion findCoercion(Class sourceType, Class targetType)
     {
         CacheKey key = new CacheKey(sourceType, targetType);
 
@@ -150,7 +165,7 @@
 
         if (result == null)
         {
-            result = findOrCreateCoercer(sourceType, targetType);
+            result = findOrCreateCoercion(sourceType, targetType);
             _cache.put(key, result);
         }
 
@@ -188,7 +203,7 @@
      * @return coercer from sourceType to targetType
      */
     @SuppressWarnings("unchecked")
-    private Coercion findOrCreateCoercer(Class sourceType, Class targetType)
+    private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
     {
         // These are instance variables because this method may be called 
concurrently.
         // On a true race, we may go to the work of seeking out and/or 
fabricating
@@ -248,13 +263,7 @@
         for (List<CoercionTuple> list : _sourceTypeToTuple.values())
         {
             for (CoercionTuple tuple : list)
-            {
-                String description = String.format("%s --> %s", ClassFabUtils
-                        .getJavaClassName(tuple.getSourceType()), ClassFabUtils
-                        .getJavaClassName(tuple.getTargetType()));
-
-                descriptions.add(description);
-            }
+                descriptions.add(tuple.toString());
         }
 
         return InternalUtils.joinSorted(descriptions);
@@ -329,7 +338,7 @@
                         tuple.getCoercion());
 
                 CoercionTuple compoundTuple = new CoercionTuple(sourceType, 
newIntermediateType,
-                        compoundCoercer);
+                        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

Modified: 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/CoercionTuple.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/CoercionTuple.java?view=diff&rev=507150&r1=507149&r2=507150
==============================================================================
--- 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/CoercionTuple.java
 (original)
+++ 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/java/org/apache/tapestry/ioc/services/CoercionTuple.java
 Tue Feb 13 10:35:46 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -12,55 +12,107 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.ioc.services;
-
-/**
- * An immutable object that represents a mapping from one type to another. 
This is also the
- * contribution type when buildign the TypeCoercer service. Wraps a [EMAIL 
PROTECTED] Coercion} object that
- * performs the work with additional properties that describe the input and 
output types of the
- * coercion, needed when searching for an appropriate coercion (or combination 
of coercions).
- * 
- * 
- * @param <S>
- *            source (input) type
- * @param <T>
- *            target (output) type
- */
-public final class CoercionTuple<S, T>
-{
-    private final Class<S> _sourceType;
-
-    private final Class<T> _targetType;
-
-    private final Coercion<S, T> _coercion;
-
-    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, 
T> coercer)
-    {
-        _sourceType = sourceType;
-        _targetType = targetType;
-        _coercion = coercer;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("CoercionTuple[%s --> %s]", 
_sourceType.getName(), _targetType
-                .getName());
-    }
-
-    public Coercion<S, T> getCoercion()
-    {
-        return _coercion;
-    }
-
-    public Class<S> getSourceType()
-    {
-        return _sourceType;
-    }
-
-    public Class<T> getTargetType()
-    {
-        return _targetType;
-    }
-
-}
+package org.apache.tapestry.ioc.services;
+
+import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
+
+/**
+ * An immutable object that represents a mapping from one type to another. 
This is also the
+ * contribution type when buildign the TypeCoercer service. Wraps a [EMAIL 
PROTECTED] Coercion} object that
+ * performs the work with additional properties that describe the input and 
output types of the
+ * coercion, needed when searching for an appropriate coercion (or combination 
of coercions).
+ * 
+ * @param <S>
+ *            source (input) type
+ * @param <T>
+ *            target (output) type
+ */
+public final class CoercionTuple<S, T>
+{
+    private final Class<S> _sourceType;
+
+    private final Class<T> _targetType;
+
+    private final Coercion<S, T> _coercion;
+
+    /**
+     * Wraps an arbitrary coercion with an implementation of toString() that 
identifies the source
+     * and target types.
+     */
+    private class CoercionWrapper<S, T> implements Coercion<S, T>
+    {
+        private final Coercion<S, T> _coercion;
+
+        public CoercionWrapper(Coercion<S, T> coercion)
+        {
+            _coercion = coercion;
+        }
+
+        public T coerce(S input)
+        {
+            return _coercion.coerce(input);
+        }
+
+        public String toString()
+        {
+            return String.format(
+                    "%s --> %s",
+                    ClassFabUtils.getJavaClassName(_sourceType),
+                    ClassFabUtils.getJavaClassName(_targetType));
+        }
+    }
+
+    /**
+     * Standard constructor, which defaults wrap to true.
+     */
+    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, 
T> coercion)
+    {
+        this(sourceType, targetType, coercion, true);
+    }
+
+    /**
+     * Internal-use constructor.
+     * 
+     * @param sourceType
+     *            the source (or input) type of the coercion
+     * @param targetType
+     *            the target (or output) type of the coercion
+     * @param coercion
+     *            the object that performs the coercion
+     * @param wrap
+     *            if true, the coercion is wrapped to provide a useful 
toString()
+     */
+    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, 
T> coercion,
+            boolean wrap)
+    {
+        notNull(sourceType, "sourceType");
+        notNull(targetType, "targetType");
+        notNull(coercion, "coercion");
+
+        _sourceType = sourceType;
+        _targetType = targetType;
+        _coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
+    }
+
+    @Override
+    public String toString()
+    {
+        return _coercion.toString();
+    }
+
+    public Coercion<S, T> getCoercion()
+    {
+        return _coercion;
+    }
+
+    public Class<S> getSourceType()
+    {
+        return _sourceType;
+    }
+
+    public Class<T> getTargetType()
+    {
+        return _targetType;
+    }
+
+}

Modified: 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/internal/services/ServiceStrings.properties
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/internal/services/ServiceStrings.properties?view=diff&rev=507150&r1=507149&r2=507150
==============================================================================
--- 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/internal/services/ServiceStrings.properties
 (original)
+++ 
tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/internal/services/ServiceStrings.properties
 Tue Feb 13 10:35:46 2007
@@ -1,4 +1,4 @@
-# Copyright 2006 The Apache Software Foundation
+# Copyright 2006, 2007 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.
@@ -37,4 +37,4 @@
 symbol-undefined-in-path=Symbol '%s' is not defined (in %s). 
 missing-symbol-close-brace=Input string '%s' is missing a symbol closing brace.
 missing-symbol-close-brace-in-path=Input string '%s' is missing a symbol 
closing brace (in %s).
-
+failed-coercion=Coercion of %s to type %s (via %s) failed: %s

Modified: 
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImplTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImplTest.java?view=diff&rev=507150&r1=507149&r2=507150
==============================================================================
--- 
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImplTest.java
 (original)
+++ 
tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImplTest.java
 Tue Feb 13 10:35:46 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2007 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.
@@ -87,7 +87,7 @@
     }
 
     @Test
-    public void coercion_failure()
+    public void no_coercion_found()
     {
         try
         {
@@ -98,6 +98,24 @@
         {
             assertTrue(ex.getMessage().contains(
                     "Could not find a coercion from type java.lang.String to 
type java.util.Map"));
+        }
+    }
+
+    @Test
+    public void coercion_failure()
+    {
+        try
+        {
+            _coercer.coerce(Collections.EMPTY_MAP, Float.class);
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertTrue(ex
+                    .getMessage()
+                    .contains(
+                            "Coercion of {} to type java.lang.Float (via 
java.lang.Object --> java.lang.String, java.lang.String --> java.lang.Double, 
java.lang.Double --> java.lang.Float) failed"));
+            assertTrue(ex.getCause() instanceof NumberFormatException);
         }
     }
 


Reply via email to