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(); + } }
