aviatorscript
aviatorscript copied to clipboard
将表达式编译后的字节流结果存入redis,然后反序列化报错
使用如下工具类 AviatorUtilsDemo将表达式编译后的字节流(bytes[])结果存入redis,然后取出反序列化报错
deserializeExpression方法报错:
2024-08-22 17:00:02.770 [http-nio-8083-exec-2] ERROR com.xxx.RestExceptionHandler:23 - org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.LinkageError: loader (instance of com/googlecode/aviator/parser/AviatorClassLoader): attempted duplicate class definition for name: "AviatorScript_1724315357698_58"
序列化和反序列化代码
@Slf4j
public class AviatorUtilsDemo {
/**
* 初始化执行引擎
*/
private static final AviatorEvaluatorInstance engine;
static {
engine = AviatorEvaluator.getInstance();
engine.setOption(Options.SERIALIZABLE, true);
}
/**
* execute the expression
* @param expression
* @param paramMap
* @param resultType
* @return
*/
public static <T> T executeExpression(Expression expression, Map<String, Object> paramMap, Class<T> resultType) {
return resultType.cast(expression.execute(paramMap));
}
/**
* execute the expression
* @param bs
* @param paramMap
* @param resultType
* @return
*/
public static <T> T executeExpression(byte[] bs, Map<String, Object> paramMap, Class<T> resultType) {
Expression expression = deserializeExpression(bs);
return resultType.cast(expression.execute(paramMap));
}
/**
* execute the expression
* @param expression
* @param resultType
* @return
*/
public static <T> T executeExpression(Expression expression, Class<T> resultType) {
return resultType.cast(expression.execute());
}
/**
* execute the expression
* @param bs
* @param resultType
* @return
*/
public static <T> T executeExpression(byte[] bs, Class<T> resultType) {
Expression expression = deserializeExpression(bs);
return resultType.cast(expression.execute());
}
/**
* execute the expression
* 谨慎使用 会导致metaspace OOM
* @param expressionStr
* @param paramMap
* @param resultType
* @return
*/
public static <T> T executeExpression(String expressionStr, Map<String, Object> paramMap, Class<T> resultType) {
Expression expression = engine.compile(expressionStr);
return resultType.cast(expression.execute(paramMap));
}
/**
* execute the expression
* 谨慎使用 会导致metaspace OOM
* @param expressionStr
* @param resultType
* @return
*/
public static <T> T executeExpression(String expressionStr, Class<T> resultType) {
Expression expression = engine.compile(expressionStr);
return resultType.cast(expression.execute());
}
/**
* Serialize the expression
* @param expression
* @return
*/
public static byte[] serializeExpression(String expression) {
byte[] bs = null; // the serialized bytes
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
// Create the ObjectOutputStream
ObjectOutputStream output = engine.newObjectOutputStream(out);
// Write the expression object
output.writeObject(engine.compile(expression));
output.close();
// Get the result byte array
bs = out.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
return bs;
}
/**
* Deserialize expression from bytes
* @param bs
* @return
*/
public static Expression deserializeExpression(byte[] bs) {
Expression expression = null;
try (ByteArrayInputStream in = new ByteArrayInputStream(bs)) {
// Create the ObjectInputStream from ByteArrayInputStream(bs)
ObjectInputStream input = engine.newObjectInputStream(in);
// Read the expression from ObjectInputStream
expression = (Expression) input.readObject();
} catch (Exception e) {
log.error("avaitor deserializeExpression err", e);
// throw new RuntimeException(e);
}
return expression;
}
public static void main(String[] args) {
// Boolean b = AviatorUtils.executeExpression("1+1==3", Boolean.class);
// System.out.println(b);
//
// Map<String, Object> map = new HashMap<>();
// map.put("price", 20);
// Boolean b1 = AviatorUtils.executeExpression("price>30", map, Boolean.class);
// System.out.println(b1);
Map<String, Object> map = new HashMap<>();
map.put("price", 30);
map.put("period", "14d");
byte[] bs = AviatorUtilsDemo.serializeExpression("(price>=29.99)&&(period=='14d')");
Boolean b2 = AviatorUtilsDemo.executeExpression(bs, map, Boolean.class);
System.out.println(b2);
}
}
看着像是把类定义序列化了
这个其实是因为当前的 aviator instance 已经有这个表达式存在了,重复编译加载了,简单可以忽略的。或者你应该能判断某个表达式是否已经编译过,编译过就不要去反序列化了。