AFAIK, the SnakeYAML library doesn't provide a straight way to do that.
You may try tweaking it and defining a container base class with only the fields you required to support. Consider for example the following 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 +
'}';
}
}
Where, InterestingSetup
is your own 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 +
'}';
}
}
With those beans in place, the following code would work as you required:
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());
}
}
Perhaps, a more simple solution will consists on using some method that allows you, given a bunch of fields and their corresponding values, to set the appropriate information in the InterestedSetup
bean. You can use the Reflection API for that. The populate
method in the BeansUtils
class from Apache Commons can also be handy as well:
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);
As an alternate approach, you can use Jackson to process the YAML file. The code will be similar to this:
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());
The Container
class is the same presented above with the addition of a @JsonProperty
annotation in order to successfully handle the interesting-setup
field:
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 +
'}';
}
}
The required artifacts can be downloaded from Maven as the following dependency:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.13.1</version>
</dependency>