aviatorscript icon indicating copy to clipboard operation
aviatorscript copied to clipboard

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

Open huahuadan opened this issue 1 year ago • 2 comments

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

}

huahuadan avatar Aug 22 '24 09:08 huahuadan

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

xiongxin avatar Aug 30 '24 07:08 xiongxin

这个其实是因为当前的 aviator instance 已经有这个表达式存在了,重复编译加载了,简单可以忽略的。或者你应该能判断某个表达式是否已经编译过,编译过就不要去反序列化了。

killme2008 avatar Nov 20 '24 14:11 killme2008