You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2021/07/09 12:09:30 UTC
[tomcat] 02/02: Check requirements of functional interface rather
than annotation
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 0827d1ce4200ad030a9c3496349b240fefeb53a7
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Jul 9 13:07:14 2021 +0100
Check requirements of functional interface rather than annotation
The annotation is only a recommendation so check to see if type meets
the requirements of a functional interface rather than relying on the
annotation.
---
java/org/apache/el/lang/ELSupport.java | 57 ++++++++++++++++++-
test/org/apache/el/lang/TestELSupport.java | 88 ++++++++++++++++++++++++++++++
2 files changed, 144 insertions(+), 1 deletion(-)
diff --git a/java/org/apache/el/lang/ELSupport.java b/java/org/apache/el/lang/ELSupport.java
index 3f8fa78..bc1b67a 100644
--- a/java/org/apache/el/lang/ELSupport.java
+++ b/java/org/apache/el/lang/ELSupport.java
@@ -592,7 +592,7 @@ public class ELSupport {
return result;
}
- if (obj instanceof LambdaExpression && type.getAnnotation(FunctionalInterface.class) != null) {
+ if (obj instanceof LambdaExpression && isFunctionalInterface(type)) {
T result = coerceToFunctionalInterface(ctx, (LambdaExpression) obj, type);
return result;
}
@@ -687,6 +687,61 @@ public class ELSupport {
}
+ static boolean isFunctionalInterface(Class<?> type) {
+
+ if (!type.isInterface()) {
+ return false;
+ }
+
+ boolean foundAbstractMethod = false;
+ Method[] methods = type.getMethods();
+ for (Method method : methods) {
+ if (Modifier.isAbstract(method.getModifiers())) {
+ // Abstract methods that override one of the public methods
+ // of Object don't count
+ if (overridesObjectMethod(method)) {
+ continue;
+ }
+ if (foundAbstractMethod) {
+ // Found more than one
+ return false;
+ } else {
+ foundAbstractMethod = true;
+ }
+ }
+ }
+ return foundAbstractMethod;
+ }
+
+
+ private static boolean overridesObjectMethod(Method method) {
+ // There are three methods that can be overridden
+ if ("equals".equals(method.getName())) {
+ if (method.getReturnType().equals(boolean.class)) {
+ if (method.getParameterCount() == 1) {
+ if (method.getParameterTypes()[0].equals(Object.class)) {
+ return true;
+ }
+ }
+ }
+ } else if ("hashCode".equals(method.getName())) {
+ if (method.getReturnType().equals(int.class)) {
+ if (method.getParameterCount() == 0) {
+ return true;
+ }
+ }
+ } else if ("toString".equals(method.getName())) {
+ if (method.getReturnType().equals(String.class)) {
+ if (method.getParameterCount() == 0) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
private ELSupport() {
// Uility class - hide default constructor;
}
diff --git a/test/org/apache/el/lang/TestELSupport.java b/test/org/apache/el/lang/TestELSupport.java
index 2cf1217..76d174f 100644
--- a/test/org/apache/el/lang/TestELSupport.java
+++ b/test/org/apache/el/lang/TestELSupport.java
@@ -19,6 +19,7 @@ package org.apache.el.lang;
import java.beans.PropertyEditorManager;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.util.Map;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
@@ -372,4 +373,91 @@ public class TestELSupport {
return "BLOCK";
}
}
+
+
+ @Test
+ public void testIsFunctionalInterface01() {
+ Assert.assertTrue(ELSupport.isFunctionalInterface(Predicate.class));
+ }
+
+
+ @Test
+ public void testIsFunctionalInterface02() {
+ // Interface but more than one abstract method
+ Assert.assertFalse(ELSupport.isFunctionalInterface(Map.class));
+ }
+
+
+ @Test
+ public void testIsFunctionalInterface03() {
+ // Not an interface
+ Assert.assertFalse(ELSupport.isFunctionalInterface(String.class));
+ }
+
+
+ @Test
+ public void testIsFunctionalInterface04() {
+ // Extends a functional interface with no changes
+ Assert.assertTrue(ELSupport.isFunctionalInterface(FunctionalA.class));
+ }
+
+
+ @Test
+ public void testIsFunctionalInterface05() {
+ // Extends a functional interface with additional abstract method
+ Assert.assertFalse(ELSupport.isFunctionalInterface(FunctionalB.class));
+ }
+
+
+ @Test
+ public void testIsFunctionalInterface06() {
+ // Extends a functional interface with additional default method
+ Assert.assertTrue(ELSupport.isFunctionalInterface(FunctionalC.class));
+ }
+
+
+ @Test
+ public void testIsFunctionalInterface07() {
+ // Extends a functional interface and overrides method in Object
+ Assert.assertTrue(ELSupport.isFunctionalInterface(FunctionalD.class));
+ }
+
+
+ @Test
+ public void testIsFunctionalInterface08() {
+ // Extends a functional interface adds a method that looks like a
+ // method from Object
+ Assert.assertFalse(ELSupport.isFunctionalInterface(FunctionalE.class));
+ }
+
+
+ private static interface FunctionalA<T> extends Predicate<T> {
+ }
+
+
+ private static interface FunctionalB<T> extends Predicate<T> {
+ public void extra();
+ }
+
+
+ private static interface FunctionalC<T> extends Predicate<T> {
+ @SuppressWarnings("unused")
+ public default void extra() {
+ }
+ }
+
+
+ private static interface FunctionalD<T> extends Predicate<T> {
+ @Override
+ public String toString();
+ @Override
+ public int hashCode();
+ @Override
+ public boolean equals(Object o);
+ }
+
+
+ private static interface FunctionalE<T> extends Predicate<T> {
+ public boolean equals(String s);
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org