浏览代码

FilterInvocation Support Default Methods on HttpServletRequest

Closes gh-8566
Rob Winch 5 年之前
父节点
当前提交
dc514b369e
共有 1 个文件被更改,包括 41 次插入1 次删除
  1. 41 1
      web/src/main/java/org/springframework/security/web/FilterInvocation.java

+ 41 - 1
web/src/main/java/org/springframework/security/web/FilterInvocation.java

@@ -16,6 +16,10 @@
 
 package org.springframework.security.web;
 
+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.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
@@ -231,7 +235,43 @@ class DummyRequest extends HttpServletRequestWrapper {
 }
 
 final class UnsupportedOperationExceptionInvocationHandler implements InvocationHandler {
-	public Object invoke(Object proxy, Method method, Object[] args) {
+	private static final float JAVA_VERSION = Float.parseFloat(System.getProperty("java.class.version", "52"));
+
+	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+		if (method.isDefault()) {
+			return invokeDefaultMethod(proxy, method, args);
+		}
 		throw new UnsupportedOperationException(method + " is not supported");
 	}
+
+	private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
+		if (isJdk8OrEarlier()) {
+			return invokeDefaultMethodForJdk8(proxy, method, args);
+		}
+		return MethodHandles.lookup()
+				.findSpecial(
+					method.getDeclaringClass(),
+					method.getName(),
+					MethodType.methodType(method.getReturnType(), new Class[0]),
+					method.getDeclaringClass()
+				)
+				.bindTo(proxy)
+				.invokeWithArguments(args);
+	}
+
+	private Object invokeDefaultMethodForJdk8(Object proxy, Method method, Object[] args) throws Throwable {
+		Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class);
+		constructor.setAccessible(true);
+
+		Class<?> clazz = method.getDeclaringClass();
+		return constructor.newInstance(clazz)
+				.in(clazz)
+				.unreflectSpecial(method, clazz)
+				.bindTo(proxy)
+				.invokeWithArguments(args);
+	}
+
+	private boolean isJdk8OrEarlier() {
+		return JAVA_VERSION <= 52;
+	}
 }