[英]How to parse part of .yaml file to object in SnakeYAML?
我有一个 yaml 文件,例如:
# this is the part I don't care about
config:
key-1: val-1
other-config:
lang: en
year: 1906
# below is the only part I care about
interesting-setup:
port: 1234
validation: false
parts:
- on-start: backup
on-stop: say-goodbye
我还有一个适用于interesting-setup
部分的 POJO class
public class InterestingSetup {
int port;
boolean validation;
List<Map<String, String>> parts;
}
我只想加载interesting-setup
部分(类似于 Spring 中@ConfigurationProperties("interesting-setup")
)
目前我是这样做的:
Map<String, Object> yamlConfig = yaml.load(yamlFile); # loading the whole file to Map with Object values
Object interestingObject = yamlConfig.get("interesting-setup"); # loading 'interesting-setup' part as an object
Map<String, Object> interestingMap = (Map<String, Object>); # Casting object to Map<String, Object>
String yamlDumped = yaml.dump(interestingMap); # Serialization to String
InterestingSetup finalObject = yaml.load(yamlDumped); # Getting final object from String
关键部分是当我有一个 Object (Map<String, Object>) 并想将其转换为我的最终 class 时。为此 - 我需要将其序列化为 String,因此过程如下所示:
File -> Map<String, Object> -> Object -> Map<String, Object> -> String -> FinalClass
我想避免反序列化和再次序列化相同的数据。
那么我能以某种方式使用Yaml
到 map Map<String, Object>
到另一个 class 吗? 我在 API 中看不到这个?
AFAIK,SnakeYAML 库没有提供直接的方法来做到这一点。
您可以尝试调整它并定义一个容器基础 class,其中仅包含您需要支持的字段。 例如考虑以下 POJO:
public class Container {
private InterestingSetup interestingSetup;
public InterestingSetup getInterestingSetup() {
return interestingSetup;
}
public void setInterestingSetup(InterestingSetup interestingSetup) {
this.interestingSetup = interestingSetup;
}
@Override
public String toString() {
return "Container{" +
"interestingSetup=" + interestingSetup +
'}';
}
}
其中, InterestingSetup
是你自己的class:
import java.util.List;
import java.util.Map;
public class InterestingSetup {
private int port;
private boolean validation;
private List<Map<String, String>> parts;
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isValidation() {
return validation;
}
public void setValidation(boolean validation) {
this.validation = validation;
}
public List<Map<String, String>> getParts() {
return parts;
}
public void setParts(List<Map<String, String>> parts) {
this.parts = parts;
}
@Override
public String toString() {
return "InterestingSetup{" +
"port=" + port +
", validation=" + validation +
", parts=" + parts +
'}';
}
}
有了这些 bean,下面的代码就可以按您的要求工作:
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.representer.Representer;
public class Main {
public static void main(String... args) throws UnsupportedEncodingException {
String yamlString =
"# this is the part I don't care about\n" +
"config:\n" +
" key-1: val-1\n" +
"other-config:\n" +
" lang: en\n" +
" year: 1906\n" +
"# below is the only part I care about\n" +
"interesting-setup:\n" +
" port: 1234\n" +
" validation: false\n" +
" parts:\n" +
" - on-start: backup\n" +
" on-stop: say-goodbye";
// Skip unknown properties
Representer representer = new Representer();
representer.getPropertyUtils().setSkipMissingProperties(true);
// Define the target object type
Constructor constructor = new Constructor(Container.class);
TypeDescription containerTypeDescription = new TypeDescription(Container.class);
// Define how the interesting-setup property should be processed
containerTypeDescription.substituteProperty("interesting-setup", InterestingSetup.class,
"getInterestingSetup", "setInterestingSetup");
constructor.addTypeDescription(containerTypeDescription);
// Finally, parse the YAML
Yaml yaml = new Yaml(constructor, representer);
InputStream inputStream = new ByteArrayInputStream(yamlString.getBytes(StandardCharsets.UTF_8));;
Container container = yaml.load(inputStream);
System.out.println(container.getInterestingSetup());
}
}
也许,一个更简单的解决方案将包括使用一些方法,允许您在给定一堆字段及其相应值的情况下在InterestedSetup
bean 中设置适当的信息。 您可以为此使用 Reflection API。 来自 Apache Commons 的BeansUtils
class 中的populate
方法也很方便:
Map<String, Object> yamlConfig = yaml.load(yamlFile);
Object interestingObject = yamlConfig.get("interesting-setup");
Map<String, Object> interestingMap = (Map<String, Object>);
InterestingSetup finalObject = BeanUtils.populate(interestingMap);
作为替代方法,您可以使用 Jackson 来处理 YAML 文件。 代码将类似于:
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
// As the helper object Container doesn't contain all the properties
// it is necessary to indicate that fact to the library to avoid
// errors
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Container container = mapper.readValue(yamlString, Container.class);
System.out.println(container.getInterestingSetup());
Container
class 与上面所示相同,只是添加了@JsonProperty
注释以便成功处理interesting-setup
字段:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
// Instead of mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
// you can annotate the class with @JsonIgnoreProperties(ignoreUnknown = true)
// to avoid errors related to unknown properties
public class Container {
@JsonProperty("interesting-setup")
private InterestingSetup interestingSetup;
public InterestingSetup getInterestingSetup() {
return interestingSetup;
}
public void setInterestingSetup(InterestingSetup interestingSetup) {
this.interestingSetup = interestingSetup;
}
@Override
public String toString() {
return "Container{" +
"interestingSetup=" + interestingSetup +
'}';
}
}
所需的工件可以从Maven下载为以下依赖项:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.13.1</version>
</dependency>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.