This commit is contained in:
Looly 2023-03-24 18:12:50 +08:00
parent 01f94defd2
commit 3b2160d296
6 changed files with 104 additions and 41 deletions

View File

@ -16,13 +16,14 @@ public class FunctionPool {
/**
* 通过{@code String(char[] value, boolean share)}这个内部构造生成一个Lambda函数<br>
* 此函数通过传入char[]实现zero-copy的String创建效率很高但是要求传入的char[]不可以在其他地方修改
* 此函数通过传入char[]实现zero-copy的String创建效率很高但是要求传入的char[]不可以在其他地方修改<br>
* 此函数只支持JKDK8
*/
public static final BiFunction<char[], Boolean, String> STRING_CREATOR;
public static final BiFunction<char[], Boolean, String> STRING_CREATOR_JDK8;
static {
final Constructor<String> constructor = ConstructorUtil.getConstructor(String.class, char[].class, boolean.class);
STRING_CREATOR = LambdaFactory.build(BiFunction.class, constructor);
STRING_CREATOR_JDK8 = LambdaFactory.build(BiFunction.class, constructor);
}
/**
@ -33,6 +34,6 @@ public class FunctionPool {
* @return String
*/
public static String createString(final char[] value) {
return STRING_CREATOR.apply(value, true);
return STRING_CREATOR_JDK8.apply(value, true);
}
}

View File

@ -1,6 +1,7 @@
package cn.hutool.core.reflect;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.util.JdkUtil;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
@ -24,30 +25,16 @@ public class LookupFactory {
private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
| MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC;
private static Constructor<MethodHandles.Lookup> java8LookupConstructor;
private static Method privateLookupInMethod;
private static Constructor<MethodHandles.Lookup> jdk8LookupConstructor;
static {
//先查询jdk9 开始提供的java.lang.invoke.MethodHandles.privateLookupIn方法,
//如果没有说明是jdk8的版本.(不考虑jdk8以下版本)
try {
//noinspection JavaReflectionMemberAccess
privateLookupInMethod = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
} catch (final NoSuchMethodException ignore) {
//ignore
}
//jdk8
//这种方式其实也适用于jdk9及以上的版本,但是上面优先,可以避免 jdk9 反射警告
if (privateLookupInMethod == null) {
try {
java8LookupConstructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
java8LookupConstructor.setAccessible(true);
} catch (final NoSuchMethodException e) {
//可能是jdk8 以下版本
throw new IllegalStateException(
"There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.", e);
}
if(JdkUtil.isJdk8()){
// jdk8 这种方式其实也适用于jdk9及以上的版本,但是上面优先,可以避免 jdk9 反射警告
jdk8LookupConstructor = createJdk8LookupConstructor();
} else {
// jdk9+ 开始提供的java.lang.invoke.MethodHandles.privateLookupIn方法
privateLookupInMethod = createJdk9PrivateLookupInMethod();
}
}
@ -69,9 +56,33 @@ public class LookupFactory {
}
//jdk 8
try {
return java8LookupConstructor.newInstance(callerClass, ALLOWED_MODES);
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<MethodHandles.Lookup> createJdk8LookupConstructor(){
final Constructor<MethodHandles.Lookup> 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;
}
}

View File

@ -22,17 +22,6 @@ import java.lang.reflect.Method;
*/
public class MethodHandleUtil {
/**
* 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 LookupFactory.lookup(callerClass);
}
/**
* 查找指定方法的方法句柄<br>
* 此方法只会查找
@ -53,7 +42,7 @@ public class MethodHandleUtil {
}
MethodHandle handle = null;
final MethodHandles.Lookup lookup = lookup(callerClass);
final MethodHandles.Lookup lookup = LookupFactory.lookup(callerClass);
try {
handle = lookup.findVirtual(callerClass, name, type);
} catch (final IllegalAccessException | NoSuchMethodException ignore) {
@ -102,7 +91,7 @@ public class MethodHandleUtil {
* @return 构造方法句柄
*/
public static MethodHandle findConstructor(final Class<?> callerClass, final MethodType type) {
final MethodHandles.Lookup lookup = lookup(callerClass);
final MethodHandles.Lookup lookup = LookupFactory.lookup(callerClass);
try {
return lookup.findConstructor(callerClass, type);
} catch (final NoSuchMethodException e) {
@ -208,7 +197,7 @@ public class MethodHandleUtil {
public static <T> 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 = lookup(declaringClass);
final MethodHandles.Lookup lookup = LookupFactory.lookup(declaringClass);
try {
MethodHandle handle = isSpecial ? lookup.unreflectSpecial(method, declaringClass)
: lookup.unreflect(method);

View File

@ -0,0 +1,50 @@
package cn.hutool.core.util;
import cn.hutool.core.text.StrUtil;
/**
* JDK相关工具类包括判断JDK版本等<br>
* 工具部分方法来自fastjson2的JDKUtils
*
* @author fastjson, looly
*/
public class JdkUtil {
/**
* JDK版本
*/
public static final int JVM_VERSION;
static {
JVM_VERSION = _getJvmVersion();
}
/**
* 是否JDK8
*
* @return 是否JDK8
*/
public static boolean isJdk8() {
return 8 == JVM_VERSION;
}
/**
* 根据{@code java.specification.version}属性值获取版本号
*
* @return 版本号
*/
private static int _getJvmVersion() {
int jvmVersion = -1;
String javaSpecVer = System.getProperty("java.specification.version");
if (StrUtil.isNotBlank(javaSpecVer)) {
if (javaSpecVer.startsWith("1.")) {
javaSpecVer = javaSpecVer.substring(2);
}
if (javaSpecVer.indexOf('.') == -1) {
jvmVersion = Integer.parseInt(javaSpecVer);
}
}
return jvmVersion;
}
}

View File

@ -0,0 +1,12 @@
package cn.hutool.core.util;
import org.junit.Assert;
import org.junit.Test;
public class JdkUtilTest {
@Test
public void jvmVersionTest() {
final int jvmVersion = JdkUtil.JVM_VERSION;
Assert.assertTrue(jvmVersion >= 8);
}
}

View File

@ -44,7 +44,7 @@
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.24</version>
<version>2.0.25</version>
<scope>test</scope>
</dependency>
</dependencies>