This commit is contained in:
Looly 2023-04-21 01:09:02 +08:00
parent 9bbfdca820
commit 32e8caccdd
14 changed files with 86 additions and 512 deletions

View File

@ -31,9 +31,6 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static java.lang.invoke.LambdaMetafactory.FLAG_SERIALIZABLE;
import static java.lang.invoke.MethodType.methodType;
/**
* 以类似反射的方式动态创建Lambda在性能上有一定优势同时避免每次调用Lambda时创建匿名内部类
* TODO JDK9+存在兼容问题
@ -65,8 +62,8 @@ public class LambdaFactory {
* @param methodClass 声明方法的类的类型
* @param methodName 方法名称
* @param paramTypes 方法参数数组
* @param <F> Function类型
* @return 接受Lambda的函数式接口对象
* @param <F> Function类型
*/
public static <F> F build(final Class<F> functionInterfaceType, final Class<?> methodClass, final String methodName, final Class<?>... paramTypes) {
return build(functionInterfaceType, MethodUtil.getMethod(methodClass, methodName, paramTypes));
@ -77,7 +74,7 @@ public class LambdaFactory {
* 调用函数相当于执行对应的方法或构造
*
* @param functionInterfaceType 接受Lambda的函数式接口类型
* @param executable 方法对象支持构造器
* @param executable 方法对象支持构造器
* @param <F> Function类型
* @return 接受Lambda的函数式接口对象
*/
@ -88,8 +85,8 @@ public class LambdaFactory {
final MutableEntry<Class<?>, Executable> cacheKey = new MutableEntry<>(functionInterfaceType, executable);
return (F) CACHE.computeIfAbsent(cacheKey, key -> {
final List<Method> abstractMethods = Arrays.stream(functionInterfaceType.getMethods())
.filter(ModifierUtil::isAbstract)
.collect(Collectors.toList());
.filter(ModifierUtil::isAbstract)
.collect(Collectors.toList());
Assert.equals(abstractMethods.size(), 1, "不支持非函数式接口");
ReflectUtil.setAccessible(executable);
@ -107,27 +104,27 @@ public class LambdaFactory {
final Method invokeMethod = abstractMethods.get(0);
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());
final MethodType invokedType = MethodType.methodType(functionInterfaceType);
final MethodType samMethodType = MethodType.methodType(invokeMethod.getReturnType(), invokeMethod.getParameterTypes());
try {
final CallSite callSite = isSerializable ?
LambdaMetafactory.altMetafactory(
caller,
invokeName,
invokedType,
samMethodType,
methodHandle,
instantiatedMethodType,
FLAG_SERIALIZABLE
) :
LambdaMetafactory.metafactory(
caller,
invokeName,
invokedType,
samMethodType,
methodHandle,
instantiatedMethodType
);
LambdaMetafactory.altMetafactory(
caller,
invokeName,
invokedType,
samMethodType,
methodHandle,
instantiatedMethodType,
LambdaMetafactory.FLAG_SERIALIZABLE
) :
LambdaMetafactory.metafactory(
caller,
invokeName,
invokedType,
samMethodType,
methodHandle,
instantiatedMethodType
);
//noinspection unchecked
return (F) callSite.getTarget().invoke();
} catch (final Throwable e) {

View File

@ -89,20 +89,16 @@ public class ConstructorUtil {
// --------------------------------------------------------------------------------------------------------- newInstance
/**
* 实例化对象
* 实例化对象<br>
* 类必须有空构造函数
*
* @param <T> 对象类型
* @param clazz 类名
* @return 对象
* @throws UtilException 包装各类异常
*/
@SuppressWarnings("unchecked")
public static <T> T newInstance(final String clazz) throws UtilException {
try {
return (T) ClassLoaderUtil.loadClass(clazz).newInstance();
} catch (final Exception e) {
throw new UtilException(e, "Instance class [{}] error!", clazz);
}
return newInstance(ClassLoaderUtil.loadClass(clazz));
}
/**
@ -117,7 +113,7 @@ public class ConstructorUtil {
public static <T> T newInstance(final Class<T> clazz, final Object... params) throws UtilException {
if (ArrayUtil.isEmpty(params)) {
final Constructor<T> constructor = getConstructor(clazz);
if(null == constructor){
if (null == constructor) {
throw new UtilException("No constructor for [{}]", clazz);
}
try {

View File

@ -354,8 +354,8 @@
</dependency>
<dependency>
<groupId>com.mayabot.mynlp</groupId>
<artifactId>mynlp-segment</artifactId>
<version>3.0.2</version>
<artifactId>mynlp-all</artifactId>
<version>4.0.0</version>
<optional>true</optional>
</dependency>
<!-- Spring Boot -->
@ -422,6 +422,13 @@
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.14.4</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- 验证工具可选依赖 begin -->
<dependency>
<groupId>jakarta.validation</groupId>
@ -463,6 +470,10 @@
<artifactId>junit-jupiter</artifactId>
<groupId>org.junit.jupiter</groupId>
</exclusion>
<exclusion>
<artifactId>json-path</artifactId>
<groupId>com.jayway.jsonpath</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>

View File

@ -1,72 +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.extra.aop.interceptor;
import org.dromara.hutool.extra.aop.aspects.Aspect;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Cglib实现的动态代理切面
*
* @author looly, ted.L
*/
public class CglibInterceptor implements MethodInterceptor, Serializable {
private static final long serialVersionUID = 1L;
private final Object target;
private final Aspect aspect;
/**
* 构造
*
* @param target 被代理对象
* @param aspect 切面实现
*/
public CglibInterceptor(final Object target, final Aspect aspect) {
this.target = target;
this.aspect = aspect;
}
public Object getTarget() {
return this.target;
}
@Override
public Object intercept(final Object obj, final Method method, final Object[] args, final MethodProxy proxy) throws Throwable {
final Object target = this.target;
Object result = null;
// 开始前回调
if (aspect.before(target, method, args)) {
try {
// result = proxy.invokeSuper(obj, args);
result = proxy.invoke(target, args);
} catch (final InvocationTargetException e) {
// 异常回调只捕获业务代码导致的异常而非反射导致的异常
if (aspect.afterException(target, method, args, e.getTargetException())) {
throw e;
}
}
}
// 结束执行回调
if (aspect.after(target, method, args, result)) {
return result;
}
return null;
}
}

View File

@ -16,7 +16,6 @@ import org.dromara.hutool.core.reflect.ModifierUtil;
import org.dromara.hutool.core.reflect.ReflectUtil;
import org.dromara.hutool.extra.aop.aspects.Aspect;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@ -27,12 +26,9 @@ import java.lang.reflect.Method;
* @author Looly
* @author ted.L
*/
public class JdkInterceptor implements InvocationHandler, Serializable {
public class JdkInterceptor extends SimpleInterceptor implements InvocationHandler {
private static final long serialVersionUID = 1L;
private final Object target;
private final Aspect aspect;
/**
* 构造
*
@ -40,17 +36,7 @@ public class JdkInterceptor implements InvocationHandler, Serializable {
* @param aspect 切面实现
*/
public JdkInterceptor(final Object target, final Aspect aspect) {
this.target = target;
this.aspect = aspect;
}
/**
* 获取目标对象
*
* @return 目标对象
*/
public Object getTarget() {
return this.target;
super(target, aspect);
}
@SuppressWarnings("SuspiciousInvocationHandlerImplementation")

View File

@ -10,27 +10,42 @@
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.extra.aop.proxy;
package org.dromara.hutool.extra.aop.interceptor;
import org.dromara.hutool.extra.aop.aspects.Aspect;
import org.dromara.hutool.extra.aop.interceptor.CglibInterceptor;
import net.sf.cglib.proxy.Enhancer;
import java.io.Serializable;
/**
* 基于Cglib的切面代理工厂
* 简单拦截器保存了被拦截的对象和Aspect实现
*
* @author looly
* @since 6.0.0
*/
public class CglibProxyFactory implements ProxyFactory {
public class SimpleInterceptor implements Serializable {
private static final long serialVersionUID = 1L;
@Override
@SuppressWarnings("unchecked")
public <T> T proxy(final T target, final Aspect aspect) {
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new CglibInterceptor(target, aspect));
return (T) enhancer.create();
protected final Object target;
protected final Aspect aspect;
/**
* 构造
*
* @param target 被代理对象
* @param aspect 切面实现
*/
public SimpleInterceptor(final Object target, final Aspect aspect) {
this.target = target;
this.aspect = aspect;
}
/**
* 获取目标对象
*
* @return 目标对象
*/
public Object getTarget() {
return this.target;
}
}

View File

@ -16,21 +16,18 @@ import org.dromara.hutool.extra.aop.aspects.Aspect;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Spring-cglib实现的动态代理切面
* Spring-cglib实现的动态代理切面<br>
* 只用于JDK8
*
* @author looly
*/
public class SpringCglibInterceptor implements MethodInterceptor, Serializable {
public class SpringCglibInterceptor extends SimpleInterceptor implements MethodInterceptor {
private static final long serialVersionUID = 1L;
private final Object target;
private final Aspect aspect;
/**
* 构造
*
@ -38,17 +35,7 @@ public class SpringCglibInterceptor implements MethodInterceptor, Serializable {
* @param aspect 切面实现
*/
public SpringCglibInterceptor(final Object target, final Aspect aspect) {
this.target = target;
this.aspect = aspect;
}
/**
* 获得目标对象
*
* @return 目标对象
*/
public Object getTarget() {
return this.target;
super(target, aspect);
}
@Override
@ -58,7 +45,6 @@ public class SpringCglibInterceptor implements MethodInterceptor, Serializable {
// 开始前回调
if (aspect.before(target, method, args)) {
try {
// result = proxy.invokeSuper(obj, args);
result = proxy.invoke(target, args);
} catch (final InvocationTargetException e) {
// 异常回调只捕获业务代码导致的异常而非反射导致的异常

View File

@ -1,287 +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.extra.script;
import org.dromara.hutool.core.exceptions.UtilException;
import org.dromara.hutool.core.map.WeakConcurrentMap;
import org.dromara.hutool.core.text.StrUtil;
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
/**
* 脚本工具类<br>
* 此脚本工具为javax.script的薄封装脚本执行取决于脚本引擎<br>
* 使用此脚本工具用户需要自行检查脚本中可能存在的风险代码以避免脚本执行漏洞
*
* @author Looly
*/
public class ScriptUtil {
private static final ScriptEngineManager MANAGER = new ScriptEngineManager();
private static final WeakConcurrentMap<String, ScriptEngine> CACHE = new WeakConcurrentMap<>();
/**
* 获得单例的{@link ScriptEngine} 实例
*
* @param nameOrExtOrMime 脚本名称
* @return {@link ScriptEngine} 实例
*/
public static ScriptEngine getScript(final String nameOrExtOrMime) {
return CACHE.computeIfAbsent(nameOrExtOrMime, (key) -> createScript(nameOrExtOrMime));
}
/**
* 创建 {@link ScriptEngine} 实例
*
* @param nameOrExtOrMime 脚本名称
* @return {@link ScriptEngine} 实例
* @since 5.2.6
*/
public static ScriptEngine createScript(final String nameOrExtOrMime) {
ScriptEngine engine = MANAGER.getEngineByName(nameOrExtOrMime);
if (null == engine) {
engine = MANAGER.getEngineByExtension(nameOrExtOrMime);
}
if (null == engine) {
engine = MANAGER.getEngineByMimeType(nameOrExtOrMime);
}
if (null == engine) {
throw new NullPointerException(StrUtil.format("Script for [{}] not support !", nameOrExtOrMime));
}
return engine;
}
/**
* 获得单例的JavaScript引擎
*
* @return Javascript引擎
* @since 5.2.5
*/
public static ScriptEngine getJsEngine() {
return getScript("js");
}
/**
* 创建新的JavaScript引擎
*
* @return Javascript引擎
* @since 5.2.6
*/
public static ScriptEngine createJsEngine() {
return createScript("js");
}
/**
* 获得单例的Python引擎<br>
* 需要引入org.python:jython
*
* @return Python引擎
* @since 5.2.5
*/
public static ScriptEngine getPythonEngine() {
System.setProperty("python.import.site", "false");
return getScript("python");
}
/**
* 创建Python引擎<br>
* 需要引入org.python:jython
*
* @return Python引擎
* @since 5.2.6
*/
public static ScriptEngine createPythonEngine() {
System.setProperty("python.import.site", "false");
return createScript("python");
}
/**
* 获得单例的Lua引擎<br>
* 需要引入org.luaj:luaj-jse
*
* @return Lua引擎
* @since 5.2.5
*/
public static ScriptEngine getLuaEngine() {
return getScript("lua");
}
/**
* 创建Lua引擎<br>
* 需要引入org.luaj:luaj-jse
*
* @return Lua引擎
* @since 5.2.6
*/
public static ScriptEngine createLuaEngine() {
return createScript("lua");
}
/**
* 获得单例的Groovy引擎<br>
* 需要引入org.codehaus.groovy:groovy-all
*
* @return Groovy引擎
* @since 5.2.5
*/
public static ScriptEngine getGroovyEngine() {
return getScript("groovy");
}
/**
* 创建Groovy引擎<br>
* 需要引入org.codehaus.groovy:groovy-all
*
* @return Groovy引擎
* @since 5.2.6
*/
public static ScriptEngine createGroovyEngine() {
return createScript("groovy");
}
/**
* 执行Javascript脚本返回Invocable此方法分为两种情况
*
* <ol>
* <li>执行的脚本返回值是可执行的脚本方法</li>
* <li>脚本为函数库则ScriptEngine本身为可执行方法</li>
* </ol>
*
* @param script 脚本内容
* @return 执行结果
* @throws UtilException 脚本异常
* @since 5.3.6
*/
public static Invocable evalInvocable(final String script) throws UtilException {
final ScriptEngine jsEngine = getJsEngine();
final Object eval;
try {
eval = jsEngine.eval(script);
} catch (final ScriptException e) {
throw new UtilException(e);
}
if(eval instanceof Invocable){
return (Invocable)eval;
} else if(jsEngine instanceof Invocable){
return (Invocable)jsEngine;
}
throw new UtilException("Script is not invocable !");
}
/**
* 执行有返回值的Javascript脚本
*
* @param script 脚本内容
* @return 执行结果
* @throws UtilException 脚本异常
* @since 3.2.0
*/
public static Object eval(final String script) throws UtilException {
try {
return getJsEngine().eval(script);
} catch (final ScriptException e) {
throw new UtilException(e);
}
}
/**
* 执行有返回值的脚本
*
* @param script 脚本内容
* @param context 脚本上下文
* @return 执行结果
* @throws UtilException 脚本异常
* @since 3.2.0
*/
public static Object eval(final String script, final ScriptContext context) throws UtilException {
try {
return getJsEngine().eval(script, context);
} catch (final ScriptException e) {
throw new UtilException(e);
}
}
/**
* 执行有返回值的脚本
*
* @param script 脚本内容
* @param bindings 绑定的参数
* @return 执行结果
* @throws UtilException 脚本异常
* @since 3.2.0
*/
public static Object eval(final String script, final Bindings bindings) throws UtilException {
try {
return getJsEngine().eval(script, bindings);
} catch (final ScriptException e) {
throw new UtilException(e);
}
}
/**
* 执行JS脚本中的指定方法
*
* @param script js脚本
* @param func 方法名
* @param args 方法参数
* @return 结果
* @since 5.3.6
*/
public static Object invoke(final String script, final String func, final Object... args) {
final Invocable eval = evalInvocable(script);
try {
return eval.invokeFunction(func, args);
} catch (final ScriptException | NoSuchMethodException e) {
throw new UtilException(e);
}
}
/**
* 编译Javascript脚本
*
* @param script 脚本内容
* @return {@link CompiledScript}
* @throws UtilException 脚本异常
* @since 3.2.0
*/
public static CompiledScript compile(final String script) throws UtilException {
try {
return compile(getJsEngine(), script);
} catch (final ScriptException e) {
throw new UtilException(e);
}
}
/**
* 编译Javascript脚本
*
* @param engine 引擎
* @param script 脚本内容
* @return {@link CompiledScript}
* @throws ScriptException 脚本异常
*/
public static CompiledScript compile(final ScriptEngine engine, final String script) throws ScriptException {
if (engine instanceof Compilable) {
final Compilable compEngine = (Compilable) engine;
return compEngine.compile(script);
}
return null;
}
}

View File

@ -1,18 +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.
*/
/**
* 使用Java对脚本引擎的工具封装
*
* @author looly
*/
package org.dromara.hutool.extra.script;

View File

@ -12,10 +12,9 @@
package org.dromara.hutool.extra.tokenizer.engine.mynlp;
import com.mayabot.nlp.Mynlp;
import com.mayabot.nlp.segment.Lexer;
import com.mayabot.nlp.segment.Lexers;
import com.mayabot.nlp.segment.Sentence;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.extra.tokenizer.Result;
import org.dromara.hutool.extra.tokenizer.TokenizerEngine;
@ -35,7 +34,10 @@ public class MynlpEngine implements TokenizerEngine {
* 构造
*/
public MynlpEngine() {
this.lexer = Lexers.core();
// CORE分词器构建器
// 开启词性标注功能
// 开启人名识别功能
this.lexer = Mynlp.instance().bigramLexer();
}
/**

View File

@ -10,6 +10,5 @@
# See the Mulan PSL v2 for more details.
#
org.dromara.hutool.extra.aop.proxy.CglibProxyFactory
org.dromara.hutool.extra.aop.proxy.SpringCglibProxyFactory
org.dromara.hutool.extra.aop.proxy.JdkProxyFactory

View File

@ -1,39 +0,0 @@
package org.dromara.hutool.extra.script;
import org.dromara.hutool.core.exceptions.UtilException;
import org.dromara.hutool.core.io.resource.ResourceUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import javax.script.CompiledScript;
import javax.script.ScriptException;
/**
* 脚本单元测试类
*
* @author looly
*
*/
public class ScriptUtilTest {
@Test
public void compileTest() {
final CompiledScript script = ScriptUtil.compile("print('Script test!');");
try {
script.eval();
} catch (final ScriptException e) {
throw new UtilException(e);
}
}
@Test
public void evalTest() {
ScriptUtil.eval("print('Script test!');");
}
@Test
public void invokeTest() {
final Object result = ScriptUtil.invoke(ResourceUtil.readUtf8Str("filter1.js"), "filter1", 2, 1);
Assertions.assertTrue((Boolean) result);
}
}

View File

@ -1,6 +0,0 @@
function filter1(a, b) {
if (a > b) {
return a > b;
}
return false;
}

View File

@ -13,17 +13,21 @@
package org.dromara.hutool.swing.img;
import org.dromara.hutool.core.codec.binary.Base64;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.io.file.FileNameUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.io.resource.Resource;
import org.dromara.hutool.core.io.stream.FastByteArrayOutputStream;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.math.NumberUtil;
import org.dromara.hutool.core.net.url.URLUtil;
import org.dromara.hutool.core.text.StrUtil;
import javax.imageio.*;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.ImageIcon;
@ -1369,9 +1373,9 @@ public class ImgUtil {
* @since 5.2.4
*/
public static byte[] toBytes(final Image image, final String imageType) {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
write(image, imageType, out);
return out.toByteArray();
return out.toByteArrayZeroCopyIfPossible();
}
// region ----- createImage