diff --git a/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java b/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java index 60b13c620..79cbdb373 100644 --- a/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java +++ b/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,10 @@ */ package org.springframework.data.projection; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -27,6 +30,7 @@ import org.springframework.aop.ProxyMethodInvocation; * Method interceptor to invoke default methods on the repository proxy. * * @author Oliver Gierke + * @author Jens Schauder */ public class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor { @@ -36,15 +40,27 @@ public class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor * Creates a new {@link DefaultMethodInvokingMethodInterceptor}. */ public DefaultMethodInvokingMethodInterceptor() { + constructor = tryToGetLookupConstructor(); + } + + private static Constructor tryToGetLookupConstructor() { try { - this.constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class); - if (!constructor.isAccessible()) { - constructor.setAccessible(true); + Constructor accessibleConstructor = Lookup.class.getDeclaredConstructor(Class.class); + + if (!accessibleConstructor.isAccessible()) { + accessibleConstructor.setAccessible(true); + } + + return accessibleConstructor; + } catch (Exception ex) { + // this is the signal that we are on Java 9 and can't use the accessible constructor approach. + if (ex.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) { + return null; + } else { + throw new IllegalStateException(ex); } - } catch (Exception o_O) { - throw new IllegalStateException(o_O); } } @@ -65,7 +81,24 @@ public class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor Class declaringClass = method.getDeclaringClass(); Object proxy = ((ProxyMethodInvocation) invocation).getProxy(); - return constructor.newInstance(declaringClass).unreflectSpecial(method, declaringClass).bindTo(proxy) - .invokeWithArguments(arguments); + return getMethodHandle(method, arguments, declaringClass, proxy).bindTo(proxy).invokeWithArguments(arguments); + } + + private MethodHandle getMethodHandle(Method method, Object[] arguments, Class declaringClass, Object proxy) + throws Throwable { + + if (constructor != null) { + // java 8 variant + return constructor.newInstance(declaringClass).unreflectSpecial(method, declaringClass); + } + + // java 9 variant + return MethodHandles.lookup() // + .findSpecial( // + method.getDeclaringClass(), // + method.getName(), // + MethodType.methodType(method.getReturnType(), method.getParameterTypes()), // + method.getDeclaringClass() // + ); } }