org.springframework.boot.bind.YamlConfigurationFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.boot.bind.YamlConfigurationFactory.java

Source

/*
 * Copyright 2012-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.bind;

import java.nio.charset.Charset;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.error.YAMLException;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.Validator;

/**
 * Validate some YAML by binding it to an object of a specified type and then optionally
 * running a {@link Validator} over it.
 *
 * @param <T> the configuration type
 * @author Luke Taylor
 * @author Dave Syer
 */
public class YamlConfigurationFactory<T> implements FactoryBean<T>, MessageSourceAware, InitializingBean {

    private final Log logger = LogFactory.getLog(getClass());

    private final Class<?> type;

    private boolean exceptionIfInvalid;

    private String yaml;

    private Resource resource;

    private T configuration;

    private Validator validator;

    private MessageSource messageSource;

    private Map<Class<?>, Map<String, String>> propertyAliases = Collections.emptyMap();

    /**
     * Sets a validation constructor which will be applied to the YAML doc to see whether
     * it matches the expected Javabean.
     * @param type the root type
     */
    public YamlConfigurationFactory(Class<?> type) {
        Assert.notNull(type);
        this.type = type;
    }

    /**
     * Set the message source.
     * @param messageSource the message source
     */
    @Override
    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    /**
     * Set the property aliases.
     * @param propertyAliases the property aliases
     */
    public void setPropertyAliases(Map<Class<?>, Map<String, String>> propertyAliases) {
        this.propertyAliases = new HashMap<Class<?>, Map<String, String>>(propertyAliases);
    }

    /**
     * Set the YAML.
     * @param yaml the YAML
     */
    public void setYaml(String yaml) {
        this.yaml = yaml;
    }

    /**
     * Set the resource.
     * @param resource the resource
     */
    public void setResource(Resource resource) {
        this.resource = resource;
    }

    /**
     * Set the validator.
     * @param validator the validator
     */
    public void setValidator(Validator validator) {
        this.validator = validator;
    }

    public void setExceptionIfInvalid(boolean exceptionIfInvalid) {
        this.exceptionIfInvalid = exceptionIfInvalid;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void afterPropertiesSet() throws Exception {
        if (this.yaml == null) {
            Assert.state(this.resource != null, "Resource should not be null");
            this.yaml = StreamUtils.copyToString(this.resource.getInputStream(), Charset.defaultCharset());
        }
        Assert.state(this.yaml != null, "Yaml document should not be null: "
                + "either set it directly or set the resource to load it from");
        try {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Yaml document is\n" + this.yaml);
            }
            Constructor constructor = new YamlJavaBeanPropertyConstructor(this.type, this.propertyAliases);
            this.configuration = (T) (new Yaml(constructor)).load(this.yaml);
            if (this.validator != null) {
                validate();
            }
        } catch (YAMLException ex) {
            if (this.exceptionIfInvalid) {
                throw ex;
            }
            this.logger.error("Failed to load YAML validation bean. " + "Your YAML file may be invalid.", ex);
        }
    }

    private void validate() throws BindException {
        BindingResult errors = new BeanPropertyBindingResult(this.configuration, "configuration");
        this.validator.validate(this.configuration, errors);
        if (errors.hasErrors()) {
            this.logger.error("YAML configuration failed validation");
            for (ObjectError error : errors.getAllErrors()) {
                this.logger.error(this.messageSource != null
                        ? this.messageSource.getMessage(error, Locale.getDefault()) + " (" + error + ")"
                        : error);
            }
            if (this.exceptionIfInvalid) {
                BindException summary = new BindException(errors);
                throw summary;
            }
        }
    }

    @Override
    public Class<?> getObjectType() {
        if (this.configuration == null) {
            return Object.class;
        }
        return this.configuration.getClass();
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public T getObject() throws Exception {
        if (this.configuration == null) {
            afterPropertiesSet();
        }
        return this.configuration;
    }

}