Repository: tapestry-5
Updated Branches:
  refs/heads/5.4.x e226f86ac -> d7cc7c7da


TAP5-2582: Service creation for Hibernate Session results in
ClassFormatError: Duplicate method name&signature

Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/d7cc7c7d
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/d7cc7c7d
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/d7cc7c7d

Branch: refs/heads/5.4.x
Commit: d7cc7c7daed3e8d38472d211ceecfa2218793503
Parents: e226f86
Author: Thiago H. de Paula Figueiredo <[email protected]>
Authored: Fri Nov 3 00:09:53 2017 -0200
Committer: Thiago H. de Paula Figueiredo <[email protected]>
Committed: Fri Nov 3 00:09:53 2017 -0200

----------------------------------------------------------------------
 .../internal/plastic/PlasticClassImpl.java      | 124 +++++++++++++++++--
 .../tapestry5/plastic/MethodDescription.java    |  15 +++
 .../apache/tapestry5/plastic/PlasticClass.java  |  11 ++
 tapestry-ioc/build.gradle                       |   6 +-
 .../tapestry5/ioc/internal/ModuleImpl.java      |   9 +-
 .../AspectInterceptorBuilderImplSpec.groovy     |   2 +-
 .../tapestry5/ioc/internal/AdviceModule.java    |  21 ++++
 7 files changed, 173 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d7cc7c7d/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
----------------------------------------------------------------------
diff --git 
a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
 
b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
index 264825a..9683e1c 100644
--- 
a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
+++ 
b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
@@ -621,11 +621,37 @@ public class PlasticClassImpl extends Lockable implements 
PlasticClass, Internal
 
         introduceInterface(interfaceType);
 
-        for (Method m : interfaceType.getMethods())
+        // TAP5-2582: avoiding adding/delegating the same method more than once
+//        for (Method m : interfaceType.getMethods())
+//        {
+//            introduceMethod(m).delegateTo(field);
+//        }
+        
+        Map<MethodSignature, MethodDescription> map = 
createMethodSignatureMap(interfaceType);
+        for (MethodSignature methodSignature : map.keySet())
         {
-            introduceMethod(m).delegateTo(field);
+            introduceMethod(map.get(methodSignature)).delegateTo(field);
         }
+        
+        return this;
+    }
+    
+    @Override
+    public PlasticClass proxyInterface(Class interfaceType, PlasticMethod 
method)
+    {
+        check();
 
+        assert method != null;
+
+        introduceInterface(interfaceType);
+
+        // TAP5-2582: avoiding adding/delegating the same method more than once
+        Map<MethodSignature, MethodDescription> map = 
createMethodSignatureMap(interfaceType);
+        for (MethodSignature methodSignature : map.keySet())
+        {
+            introduceMethod(map.get(methodSignature)).delegateTo(method);
+        }
+        
         return this;
     }
 
@@ -1410,7 +1436,7 @@ public class PlasticClassImpl extends Lockable implements 
PlasticClass, Internal
 
         if (!interfaceType.isInterface())
             throw new IllegalArgumentException(String.format(
-                    "Class %s is not an interface; ony interfaces may be 
introduced.", interfaceType.getName()));
+                    "Class %s is not an interface; only interfaces may be 
introduced.", interfaceType.getName()));
 
         String interfaceName = nameCache.toInternalName(interfaceType);
 
@@ -1431,14 +1457,19 @@ public class PlasticClassImpl extends Lockable 
implements PlasticClass, Internal
         addClassAnnotations(interfaceClassNode);
 
         Set<PlasticMethod> introducedMethods = new HashSet<PlasticMethod>();
-
-        for (Method m : interfaceType.getMethods())
+        
+        Map<MethodSignature, MethodDescription> map = 
createMethodSignatureMap(interfaceType);
+        
+        // for (Method m : interfaceType.getMethods())
+       for (MethodSignature methodSignature : map.keySet())
         {
-            MethodDescription description = new MethodDescription(m);
+            // MethodDescription description = new MethodDescription(m);
+            final MethodDescription description = map.get(methodSignature);
 
-            if (!isMethodImplemented(description) && !isDefaultMethod(m))
+            if (!isMethodImplemented(description) && 
!isDefaultMethod(methodSignature.method))
             {
-                introducedMethods.add(introduceMethod(m));
+                // introducedMethods.add(introduceMethod(m));
+                introducedMethods.add(introduceMethod(description));
             }
         }
 
@@ -1447,6 +1478,83 @@ public class PlasticClassImpl extends Lockable 
implements PlasticClass, Internal
         return introducedMethods;
     }
 
+    private Map<MethodSignature, MethodDescription> 
createMethodSignatureMap(Class interfaceType) {
+       // TAP-2582: preprocessing the method list so we don't add duplicated
+        // methods, something that happens when an interface has 
superinterfaces
+        // and they define the same method signature.
+        // In addition, we collect all the thrown checked exceptions, just in 
case.
+        Map<MethodSignature, MethodDescription> map = new 
HashMap<MethodSignature, MethodDescription>();
+        for (Method m : interfaceType.getMethods())
+        {
+            final MethodSignature methodSignature = new MethodSignature(m);
+            final MethodDescription newMethodDescription = new 
MethodDescription(m);
+            if (!map.containsKey(methodSignature)) 
+            {
+               map.put(methodSignature, newMethodDescription);
+            }
+            else 
+            {
+               if (newMethodDescription.checkedExceptionTypes != null && 
newMethodDescription.checkedExceptionTypes.length > 0)
+               {
+                   final MethodDescription methodDescription = 
map.get(methodSignature);
+                    final Set<String> checkedExceptionTypes = new 
HashSet<String>();
+                    
checkedExceptionTypes.addAll(Arrays.asList(methodDescription.checkedExceptionTypes));
+                    
checkedExceptionTypes.addAll(Arrays.asList(newMethodDescription.checkedExceptionTypes));
+                    map.put(methodSignature, new MethodDescription(
+                           methodDescription, 
+                           checkedExceptionTypes.toArray(new 
String[checkedExceptionTypes.size()])));
+               }
+            }
+        }
+       return map;
+    }
+    
+    final private static class MethodSignature implements 
Comparable<MethodSignature>{
+       
+       final private Method method;
+       final private String name;
+       final private Class<?>[] parameterTypes;
+       
+       public MethodSignature(Method method) {
+           this.method = method;
+           this.name = method.getName();
+           this.parameterTypes = method.getParameterTypes();
+       }
+
+       @Override
+       public int hashCode() {
+           final int prime = 31;
+           int result = 1;
+           result = prime * result + Arrays.hashCode(parameterTypes);
+           result = prime * result + ((name == null) ? 0 : name.hashCode());
+           return result;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+           if (this == obj)
+               return true;
+           if (obj == null)
+               return false;
+           if (getClass() != obj.getClass())
+               return false;
+           MethodSignature other = (MethodSignature) obj;
+           if (!Arrays.equals(parameterTypes, other.parameterTypes))
+               return false;
+           if (name == null) {
+               if (other.name != null)
+                   return false;
+           } else if (!name.equals(other.name))
+               return false;
+           return true;
+       }
+
+       @Override
+       public int compareTo(MethodSignature o) {
+           return method.getName().compareTo(o.method.getName());
+       }
+    }
+
     @Override
     public PlasticClass addToString(final String toStringValue)
     {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d7cc7c7d/plastic/src/main/java/org/apache/tapestry5/plastic/MethodDescription.java
----------------------------------------------------------------------
diff --git 
a/plastic/src/main/java/org/apache/tapestry5/plastic/MethodDescription.java 
b/plastic/src/main/java/org/apache/tapestry5/plastic/MethodDescription.java
index e0b7d2a..5f8b88f 100644
--- a/plastic/src/main/java/org/apache/tapestry5/plastic/MethodDescription.java
+++ b/plastic/src/main/java/org/apache/tapestry5/plastic/MethodDescription.java
@@ -72,6 +72,21 @@ public class MethodDescription implements 
Comparable<MethodDescription>
     {
         this(Modifier.PUBLIC, returnType, methodName, argumentTypes, null, 
null);
     }
+    
+    /**
+     * Convenience constructor for copying a MethodDescription with
+     * different exception types.
+     * @since 5.4.4
+     */
+    public MethodDescription(MethodDescription description, String[] 
checkedExceptionTypes)
+    {
+       this.argumentTypes = description.argumentTypes;
+       this.checkedExceptionTypes = checkedExceptionTypes;
+       this.genericSignature = description.genericSignature;
+       this.methodName = description.methodName;
+       this.modifiers = description.modifiers;
+       this.returnType = description.returnType;
+    }
 
     /**
      * @param modifiers

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d7cc7c7d/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java
----------------------------------------------------------------------
diff --git 
a/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java 
b/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java
index e212fe5..2168456 100644
--- a/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java
+++ b/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java
@@ -163,6 +163,17 @@ public interface PlasticClass extends AnnotationAccess
      * @return this plastic class, for further configuration
      */
     PlasticClass proxyInterface(Class interfaceType, PlasticField field);
+    
+    /**
+     * Introduces the interface, and then invokes {@link 
PlasticMethod#delegateTo(PlasticMethod)} on each method
+     * defined by the interface.
+     *
+     * @param interfaceType defines the interface to proxy
+     * @param method        method to delegate to
+     * @return this plastic class, for further configuration
+     * @since 5.4.4
+     */
+    PlasticClass proxyInterface(Class interfaceType, PlasticMethod method);
 
     /**
      * Conditionally adds an implementation of <code>toString()</code> to the 
class, but only if it is not already

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d7cc7c7d/tapestry-ioc/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-ioc/build.gradle b/tapestry-ioc/build.gradle
index 8113a23..b208818 100644
--- a/tapestry-ioc/build.gradle
+++ b/tapestry-ioc/build.gradle
@@ -15,8 +15,10 @@ dependencies {
 
     compile "org.slf4j:slf4j-api:${versions.slf4j}"
 
-    testCompile "commons-lang:commons-lang:2.6"
-
+    testCompile "org.apache.commons:commons-lang3:3.4"
+    testCompile "org.hibernate:hibernate-core:5.2.10.Final"
+    testRuntime "org.hsqldb:hsqldb:2.2.8"
+    
     provided "org.testng:testng:${versions.testng}", { transitive = false }
 }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d7cc7c7d/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
index 48bf24d..51f864c 100644
--- 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
+++ 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
@@ -509,10 +509,11 @@ public class ModuleImpl implements Module
                     }
                 });
 
-                for (Method m : serviceInterface.getMethods())
-                {
-                    plasticClass.introduceMethod(m).delegateTo(delegateMethod);
-                }
+                plasticClass.proxyInterface(serviceInterface, delegateMethod);
+//                for (Method m : serviceInterface.getMethods())
+//                {
+//                    
plasticClass.introduceMethod(m).delegateTo(delegateMethod);
+//                }
 
                 
plasticClass.introduceMethod(WRITE_REPLACE).changeImplementation(new 
InstructionBuilderCallback()
                 {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d7cc7c7d/tapestry-ioc/src/test/groovy/ioc/specs/AspectInterceptorBuilderImplSpec.groovy
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/groovy/ioc/specs/AspectInterceptorBuilderImplSpec.groovy
 
b/tapestry-ioc/src/test/groovy/ioc/specs/AspectInterceptorBuilderImplSpec.groovy
index e543482..b614c38 100644
--- 
a/tapestry-ioc/src/test/groovy/ioc/specs/AspectInterceptorBuilderImplSpec.groovy
+++ 
b/tapestry-ioc/src/test/groovy/ioc/specs/AspectInterceptorBuilderImplSpec.groovy
@@ -1,6 +1,6 @@
 package ioc.specs
 
-import org.apache.commons.lang.StringUtils
+import org.apache.commons.lang3.StringUtils
 import org.apache.tapestry5.ioc.internal.services.TextTransformer
 import org.apache.tapestry5.ioc.services.AspectDecorator
 import org.apache.tapestry5.plastic.MethodAdvice

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/d7cc7c7d/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
index 0e0a186..f943152 100644
--- 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
+++ 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
@@ -13,9 +13,15 @@
 // limitations under the License.
 package org.apache.tapestry5.ioc.internal;
 
+
 import org.apache.tapestry5.ioc.MethodAdviceReceiver;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.Registry;
+import org.apache.tapestry5.ioc.RegistryBuilder;
 import org.apache.tapestry5.ioc.ServiceBinder;
 import org.apache.tapestry5.ioc.annotations.Advise;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
 
 public class AdviceModule
 {
@@ -45,4 +51,19 @@ public class AdviceModule
             final MethodAdviceReceiver methodAdviceReceiver) {
         methodAdviceReceiver.adviseAllMethods(new TestAdvice());
     }
+    
+//    public static void main(String[] args) {
+//     Registry registry = 
RegistryBuilder.buildAndStartupRegistry(AdviceModule.class);
+//     Session session = registry.getService(Session.class);
+//    }
+    
+    // TAP5-2582
+    public static Session buildHibernateSession(
+           ObjectLocator objectLocator
+       ) {
+           return new Configuration()
+               .configure("hibernate.cfg.xml")
+               .buildSessionFactory()
+               .openSession();
+       }
 }

Reply via email to