
io.dropwizard.configuration.YamlConfigurationFactory Maven / Gradle / Ivy
package io.dropwizard.configuration;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.databind.node.TreeTraversingParser;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.snakeyaml.error.MarkedYAMLException;
import com.fasterxml.jackson.dataformat.yaml.snakeyaml.error.YAMLException;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static java.util.Objects.requireNonNull;
/**
* A factory class for loading YAML configuration files, binding them to configuration objects, and
* validating their constraints. Allows for overriding configuration parameters from system properties.
*
* @param the type of the configuration objects to produce
*/
public class YamlConfigurationFactory implements ConfigurationFactory {
private static final Pattern ESCAPED_COMMA_PATTERN = Pattern.compile("\\\\,");
private static final Splitter ESCAPED_COMMA_SPLITTER = Splitter.on(Pattern.compile("(? klass;
private final String propertyPrefix;
private final ObjectMapper mapper;
private final Validator validator;
private final YAMLFactory yamlFactory;
/**
* Creates a new configuration factory for the given class.
*
* @param klass the configuration class
* @param validator the validator to use
* @param objectMapper the Jackson {@link ObjectMapper} to use
* @param propertyPrefix the system property name prefix used by overrides
*/
public YamlConfigurationFactory(Class klass,
Validator validator,
ObjectMapper objectMapper,
String propertyPrefix) {
this.klass = klass;
this.propertyPrefix = (propertyPrefix == null || propertyPrefix.endsWith("."))
? propertyPrefix : (propertyPrefix + '.');
// Sub-classes may choose to omit data-binding; if so, null ObjectMapper passed:
if (objectMapper == null) { // sub-class has no need for mapper
mapper = null;
yamlFactory = null;
} else {
mapper = objectMapper;
yamlFactory = new YAMLFactory();
}
this.validator = validator;
}
@Override
public T build(ConfigurationSourceProvider provider, String path) throws IOException, ConfigurationException {
try (InputStream input = provider.open(requireNonNull(path))) {
final JsonNode node = mapper.readTree(yamlFactory.createParser(input));
if (node == null) {
throw ConfigurationParsingException
.builder("Configuration at " + path + " must not be empty")
.build(path);
}
return build(node, path);
} catch (YAMLException e) {
final ConfigurationParsingException.Builder builder = ConfigurationParsingException
.builder("Malformed YAML")
.setCause(e)
.setDetail(e.getMessage());
if (e instanceof MarkedYAMLException) {
builder.setLocation(((MarkedYAMLException) e).getProblemMark());
}
throw builder.build(path);
}
}
@Override
public T build() throws IOException, ConfigurationException {
try {
final JsonNode node = mapper.valueToTree(klass.newInstance());
return build(node, "default configuration");
} catch (InstantiationException | IllegalAccessException e) {
throw new IllegalArgumentException("Unable create an instance " +
"of the configuration class: '" + klass.getCanonicalName() + "'", e);
}
}
protected T build(JsonNode node, String path) throws IOException, ConfigurationException {
for (Map.Entry
© 2015 - 2025 Weber Informatics LLC | Privacy Policy