From ef9e430ae4394325fa36883e78a642c23a384200 Mon Sep 17 00:00:00 2001 From: kaifox Date: Thu, 7 May 2020 15:57:16 +0200 Subject: [PATCH] workaround for different treatment of default methods for java 8 and java 11 --- .../ProxiedInterfaceTensorbackeds.java | 56 ++++++++----------- .../org/tensorics/core/util/JavaVersions.java | 20 +++++++ .../core/util/JavaVersionsTries.java | 16 ++++++ 3 files changed, 59 insertions(+), 33 deletions(-) create mode 100644 src/java/org/tensorics/core/util/JavaVersions.java create mode 100644 src/test/org/tensorics/core/util/JavaVersionsTries.java diff --git a/src/java/org/tensorics/core/tensorbacked/ProxiedInterfaceTensorbackeds.java b/src/java/org/tensorics/core/tensorbacked/ProxiedInterfaceTensorbackeds.java index 22e036674..8350d6a3f 100644 --- a/src/java/org/tensorics/core/tensorbacked/ProxiedInterfaceTensorbackeds.java +++ b/src/java/org/tensorics/core/tensorbacked/ProxiedInterfaceTensorbackeds.java @@ -1,13 +1,12 @@ package org.tensorics.core.tensorbacked; import org.tensorics.core.tensor.Tensor; +import org.tensorics.core.util.JavaVersions; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import static java.util.Objects.requireNonNull; @@ -22,7 +21,7 @@ public static > T create(Class tensorbackedType, throw new IllegalArgumentException("The given tensorbacked type '" + tensorbackedType + "' is not an interface! Therefore, it cannot be instantiated by proxying!"); } - return (T) Proxy.newProxyInstance(Tensorbacked.class.getClassLoader(), new Class[] { tensorbackedType }, + return (T) Proxy.newProxyInstance(Tensorbacked.class.getClassLoader(), new Class[]{tensorbackedType}, new DelegatingInvocationHandler<>(tensor, tensorbackedType)); } @@ -39,11 +38,8 @@ public DelegatingInvocationHandler(Tensor delegate, Class intfc) { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.isDefault()) { - return MethodHandles.lookup() - .findSpecial(intfc, method.getName(), - MethodType.methodType(method.getReturnType(), method.getParameterTypes()), intfc) - .bindTo(proxy).invokeWithArguments(args); - + MethodCallHandler callHandler = callHandlerFor(intfc, method); + return callHandler.invoke(proxy, args); } if (Tensorbacked.class.equals(method.getDeclaringClass()) && "tensor".equals(method.getName()) @@ -60,35 +56,29 @@ private interface MethodCallHandler { Object invoke(Object proxy, Object[] args) throws Throwable; } - @FunctionalInterface - private interface MethodInterpreter extends InvocationHandler { - @Override - default Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - MethodCallHandler handler = interpret(method); - return handler.invoke(proxy, args); - } - - MethodCallHandler interpret(Method method); + private static MethodCallHandler callHandlerFor(Class intfc, Method method) { + MethodHandle handle = getMethodHandle(intfc, method); + return (proxy, args) -> handle.bindTo(proxy).invokeWithArguments(args); } - private static class DefaultMethodCallHandler { - - private DefaultMethodCallHandler() { - } - - private static final ConcurrentMap cache = new ConcurrentHashMap<>(); - - private static MethodCallHandler forMethod(Method method) { - return cache.computeIfAbsent(method, m -> { - MethodHandle handle = getMethodHandle(m); - return (proxy, args) -> handle.bindTo(proxy).invokeWithArguments(args); - }); - } - - private static MethodHandle getMethodHandle(Method method) { - Class declaringClass = method.getDeclaringClass(); + private static MethodHandle getMethodHandle(Class intfc, Method method) { + Class declaringClass = method.getDeclaringClass(); + /* + XXX: This is not too nice: For some reason, the original code (java) 8 did not run in java 11 anymore. + And vice versa ... what the exact border is where it stopped working was not full checked. + So potentially more research would be needed here. + */ + if (JavaVersions.isAtLeastJava11()) { + try { + return MethodHandles.lookup() + .findSpecial(intfc, method.getName(), + MethodType.methodType(method.getReturnType(), method.getParameterTypes()), intfc); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } else { try { Constructor constructor = MethodHandles.Lookup.class .getDeclaredConstructor(Class.class, int.class); diff --git a/src/java/org/tensorics/core/util/JavaVersions.java b/src/java/org/tensorics/core/util/JavaVersions.java new file mode 100644 index 000000000..ab7d1b40d --- /dev/null +++ b/src/java/org/tensorics/core/util/JavaVersions.java @@ -0,0 +1,20 @@ +package org.tensorics.core.util; + +/** + * Contains utility methods related to java versions + */ +public final class JavaVersions { + + private JavaVersions() { + throw new UnsupportedOperationException("only static methods"); + } + + /** + * Determines if the actual running jvm is at least java 11 + * + * @return true if it is java 11 or higher, false otherwise + */ + public static boolean isAtLeastJava11() { + return "11".compareTo(System.getProperty("java.version")) <= 0; + } +} diff --git a/src/test/org/tensorics/core/util/JavaVersionsTries.java b/src/test/org/tensorics/core/util/JavaVersionsTries.java new file mode 100644 index 000000000..392921de3 --- /dev/null +++ b/src/test/org/tensorics/core/util/JavaVersionsTries.java @@ -0,0 +1,16 @@ +package org.tensorics.core.util; + +import org.junit.Test; + +public class JavaVersionsTries { + + @Test + public void testJavaVersion() { + System.out.println(System.getProperty("java.version")); + System.out.println("11".compareTo("1.8") <= 0); + System.out.println("11".compareTo("11") <= 0); + System.out.println("11".compareTo("12") <= 0); + System.out.println(JavaVersions.isAtLeastJava11()); + } + +}