killme2008 / aviatorscript

A high performance scripting language hosted on the JVM.
http://fnil.net/aviator/
4.51k stars 839 forks source link

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

Open huahuadan opened 2 months ago

huahuadan commented 2 months ago

使用如下工具类 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);
    }

}
xiongxin commented 2 months ago

看着像是把类定义序列化了