Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
huahuadan opened this issue Aug 22, 2024 · 2 comments

Comments

@huahuadan
Copy link

huahuadan commented Aug 22, 2024

使用如下工具类 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
Copy link

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

@killme2008
Copy link
Owner

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants