You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/03/12 12:43:06 UTC
incubator-freemarker git commit: Fixed problem in default method
support,
where the bridge method and the related reified method appears as overloaded
methods with same parameter types,
if the reified method comes from a default method, and the bridge me
Repository: incubator-freemarker
Updated Branches:
refs/heads/2.3-gae cbc449518 -> d095f5ae3
Fixed problem in default method support, where the bridge method and the related reified method appears as overloaded methods with same parameter types, if the reified method comes from a default method, and the bridge method comes from a class.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/d095f5ae
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/d095f5ae
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/d095f5ae
Branch: refs/heads/2.3-gae
Commit: d095f5ae38b0bdefa87a5d732aceb9acb6997581
Parents: cbc4495
Author: ddekany <dd...@apache.org>
Authored: Sun Mar 12 13:42:59 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Sun Mar 12 13:42:59 2017 +0100
----------------------------------------------------------------------
.../freemarker/ext/beans/ClassIntrospector.java | 72 +++++++++++++++-----
.../beans/BeansWrapperBridgeMethodsTest.java | 47 +++++++++++++
.../freemarker/ext/beans/BridgeMethodsBean.java | 12 ++++
.../ext/beans/BridgeMethodsBeanBase.java | 11 +++
.../BridgeMethodsWithDefaultMethodBean.java | 11 +++
.../BridgeMethodsWithDefaultMethodBean2.java | 5 ++
.../BridgeMethodsWithDefaultMethodBeanBase.java | 13 ++++
...BridgeMethodsWithDefaultMethodBeanBase2.java | 10 +++
8 files changed, 163 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d095f5ae/src/main/java/freemarker/ext/beans/ClassIntrospector.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/beans/ClassIntrospector.java b/src/main/java/freemarker/ext/beans/ClassIntrospector.java
index 8fa0037..911b14d 100644
--- a/src/main/java/freemarker/ext/beans/ClassIntrospector.java
+++ b/src/main/java/freemarker/ext/beans/ClassIntrospector.java
@@ -597,25 +597,47 @@ class ClassIntrospector {
// java.beans.Introspector was good enough then.
return introspectionMDs;
}
-
- boolean anyDefaultMethodsAdded = false;
- findDefaultMethods: for (Method method : clazz.getMethods()) {
- if (_JavaVersions.JAVA_8.isDefaultMethod(method)) {
- if (!anyDefaultMethodsAdded) {
- for (MethodDescriptor methodDescriptor : introspectionMDs) {
- // Check if java.bean.Introspector now finds default methods (it did not in Java 1.8.0_66):
- if (_JavaVersions.JAVA_8.isDefaultMethod(methodDescriptor.getMethod())) {
- break findDefaultMethods;
- }
-
- // Recreate introspectionMDs so that its size can grow:
- ArrayList<MethodDescriptor> newIntrospectionMDs
- = new ArrayList<MethodDescriptor>(introspectionMDs.size() + 16);
- newIntrospectionMDs.addAll(introspectionMDs);
- introspectionMDs = newIntrospectionMDs;
- }
- anyDefaultMethodsAdded = true;
+
+ Map<String, List<Method>> defaultMethodsToAddByName = null;
+ for (Method method : clazz.getMethods()) {
+ if (_JavaVersions.JAVA_8.isDefaultMethod(method) && !method.isBridge()) {
+ if (defaultMethodsToAddByName == null) {
+ defaultMethodsToAddByName = new HashMap<String, List<Method>>();
+ }
+ List<Method> overloads = defaultMethodsToAddByName.get(method.getName());
+ if (overloads == null) {
+ overloads = new ArrayList<Method>(0);
+ defaultMethodsToAddByName.put(method.getName(), overloads);
}
+ overloads.add(method);
+ }
+ }
+
+ if (defaultMethodsToAddByName == null) {
+ // We had no interfering default methods:
+ return introspectionMDs;
+ }
+
+ // Recreate introspectionMDs so that its size can grow:
+ ArrayList<MethodDescriptor> newIntrospectionMDs
+ = new ArrayList<MethodDescriptor>(introspectionMDs.size() + 16);
+ for (MethodDescriptor introspectorMD : introspectionMDs) {
+ Method introspectorM = introspectorMD.getMethod();
+ // Prevent cases where the same method is added with different return types both from the list of default
+ // methods and from the list of Introspector-discovered methods, as that would lead to overloaded method
+ // selection ambiguity later. This is known to happen when the default method in an interface has reified
+ // return type, and then the interface is implemented by a class where the compiler generates an override
+ // for the bridge method only. (Other tricky cases might exist.)
+ if (!containsMethodWithSameParameterTypes(
+ defaultMethodsToAddByName.get(introspectorM.getName()), introspectorM)) {
+ newIntrospectionMDs.add(introspectorMD);
+ }
+ }
+ introspectionMDs = newIntrospectionMDs;
+
+ // Add default methods:
+ for (Entry<String, List<Method>> entry : defaultMethodsToAddByName.entrySet()) {
+ for (Method method : entry.getValue()) {
introspectionMDs.add(new MethodDescriptor(method));
}
}
@@ -623,6 +645,20 @@ class ClassIntrospector {
return introspectionMDs;
}
+ private boolean containsMethodWithSameParameterTypes(List<Method> overloads, Method m) {
+ if (overloads == null) {
+ return false;
+ }
+
+ Class<?>[] paramTypes = m.getParameterTypes();
+ for (Method overload : overloads) {
+ if (Arrays.equals(overload.getParameterTypes(), paramTypes)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void addPropertyDescriptorToClassIntrospectionData(Map<Object, Object> introspData,
PropertyDescriptor pd, Class<?> clazz, Map<MethodSignature, List<Method>> accessibleMethods) {
if (pd instanceof IndexedPropertyDescriptor) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d095f5ae/src/test/java/freemarker/ext/beans/BeansWrapperBridgeMethodsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BeansWrapperBridgeMethodsTest.java b/src/test/java/freemarker/ext/beans/BeansWrapperBridgeMethodsTest.java
new file mode 100644
index 0000000..5f73d0e
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/BeansWrapperBridgeMethodsTest.java
@@ -0,0 +1,47 @@
+package freemarker.ext.beans;
+
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+
+import org.junit.Test;
+
+import freemarker.template.Configuration;
+import freemarker.template.TemplateHashModel;
+import freemarker.template.TemplateMethodModelEx;
+import freemarker.template.TemplateModelException;
+
+public class BeansWrapperBridgeMethodsTest {
+
+ @Test
+ public void testWithoutDefaultMethod() throws TemplateModelException {
+ test(BridgeMethodsBean.class);
+ }
+
+ @Test
+ public void testWithDefaultMethod() throws TemplateModelException {
+ test(BridgeMethodsWithDefaultMethodBean.class);
+ }
+
+ @Test
+ public void testWithDefaultMethod2() throws TemplateModelException {
+ test(BridgeMethodsWithDefaultMethodBean2.class);
+ }
+
+ private void test(Class<?> pClass) throws TemplateModelException {
+ BeansWrapper ow = new BeansWrapperBuilder(Configuration.VERSION_2_3_26).build();
+ TemplateHashModel wrapped;
+ try {
+ wrapped = (TemplateHashModel) ow.wrap(pClass.newInstance());
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+
+ TemplateMethodModelEx m1 = (TemplateMethodModelEx) wrapped.get("m1");
+ assertEquals(BridgeMethodsBean.M1_RETURN_VALUE, "" + m1.exec(Collections.emptyList()));
+
+ TemplateMethodModelEx m2 = (TemplateMethodModelEx) wrapped.get("m2");
+ assertNull(m2.exec(Collections.emptyList()));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d095f5ae/src/test/java/freemarker/ext/beans/BridgeMethodsBean.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BridgeMethodsBean.java b/src/test/java/freemarker/ext/beans/BridgeMethodsBean.java
new file mode 100644
index 0000000..a32853c
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/BridgeMethodsBean.java
@@ -0,0 +1,12 @@
+package freemarker.ext.beans;
+
+public class BridgeMethodsBean extends BridgeMethodsBeanBase<String> {
+
+ static final String M1_RETURN_VALUE = "m1ReturnValue";
+
+ @Override
+ public String m1() {
+ return M1_RETURN_VALUE;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d095f5ae/src/test/java/freemarker/ext/beans/BridgeMethodsBeanBase.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BridgeMethodsBeanBase.java b/src/test/java/freemarker/ext/beans/BridgeMethodsBeanBase.java
new file mode 100644
index 0000000..4823400
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/BridgeMethodsBeanBase.java
@@ -0,0 +1,11 @@
+package freemarker.ext.beans;
+
+public abstract class BridgeMethodsBeanBase<T> {
+
+ public abstract T m1();
+
+ public T m2() {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d095f5ae/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean.java b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean.java
new file mode 100644
index 0000000..0c18991
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean.java
@@ -0,0 +1,11 @@
+package freemarker.ext.beans;
+
+public class BridgeMethodsWithDefaultMethodBean implements BridgeMethodsWithDefaultMethodBeanBase<String> {
+
+ static final String M1_RETURN_VALUE = "m1ReturnValue";
+
+ public String m1() {
+ return M1_RETURN_VALUE;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d095f5ae/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean2.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean2.java b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean2.java
new file mode 100644
index 0000000..85bc232
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean2.java
@@ -0,0 +1,5 @@
+package freemarker.ext.beans;
+
+public class BridgeMethodsWithDefaultMethodBean2 implements BridgeMethodsWithDefaultMethodBeanBase2 {
+ // All inherited
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d095f5ae/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase.java b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase.java
new file mode 100644
index 0000000..68960de
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase.java
@@ -0,0 +1,13 @@
+package freemarker.ext.beans;
+
+public interface BridgeMethodsWithDefaultMethodBeanBase<T> {
+
+ default T m1() {
+ return null;
+ }
+
+ default T m2() {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d095f5ae/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase2.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase2.java b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase2.java
new file mode 100644
index 0000000..be46d4f
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase2.java
@@ -0,0 +1,10 @@
+package freemarker.ext.beans;
+
+public interface BridgeMethodsWithDefaultMethodBeanBase2 extends BridgeMethodsWithDefaultMethodBeanBase<String> {
+
+ @Override
+ default String m1() {
+ return BridgeMethodsWithDefaultMethodBean.M1_RETURN_VALUE;
+ }
+
+}