From 34f7badcffbf9cecd873d7b3ec5e12b3e74a280f Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Tue, 11 Mar 2008 13:38:08 +0000
Subject: [PATCH] LMS-257 BeanUtils.Converter contract extended and tested

SVN: 4770
---
 .../cisd/common/utilities/BeanUtils.java      | 37 ++++++++++++-------
 .../cisd/common/utilities/BeanUtilsTest.java  | 23 +++++++++++-
 2 files changed, 45 insertions(+), 15 deletions(-)

diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/BeanUtils.java b/common/source/java/ch/systemsx/cisd/common/utilities/BeanUtils.java
index 06abb2ec956..a90fe315a14 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/BeanUtils.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/BeanUtils.java
@@ -129,9 +129,15 @@ public final class BeanUtils
      * Marker interface for converter classes. The real method are determined via reflection. A converter needs to match
      * both the source and the destination bean. If the destination bean has a setter <code>setFoo(FooClass foo)</code>
      * and the converter has a method <code>FooClass convertToFoo(SourceBeanClass sourceBean)</code>, then this will
-     * be called instead of any getter of the <var>sourceBean</var>. Note that if there is a matching method
-     * <code>convertToFoo()</code>, it needs to have an appropriate return type or else an
-     * {@link IllegalArgumentException} will be thrown.
+     * be called instead of any getter of the <var>sourceBean</var>.
+     * <p>
+     * Note:
+     * <ul>
+     * <li>The declared <code>SourceBeanClass</code> in the converter method can also be a superclass of
+     * <code>sourceBean</code>or an interface implemented by <code>sourceBean</code>
+     * <li>If there is a matching method <code>convertToFoo()</code>, it needs to have an appropriate return type or
+     * else an {@link IllegalArgumentException} will be thrown.
+     * </ul>
      */
     public interface Converter
     {
@@ -731,20 +737,23 @@ public final class BeanUtils
     {
         if (converter != NULL_CONVERTER)
         {
-            try
+            String methodName = "convertTo" + setter.getName().substring(SETTER_PREFIX.length());
+            Class<? extends Converter> converterClasss = converter.getClass();
+            Collection<Class<?>> classes = ClassUtils.gatherAllCastableClassesAndInterfacesFor(sourceBean);
+            for (Class<?> clazz : classes)
             {
-                String methodName = "convertTo" + setter.getName().substring(SETTER_PREFIX.length());
-                Class<? extends Converter> converterClasss = converter.getClass();
-                final Method converterMethod = converterClasss.getMethod(methodName, new Class[]
-                    { sourceBean.getClass() });
-                if (converterMethod.isAccessible() == false)
+                try
+                {
+                    final Method converterMethod = converterClasss.getMethod(methodName, new Class[] { clazz });
+                    if (converterMethod.isAccessible() == false)
+                    {
+                        converterMethod.setAccessible(true);
+                    }
+                    return converterMethod;
+                } catch (NoSuchMethodException e)
                 {
-                    converterMethod.setAccessible(true);
+                    // Nothing to do here - there just isn't any converter method for this setter.
                 }
-                return converterMethod;
-            } catch (NoSuchMethodException ex)
-            {
-                // Nothing to do here - there just isn't any converter method for this setter.
             }
         }
         return null;
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/BeanUtilsTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/BeanUtilsTest.java
index 939c6df058a..459f8b32641 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/BeanUtilsTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/BeanUtilsTest.java
@@ -955,8 +955,13 @@ public final class BeanUtilsTest
         assertEquals(msg, b2.getI(), b1.getI());
         assertEquals(msg, b2.getS(), b1.getS());
     }
+    
+    private static interface IFoo
+    {
+        public String getFoo();
+    }
 
-    public static class FooBean
+    public static class FooBean implements IFoo
     {
         private String foo;
 
@@ -1001,4 +1006,20 @@ public final class BeanUtilsTest
             });
         assertEquals("some to Foo", toFooBean.getBar());
     }
+    
+    @Test
+    public void testConverterWithArgumentOfInterfaceType()
+    {
+        final FooBean tofuBean = new FooBean();
+        tofuBean.setFoo("some tofu");
+        final BarBean toFooBean = BeanUtils.createBean(BarBean.class, tofuBean, new BeanUtils.Converter()
+        {
+            @SuppressWarnings("unused")
+            public String convertToBar(IFoo foo)
+            {
+                return StringUtils.replace(foo.getFoo(), "tofu", "to Foo");
+            }
+        });
+        assertEquals("some to Foo", toFooBean.getBar());
+    }
 }
\ No newline at end of file
-- 
GitLab