Remove tangles from core + minor polish

This commit is contained in:
Phillip Webb 2013-07-07 00:08:18 -07:00
parent 2c05e9f150
commit b838dc5422
10 changed files with 177 additions and 141 deletions

View File

@ -43,7 +43,7 @@ import org.springframework.zero.context.annotation.EnableAutoConfiguration;
import org.springframework.zero.context.condition.ConditionalOnClass;
import org.springframework.zero.context.condition.ConditionalOnMissingBean;
import org.springframework.zero.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.zero.context.embedded.ServerProperties;
import org.springframework.zero.context.embedded.properties.ServerProperties;
/**
* {@link EnableAutoConfiguration Auto-configuration} to enable Spring MVC to handle

View File

@ -20,7 +20,7 @@ import java.net.InetAddress;
import javax.validation.constraints.NotNull;
import org.springframework.zero.context.embedded.ServerProperties;
import org.springframework.zero.context.embedded.properties.ServerProperties;
import org.springframework.zero.context.properties.ConfigurationProperties;
/**

View File

@ -27,7 +27,7 @@ import org.springframework.zero.context.annotation.EnableAutoConfiguration;
import org.springframework.zero.context.condition.ConditionalOnMissingBean;
import org.springframework.zero.context.embedded.ConfigurableEmbeddedServletContainerFactory;
import org.springframework.zero.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.zero.context.embedded.ServerProperties;
import org.springframework.zero.context.embedded.properties.ServerProperties;
import org.springframework.zero.context.properties.EnableConfigurationProperties;
/**

View File

@ -33,7 +33,7 @@ import org.springframework.zero.context.embedded.AnnotationConfigEmbeddedWebAppl
import org.springframework.zero.context.embedded.ConfigurableEmbeddedServletContainerFactory;
import org.springframework.zero.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor;
import org.springframework.zero.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.zero.context.embedded.ServerProperties;
import org.springframework.zero.context.embedded.properties.ServerProperties;
import org.springframework.zero.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import static org.junit.Assert.assertEquals;

View File

@ -59,13 +59,13 @@ public class PropertiesConfigurationFactory<T> implements FactoryBean<T>,
private PropertySources propertySources;
private T configuration;
private T target;
private Validator validator;
private MessageSource messageSource;
private boolean initialized = false;
private boolean hasBeenBound = false;
private String targetName;
@ -77,7 +77,7 @@ public class PropertiesConfigurationFactory<T> implements FactoryBean<T>,
*/
public PropertiesConfigurationFactory(T target) {
Assert.notNull(target);
this.configuration = target;
this.target = target;
}
/**
@ -88,7 +88,7 @@ public class PropertiesConfigurationFactory<T> implements FactoryBean<T>,
@SuppressWarnings("unchecked")
public PropertiesConfigurationFactory(Class<?> type) {
Assert.notNull(type);
this.configuration = (T) BeanUtils.instantiate(type);
this.target = (T) BeanUtils.instantiate(type);
}
/**
@ -165,86 +165,15 @@ public class PropertiesConfigurationFactory<T> implements FactoryBean<T>,
@Override
public void afterPropertiesSet() throws Exception {
Assert.state(this.properties != null || this.propertySources != null,
"Properties or propertySources should not be null");
try {
if (this.properties != null) {
logger.trace("Properties:\n" + this.properties);
}
else {
logger.trace("Property Sources: " + this.propertySources);
}
this.initialized = true;
RelaxedDataBinder dataBinder;
if (this.targetName != null) {
dataBinder = new RelaxedDataBinder(this.configuration, this.targetName);
}
else {
dataBinder = new RelaxedDataBinder(this.configuration);
}
if (this.validator != null) {
dataBinder.setValidator(this.validator);
}
if (this.conversionService != null) {
dataBinder.setConversionService(this.conversionService);
}
dataBinder.setIgnoreInvalidFields(this.ignoreInvalidFields);
dataBinder.setIgnoreUnknownFields(this.ignoreUnknownFields);
customizeBinder(dataBinder);
PropertyValues pvs;
if (this.properties != null) {
pvs = new MutablePropertyValues(this.properties);
}
else {
pvs = new PropertySourcesPropertyValues(this.propertySources);
}
dataBinder.bind(pvs);
if (this.validator != null) {
dataBinder.validate();
BindingResult errors = dataBinder.getBindingResult();
if (errors.hasErrors()) {
logger.error("Properties configuration failed validation");
for (ObjectError error : errors.getAllErrors()) {
logger.error(this.messageSource != null ? this.messageSource
.getMessage(error, Locale.getDefault())
+ " ("
+ error
+ ")" : error);
}
if (this.exceptionIfInvalid) {
BindException summary = new BindException(errors);
throw summary;
}
}
}
}
catch (BindException e) {
if (this.exceptionIfInvalid) {
throw e;
}
logger.error(
"Failed to load Properties validation bean. Your Properties may be invalid.",
e);
}
}
/**
* @param dataBinder the data binder that will be used to bind and validate
*/
protected void customizeBinder(DataBinder dataBinder) {
bindPropertiesToTarget();
}
@Override
public Class<?> getObjectType() {
if (this.configuration == null) {
if (this.target == null) {
return Object.class;
}
return this.configuration.getClass();
return this.target.getClass();
}
@Override
@ -254,10 +183,80 @@ public class PropertiesConfigurationFactory<T> implements FactoryBean<T>,
@Override
public T getObject() throws Exception {
if (!this.initialized) {
afterPropertiesSet();
if (!this.hasBeenBound) {
bindPropertiesToTarget();
}
return this.configuration;
return this.target;
}
public void bindPropertiesToTarget() throws BindException {
Assert.state(this.properties != null || this.propertySources != null,
"Properties or propertySources should not be null");
try {
if (logger.isTraceEnabled()) {
if (this.properties != null) {
logger.trace("Properties:\n" + this.properties);
}
else {
logger.trace("Property Sources: " + this.propertySources);
}
}
this.hasBeenBound = true;
doBindPropertiesToTarget();
}
catch (BindException e) {
if (this.exceptionIfInvalid) {
throw e;
}
logger.error("Failed to load Properties validation bean. "
+ "Your Properties may be invalid.", e);
}
}
private void doBindPropertiesToTarget() throws BindException {
RelaxedDataBinder dataBinder = (this.targetName != null ? new RelaxedDataBinder(
this.target, this.targetName) : new RelaxedDataBinder(this.target));
if (this.validator != null) {
dataBinder.setValidator(this.validator);
}
if (this.conversionService != null) {
dataBinder.setConversionService(this.conversionService);
}
dataBinder.setIgnoreInvalidFields(this.ignoreInvalidFields);
dataBinder.setIgnoreUnknownFields(this.ignoreUnknownFields);
customizeBinder(dataBinder);
PropertyValues propertyValues = (this.properties != null ? new MutablePropertyValues(
this.properties)
: new PropertySourcesPropertyValues(this.propertySources));
dataBinder.bind(propertyValues);
if (this.validator != null) {
validate(dataBinder);
}
}
private void validate(RelaxedDataBinder dataBinder) throws BindException {
dataBinder.validate();
BindingResult errors = dataBinder.getBindingResult();
if (errors.hasErrors()) {
logger.error("Properties configuration failed validation");
for (ObjectError error : errors.getAllErrors()) {
logger.error(this.messageSource != null ? this.messageSource.getMessage(
error, Locale.getDefault()) + " (" + error + ")" : error);
}
if (this.exceptionIfInvalid) {
BindException summary = new BindException(errors);
throw summary;
}
}
}
/**
* @param dataBinder the data binder that will be used to bind and validate
*/
protected void customizeBinder(DataBinder dataBinder) {
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.zero.context.embedded;
package org.springframework.zero.context.embedded.properties;
import java.io.File;
import java.net.InetAddress;
@ -24,6 +24,10 @@ import javax.validation.constraints.NotNull;
import org.apache.catalina.valves.AccessLogValve;
import org.apache.catalina.valves.RemoteIpValve;
import org.springframework.util.StringUtils;
import org.springframework.zero.context.embedded.ConfigurableEmbeddedServletContainerFactory;
import org.springframework.zero.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.zero.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor;
import org.springframework.zero.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.zero.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.zero.context.properties.ConfigurationProperties;

View File

@ -27,9 +27,9 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.PropertySources;
import org.springframework.util.StringUtils;
import org.springframework.validation.Validator;
import org.springframework.zero.bind.PropertiesConfigurationFactory;
import org.springframework.zero.context.properties.EnableConfigurationPropertiesImportSelector.ConfigurationPropertiesHolder;
/**
* {@link BeanPostProcessor} to bind {@link PropertySources} to beans annotated with
@ -89,44 +89,41 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
throws BeansException {
ConfigurationProperties annotation = AnnotationUtils.findAnnotation(
bean.getClass(), ConfigurationProperties.class);
Object target = bean;
if (annotation != null || bean instanceof ConfigurationPropertiesHolder) {
if (bean instanceof ConfigurationPropertiesHolder) {
target = ((ConfigurationPropertiesHolder) bean).getTarget();
}
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
target);
factory.setPropertySources(this.propertySources);
factory.setValidator(this.validator);
// If no explicit conversion service is provided we add one so that (at least)
// comma-separated arrays of convertibles can be bound automatically
factory.setConversionService(this.conversionService == null ? getDefaultConversionService()
: this.conversionService);
String targetName = null;
if (annotation != null) {
factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());
factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());
targetName = "".equals(annotation.value()) ? (""
.equals(annotation.name()) ? null : annotation.name())
: annotation.value();
}
factory.setTargetName(targetName);
try {
target = factory.getObject(); // throwaway
}
catch (BeansException e) {
throw e;
}
catch (Exception e) {
throw new BeanCreationException(beanName, "Could not bind", e);
}
postProcessAfterInitialization(bean, beanName, annotation);
}
return bean;
}
/**
* @return
*/
private void postProcessAfterInitialization(Object bean, String beanName,
ConfigurationProperties annotation) {
Object target = (bean instanceof ConfigurationPropertiesHolder ? ((ConfigurationPropertiesHolder) bean)
.getTarget() : bean);
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
target);
factory.setPropertySources(this.propertySources);
factory.setValidator(this.validator);
// If no explicit conversion service is provided we add one so that (at least)
// comma-separated arrays of convertibles can be bound automatically
factory.setConversionService(this.conversionService == null ? getDefaultConversionService()
: this.conversionService);
if (annotation != null) {
factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());
factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());
String targetName = (StringUtils.hasLength(annotation.value()) ? annotation
.value() : annotation.name());
if (StringUtils.hasLength(targetName)) {
factory.setTargetName(targetName);
}
}
try {
factory.bindPropertiesToTarget();
}
catch (Exception ex) {
throw new BeanCreationException(beanName, "Could not bind properties", ex);
}
}
private ConversionService getDefaultConversionService() {
if (!this.initialized && this.beanFactory instanceof ListableBeanFactory) {
for (Converter<?, ?> converter : ((ListableBeanFactory) this.beanFactory)

View File

@ -0,0 +1,37 @@
/*
* Copyright 2012-2013 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.zero.context.properties;
/**
* Properties holder registered by {@link EnableConfigurationPropertiesImportSelector} to
* be picked up by {@link ConfigurationPropertiesBindingPostProcessor}.
*
* @author Dave Syer
*/
class ConfigurationPropertiesHolder {
private Object target;
public ConfigurationPropertiesHolder(Object target) {
this.target = target;
}
public Object getTarget() {
return this.target;
}
}

View File

@ -19,6 +19,7 @@ package org.springframework.zero.context.properties;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
@ -67,17 +68,7 @@ class EnableConfigurationPropertiesImportSelector implements ImportSelector {
for (Class<?> type : types) {
String name = type.getName();
if (!registry.containsBeanDefinition(name)) {
registry.registerBeanDefinition(name, BeanDefinitionBuilder
.genericBeanDefinition(type).getBeanDefinition());
ConfigurationProperties properties = AnnotationUtils.findAnnotation(
type, ConfigurationProperties.class);
if (properties == null) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(ConfigurationPropertiesHolder.class);
builder.addConstructorArgReference(name);
registry.registerBeanDefinition(name + ".HOLDER",
builder.getBeanDefinition());
}
registerBeanDefinition(registry, type, name);
}
}
}
@ -94,18 +85,25 @@ class EnableConfigurationPropertiesImportSelector implements ImportSelector {
return result;
}
}
private void registerBeanDefinition(BeanDefinitionRegistry registry,
Class<?> type, String name) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(type);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
registry.registerBeanDefinition(name, beanDefinition);
public static class ConfigurationPropertiesHolder {
private Object target;
public ConfigurationPropertiesHolder(Object target) {
this.target = target;
ConfigurationProperties properties = AnnotationUtils.findAnnotation(type,
ConfigurationProperties.class);
if (properties == null) {
registerPropertiesHolder(registry, name);
}
}
public Object getTarget() {
return this.target;
private void registerPropertiesHolder(BeanDefinitionRegistry registry, String name) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(ConfigurationPropertiesHolder.class);
builder.addConstructorArgReference(name);
registry.registerBeanDefinition(name + ".HOLDER", builder.getBeanDefinition());
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.zero.context.embedded;
package org.springframework.zero.context.embedded.properties;
import java.net.InetAddress;
import java.util.Collections;
@ -24,6 +24,7 @@ import java.util.Map;
import org.junit.Test;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.zero.bind.RelaxedDataBinder;
import org.springframework.zero.context.embedded.properties.ServerProperties;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;