killme2008 / killme2008/aviatorscript

将表达式编译后的字节流结果存入redis,然后反序列化报错

Open
#642 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
5.2k
Forks
906
PR merge metrics
No merged PRs in 30d

Description

使用如下工具类 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"`

序列化和反序列化代码

```java
@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 executeExpression(Expression expression, Map paramMap, Class resultType) {
return resultType.cast(expression.execute(paramMap));
}

/**
* execute the expression
* @param bs
* @param paramMap
* @param resultType
* @return
*/
public static T executeExpression(byte[] bs, Map paramMap, Class resultType) {
Expression expression = deserializeExpression(bs);
return resultType.cast(expression.execute(paramMap));
}

/**
* execute the expression
* @param expression
* @param resultType
* @return
*/
public static T executeExpression(Expression expression, Class resultType) {
return resultType.cast(expression.execute());
}

/**
* execute the expression
* @param bs
* @param resultType
* @return
*/
public static T executeExpression(byte[] bs, Class 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 executeExpression(String expressionStr, Map paramMap, Class 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 executeExpression(String expressionStr, Class 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 map = new HashMap<>();
// map.put("price", 20);
// Boolean b1 = AviatorUtils.executeExpression("price>30", map, Boolean.class);
// System.out.println(b1);

Map 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);
}

}
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the AviatorUtilsDemo serializeExpression and deserializeExpression entry points, especially the shared engine setup and the ObjectInputStream/ObjectOutputStream calls. Reproduce the Redis round trip using the expression and parameters in the example, then inspect the deserialization path; done means the serialized expression can be read and executed without the duplicate AviatorScript class-definition error.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, redis
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.