diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/func/LambdaFactory.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/func/LambdaFactory.java index 3c91c412a..519288cf3 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/lang/func/LambdaFactory.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/func/LambdaFactory.java @@ -16,8 +16,11 @@ import org.dromara.hutool.core.exceptions.UtilException; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.mutable.MutableEntry; import org.dromara.hutool.core.map.WeakConcurrentMap; -import org.dromara.hutool.core.reflect.*; -import org.dromara.hutool.core.reflect.*; +import org.dromara.hutool.core.reflect.MethodHandleUtil; +import org.dromara.hutool.core.reflect.MethodUtil; +import org.dromara.hutool.core.reflect.ModifierUtil; +import org.dromara.hutool.core.reflect.ReflectUtil; +import org.dromara.hutool.core.reflect.lookup.LookupUtil; import java.io.Serializable; import java.lang.invoke.*; @@ -103,7 +106,7 @@ public class LambdaFactory { final boolean isSerializable = Serializable.class.isAssignableFrom(functionInterfaceType); final Method invokeMethod = abstractMethods.get(0); - final MethodHandles.Lookup caller = LookupFactory.lookup(executable.getDeclaringClass()); + final MethodHandles.Lookup caller = LookupUtil.lookup(executable.getDeclaringClass()); final String invokeName = invokeMethod.getName(); final MethodType invokedType = methodType(functionInterfaceType); final MethodType samMethodType = methodType(invokeMethod.getReturnType(), invokeMethod.getParameterTypes()); diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/LookupFactory.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/LookupFactory.java deleted file mode 100644 index 95e255d39..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/LookupFactory.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2023 looly(loolly@aliyun.com) - * Hutool is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -package org.dromara.hutool.core.reflect; - -import org.dromara.hutool.core.exceptions.UtilException; -import org.dromara.hutool.core.lang.caller.CallerUtil; -import org.dromara.hutool.core.util.JdkUtil; - -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * {@link MethodHandles.Lookup}工厂,用于创建{@link MethodHandles.Lookup}对象
- * {@link MethodHandles.Lookup}是一个方法句柄查找对象,用于在指定类中查找符合给定方法名称、方法类型的方法句柄。 - * - *

- * jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial - * 时会出现权限不够问题,抛出"no private access for invokespecial"异常,因此针对JDK8及JDK9+分别封装lookup方法。 - *

- * - *

- * 参考: - *

https://blog.csdn.net/u013202238/article/details/108687086

- * - * @author looly - * @since 5.7.7 - */ -public class LookupFactory { - - private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED - | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC; - - private static Method privateLookupInMethod; - private static Constructor jdk8LookupConstructor; - - static { - if(JdkUtil.IS_JDK8){ - // jdk8 这种方式其实也适用于jdk9及以上的版本,但是上面优先,可以避免 jdk9 反射警告 - jdk8LookupConstructor = createJdk8LookupConstructor(); - } else { - // jdk9+ 开始提供的java.lang.invoke.MethodHandles.privateLookupIn方法 - privateLookupInMethod = createJdk9PrivateLookupInMethod(); - } - } - - /** - * jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial - * 时会出现权限不够问题,抛出"no private access for invokespecial"异常,因此针对JDK8及JDK9+分别封装lookup方法。 - * - * @return {@link MethodHandles.Lookup} - */ - public static MethodHandles.Lookup lookup() { - return lookup(CallerUtil.getCaller()); - } - - /** - * jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial - * 时会出现权限不够问题,抛出"no private access for invokespecial"异常,因此针对JDK8及JDK9+分别封装lookup方法。 - * - * @param callerClass 被调用的类或接口 - * @return {@link MethodHandles.Lookup} - */ - public static MethodHandles.Lookup lookup(final Class callerClass) { - //使用反射,因为当前jdk可能不是java9或以上版本 - if (privateLookupInMethod != null) { - try { - return (MethodHandles.Lookup) privateLookupInMethod.invoke(MethodHandles.class, callerClass, MethodHandles.lookup()); - } catch (final IllegalAccessException | InvocationTargetException e) { - throw new UtilException(e); - } - } - //jdk 8 - try { - return jdk8LookupConstructor.newInstance(callerClass, ALLOWED_MODES); - } catch (final Exception e) { - throw new IllegalStateException("no 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.", e); - } - } - - @SuppressWarnings("JavaReflectionMemberAccess") - private static Method createJdk9PrivateLookupInMethod(){ - try { - return MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class); - } catch (final NoSuchMethodException e) { - //可能是jdk9 以下版本 - throw new IllegalStateException( - "There is no 'privateLookupIn(Class, Lookup)' method in java.lang.invoke.MethodHandles.", e); - } - } - - private static Constructor createJdk8LookupConstructor(){ - final Constructor constructor; - try { - constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class); - } catch (final NoSuchMethodException e) { - //可能是jdk8 以下版本 - throw new IllegalStateException( - "There is no 'Lookup(Class, int)' constructor in java.lang.invoke.MethodHandles.", e); - } - constructor.setAccessible(true); - return constructor; - } -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/MethodHandleUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/MethodHandleUtil.java index 61d8d9282..25c53d152 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/MethodHandleUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/MethodHandleUtil.java @@ -14,6 +14,7 @@ package org.dromara.hutool.core.reflect; import org.dromara.hutool.core.exceptions.UtilException; import org.dromara.hutool.core.lang.Assert; +import org.dromara.hutool.core.reflect.lookup.LookupUtil; import org.dromara.hutool.core.text.StrUtil; import java.lang.invoke.MethodHandle; @@ -51,9 +52,9 @@ public class MethodHandleUtil { public static MethodHandle unreflect(final Member methodOrConstructor) { try { if (methodOrConstructor instanceof Method) { - return LookupFactory.lookup().unreflect((Method) methodOrConstructor); + return LookupUtil.lookup().unreflect((Method) methodOrConstructor); } else { - return LookupFactory.lookup().unreflectConstructor((Constructor) methodOrConstructor); + return LookupUtil.lookup().unreflectConstructor((Constructor) methodOrConstructor); } } catch (final IllegalAccessException e) { throw new UtilException(e); @@ -80,7 +81,7 @@ public class MethodHandleUtil { } MethodHandle handle = null; - final MethodHandles.Lookup lookup = LookupFactory.lookup(callerClass); + final MethodHandles.Lookup lookup = LookupUtil.lookup(callerClass); try { handle = lookup.findVirtual(callerClass, name, type); } catch (final IllegalAccessException | NoSuchMethodException ignore) { @@ -129,7 +130,7 @@ public class MethodHandleUtil { * @return 构造方法句柄 */ public static MethodHandle findConstructor(final Class callerClass, final MethodType type) { - final MethodHandles.Lookup lookup = LookupFactory.lookup(callerClass); + final MethodHandles.Lookup lookup = LookupUtil.lookup(callerClass); try { return lookup.findConstructor(callerClass, type); } catch (final NoSuchMethodException e) { @@ -252,7 +253,7 @@ public class MethodHandleUtil { public static T invoke(final boolean isSpecial, final Object obj, final Method method, final Object... args) { Assert.notNull(method, "Method must be not null!"); final Class declaringClass = method.getDeclaringClass(); - final MethodHandles.Lookup lookup = LookupFactory.lookup(declaringClass); + final MethodHandles.Lookup lookup = LookupUtil.lookup(declaringClass); try { MethodHandle handle = isSpecial ? lookup.unreflectSpecial(method, declaringClass) : lookup.unreflect(method); diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/ConstructorLookupFactory.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/ConstructorLookupFactory.java new file mode 100644 index 000000000..82d3ef6bf --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/ConstructorLookupFactory.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.reflect.lookup; + +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; + +/** + * jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}
+ * 在调用findSpecial和unreflectSpecial时会出现权限不够问题,抛出"no private access for invokespecial"异常
+ * 所以通过反射创建MethodHandles.Lookup解决该问题。 + *

+ * 参考:https://blog.csdn.net/u013202238/article/details/108687086 + * + * @author looly + * @since 6.0.0 + */ +public class ConstructorLookupFactory implements LookupFactory { + + private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED + | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC; + + private final Constructor lookupConstructor; + + /** + * 构造 + */ + public ConstructorLookupFactory() { + this.lookupConstructor = createLookupConstructor(); + } + + @Override + public MethodHandles.Lookup lookup(final Class callerClass) { + try { + return lookupConstructor.newInstance(callerClass, ALLOWED_MODES); + } catch (final Exception e) { + throw new IllegalStateException("no 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.", e); + } + } + + private static Constructor createLookupConstructor() { + final Constructor constructor; + try { + constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class); + } catch (final NoSuchMethodException e) { + //可能是jdk8 以下版本 + throw new IllegalStateException( + "There is no 'Lookup(Class, int)' constructor in java.lang.invoke.MethodHandles.", e); + } + constructor.setAccessible(true); + return constructor; + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/LookupFactory.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/LookupFactory.java new file mode 100644 index 000000000..d90f89c9e --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/LookupFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.reflect.lookup; + +import java.lang.invoke.MethodHandles; + +/** + * {@link MethodHandles.Lookup}方法工厂,用于创建{@link MethodHandles.Lookup}对象
+ * {@link MethodHandles.Lookup}是一个方法句柄查找对象,用于在指定类中查找符合给定方法名称、方法类型的方法句柄。 + * + *

+ * 参考:https://blog.csdn.net/u013202238/article/details/108687086 + *

+ * + * @author looly + * @since 6.0.0 + */ +public interface LookupFactory { + + /** + * jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial + * 时会出现权限不够问题,抛出"no private access for invokespecial"异常,因此针对JDK8及JDK9+分别封装lookup方法。 + * + * @param callerClass 被调用的类或接口 + * @return {@link MethodHandles.Lookup} + */ + MethodHandles.Lookup lookup(final Class callerClass); +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/LookupUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/LookupUtil.java new file mode 100644 index 000000000..e4c20892d --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/LookupUtil.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.reflect.lookup; + +import org.dromara.hutool.core.lang.caller.CallerUtil; +import org.dromara.hutool.core.util.JdkUtil; + +import java.lang.invoke.MethodHandles; + +/** + * {@link MethodHandles.Lookup}工厂工具,用于创建{@link MethodHandles.Lookup}对象
+ * {@link MethodHandles.Lookup}是一个方法句柄查找对象,用于在指定类中查找符合给定方法名称、方法类型的方法句柄。 + * + *

+ * jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial + * 时会出现权限不够问题,抛出"no private access for invokespecial"异常,因此针对JDK8及JDK9+分别封装lookup方法。 + *

+ * + *

+ * 参考:https://blog.csdn.net/u013202238/article/details/108687086 + * + * @author looly + * @since 6.0.0 + */ +public class LookupUtil { + + private static final LookupFactory factory; + + static { + if (JdkUtil.IS_JDK8) { + factory = new ConstructorLookupFactory(); + } else { + factory = new MethodLookupFactory(); + } + } + + /** + * jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial + * 时会出现权限不够问题,抛出"no private access for invokespecial"异常,因此针对JDK8及JDK9+分别封装lookup方法。 + * + * @return {@link MethodHandles.Lookup} + */ + public static MethodHandles.Lookup lookup() { + return lookup(CallerUtil.getCaller()); + } + + /** + * jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial + * 时会出现权限不够问题,抛出"no private access for invokespecial"异常,因此针对JDK8及JDK9+分别封装lookup方法。 + * + * @param callerClass 被调用的类或接口 + * @return {@link MethodHandles.Lookup} + */ + public static MethodHandles.Lookup lookup(final Class callerClass) { + return factory.lookup(callerClass); + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/MethodLookupFactory.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/MethodLookupFactory.java new file mode 100644 index 000000000..564c0c225 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/MethodLookupFactory.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.reflect.lookup; + +import org.dromara.hutool.core.exceptions.UtilException; + +import java.lang.invoke.MethodHandles; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * jdk11中直接调用MethodHandles.lookup()获取到的MethodHandles.Lookup只能对接口类型才会权限获取方法的方法句柄MethodHandle。 + * 如果是普通类型Class,需要使用jdk9开始提供的 MethodHandles#privateLookupIn(java.lang.Class, java.lang.invoke.MethodHandles.Lookup)方法. + *

+ * 参考:https://blog.csdn.net/u013202238/article/details/108687086 + * + * @author looly + * @since 6.0.0 + */ +public class MethodLookupFactory implements LookupFactory { + + private final Method privateLookupInMethod; + + /** + * 构造 + */ + public MethodLookupFactory() { + this.privateLookupInMethod = createJdk9PrivateLookupInMethod(); + } + + @Override + public MethodHandles.Lookup lookup(final Class callerClass) { + try { + return (MethodHandles.Lookup) privateLookupInMethod.invoke(MethodHandles.class, callerClass, MethodHandles.lookup()); + } catch (final IllegalAccessException | InvocationTargetException e) { + throw new UtilException(e); + } + } + + @SuppressWarnings("JavaReflectionMemberAccess") + private static Method createJdk9PrivateLookupInMethod() { + try { + return MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class); + } catch (final NoSuchMethodException e) { + //可能是jdk9 以下版本 + throw new IllegalStateException( + "There is no 'privateLookupIn(Class, Lookup)' method in java.lang.invoke.MethodHandles.", e); + } + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/package-info.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/package-info.java new file mode 100644 index 000000000..c96400540 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/lookup/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * {@link java.lang.invoke.MethodHandles.Lookup} 创建封装
+ *

+ * jdk8中如果直接调用{@link java.lang.invoke.MethodHandles#lookup()}获取到的{@link java.lang.invoke.MethodHandles.Lookup}在调用findSpecial和unreflectSpecial + * 时会出现权限不够问题,抛出"no private access for invokespecial"异常,因此针对JDK8及JDK9+分别封装lookup方法。 + *

+ * + *

+ * 参考: + *

https://blog.csdn.net/u013202238/article/details/108687086

+ */ +package org.dromara.hutool.core.reflect.lookup;