可以在Java中评估YAML值字符串吗?

huangapple go评论73阅读模式
英文:

Can a YAML value string be evaluated in Java?

问题

在YAML文件中将Java代码作为值传递是否可能?例如,像这样的内容:

--- 
dueDate: "DueDateCalc()"

DueDateCalc() 可能是在解析YAML的Java代码中定义的方法。然后,它将Java的 dueDate 属性设置为预定义的 DueDateCalc() 方法的返回值。

英文:

Is it possible to pass Java code as a value in a YAML file. For example, something like this:

--- 
 dueDate: "DueDateCalc()"

DueDateCalc() might be a method defined in the Java code that is parsing the YAML. It would then set the Java dueDate property to the return of the predefined DueDateCalc() method.

答案1

得分: 3

这在 Java 运行时反射的限制下是可能的,但是你需要自己实现。

例如,你的 YAML 可能是这样的:

--- 
dueDate: !call DueDateCalc

!call 是一个本地标签,用于告诉加载代码,标量值 DueDateCalc 应该被解释为要调用的方法(这是由你选择的,而不是预定义的)。你可以通过为 !call 标签创建自定义构造函数来实现,该构造函数在某个给定的类中搜索具有指定名称的方法,然后在某个给定的对象上调用它。

那么参数呢?虽然仍然可能实现,但会变得非常混乱。首先问题是如何定义参数:

使用嵌套的 YAML 序列:!call [MyMethod, [1, 2, 3]]
使用需要解析的标量:!call MyMethod(1, 2, 3)

前一种选项允许 YAML 解析参数,你会得到一个列表;后一种选项需要你从你从 YAML 中获得的字符串中自己解析方法调用。

第二个问题是将值加载到 Java 变量中,以便你可以将它们作为参数列表提供。Java 反射允许你获取方法的参数类型,你可以使用这些类型来加载参数值。例如,如果第一个参数的类型是 String,你会将 1 解析为 "1",而如果是 int,你可以将 1 解析为 int。如果你在方法调用编码中使用了嵌套的 YAML 序列,那么这可以通过 SnakeYAML 的内置功能实现。

即使参数是具有复杂结构的类对象,这也可以工作,你只需使用普通的 YAML 语法,对象就会被正确加载。直接引用代码中的变量是不可能的,但是你可以定义另一个标签 !lookup,它从给定的 Map 结构中检索值。

虽然反射允许你进行方法调用,但无法直接评估诸如 6*9 之类的表达式。因此,在尝试实现任何功能之前,请评估你需要哪些功能,并检查是否可以通过反射来实现。

英文:

This is possible within the constraints of Java runtime reflection, however you need to implement it yourself.

For example, your YAML could look like this:

--- 
dueDate: !call DueDateCalc

!call is a local tag for telling the loading code that the scalar value DueDateCalc should be interpreted as method to be called (this is chosen by you, not something predefined). You can implement this with a custom constructor for the !calc tag that searches for a method with the given name within some given class, and then calls it on some given object.

What about parameters? Well, still possible, but will get ugly fast. First problem is how you define the paramaters:

with nested YAML sequences: !call [MyMethod, [1, 2, 3]]
with a scalar that needs to be parsed: !call MyMethod(1, 2, 3)

The former option lets YAML parse the parameters and you'll get a list; the latter option requires you to parse the method call yourself from the string you get from YAML.

The second problem is to load the values into Java variables so that you can give them as argument list. Java reflection lets you get the method's parameter types and you can use those to load the parameter values. For example, if the first parameter's type is a String, you would parse 1 as a "1", while if it's an int, you can parse 1 as int. This is possible with SnakeYAML's builtin facilities if you're using nested YAML sequences for method call encoding.

This would even work if parameters are class objects with complex structure, you'd just use normal YAML syntax and the objects will be loaded properly. Referring to variables in your code is not directly possible, but you could define another tag !lookup which retrieves values from a given Map structure.

While reflection lets you make method calls, you can not directly evaluate an expression like 6*9. So before you try and implement anything, evaluate which functionality you need and check whether it's doable via reflection.

huangapple
  • 本文由 发表于 2020年8月16日 14:58:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/63434035.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定