Merge branch '1.2.x'

pull/3384/head
Andy Wilkinson 10 years ago
commit 2159190713

@ -32,6 +32,7 @@ import org.springframework.context.annotation.Conditional;
* not already contained in the {@link BeanFactory}. * not already contained in the {@link BeanFactory}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson
*/ */
@Target({ ElementType.TYPE, ElementType.METHOD }) @Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ -53,6 +54,21 @@ public @interface ConditionalOnMissingBean {
*/ */
String[] type() default {}; String[] type() default {};
/**
* The class type of beans that should be ignored when identifying matching beans.
* @return the class types of beans to ignore
* @since 1.2.5
*/
Class<?>[] ignored() default {};
/**
* The class type names of beans that should be ignored when identifying matching
* beans.
* @return the class type names of beans to ignore
* @since 1.2.5
*/
String[] ignoredType() default {};
/** /**
* The annotation type decorating a bean that should be checked. The condition matches * The annotation type decorating a bean that should be checked. The condition matches
* when each annotation specified is missing from all beans in the * when each annotation specified is missing from all beans in the

@ -55,6 +55,7 @@ import org.springframework.util.StringUtils;
* @author Dave Syer * @author Dave Syer
* @author Jakub Kubrynski * @author Jakub Kubrynski
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Andy Wilkinson
*/ */
@Order(Ordered.LOWEST_PRECEDENCE) @Order(Ordered.LOWEST_PRECEDENCE)
class OnBeanCondition extends SpringBootCondition implements ConfigurationCondition { class OnBeanCondition extends SpringBootCondition implements ConfigurationCondition {
@ -136,6 +137,10 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
beanNames.addAll(getBeanNamesForType(beanFactory, type, beanNames.addAll(getBeanNamesForType(beanFactory, type,
context.getClassLoader(), considerHierarchy)); context.getClassLoader(), considerHierarchy));
} }
for (String ignoredType : beans.getIgnoredTypes()) {
beanNames.removeAll(getBeanNamesForType(beanFactory, ignoredType,
context.getClassLoader(), considerHierarchy));
}
for (String annotation : beans.getAnnotations()) { for (String annotation : beans.getAnnotations()) {
beanNames.addAll(Arrays.asList(getBeanNamesForAnnotation(beanFactory, beanNames.addAll(Arrays.asList(getBeanNamesForAnnotation(beanFactory,
annotation, context.getClassLoader(), considerHierarchy))); annotation, context.getClassLoader(), considerHierarchy)));
@ -243,6 +248,8 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
private final List<String> annotations = new ArrayList<String>(); private final List<String> annotations = new ArrayList<String>();
private final List<String> ignoredTypes = new ArrayList<String>();
private final SearchStrategy strategy; private final SearchStrategy strategy;
public BeanSearchSpec(ConditionContext context, AnnotatedTypeMetadata metadata, public BeanSearchSpec(ConditionContext context, AnnotatedTypeMetadata metadata,
@ -254,6 +261,8 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
collect(attributes, "value", this.types); collect(attributes, "value", this.types);
collect(attributes, "type", this.types); collect(attributes, "type", this.types);
collect(attributes, "annotation", this.annotations); collect(attributes, "annotation", this.annotations);
collect(attributes, "ignored", this.ignoredTypes);
collect(attributes, "ignoredType", this.ignoredTypes);
if (this.types.isEmpty() && this.names.isEmpty()) { if (this.types.isEmpty() && this.names.isEmpty()) {
addDeducedBeanType(context, metadata, this.types); addDeducedBeanType(context, metadata, this.types);
} }
@ -350,6 +359,10 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
return this.annotations; return this.annotations;
} }
public List<String> getIgnoredTypes() {
return this.ignoredTypes;
}
@Override @Override
public String toString() { public String toString() {
StringBuilder string = new StringBuilder(); StringBuilder string = new StringBuilder();

@ -45,7 +45,9 @@ class JacksonHttpMessageConvertersConfiguration {
protected static class MappingJackson2HttpMessageConverterConfiguration { protected static class MappingJackson2HttpMessageConverterConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean(value = MappingJackson2HttpMessageConverter.class, ignoredType = {
"org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter",
"org.springframework.data.rest.webmvc.alps.AlpsJsonHttpMessageConverter" })
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter( public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
ObjectMapper objectMapper) { ObjectMapper objectMapper) {
return new MappingJackson2HttpMessageConverter(objectMapper); return new MappingJackson2HttpMessageConverter(objectMapper);

@ -32,6 +32,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
@ -187,6 +188,28 @@ public class ConditionalOnMissingBeanTests {
equalTo("fromFactory")); equalTo("fromFactory"));
} }
@Test
public void testOnMissingBeanConditionWithIgnoredSubclass() {
this.context.register(CustomExampleBeanConfiguration.class,
ConditionalOnIgnoredSubclass.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertThat(this.context.getBeansOfType(ExampleBean.class).size(), is(equalTo(2)));
assertThat(this.context.getBeansOfType(CustomExampleBean.class).size(),
is(equalTo(1)));
}
@Test
public void testOnMissingBeanConditionWithIgnoredSubclassByName() {
this.context.register(CustomExampleBeanConfiguration.class,
ConditionalOnIgnoredSubclassByName.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertThat(this.context.getBeansOfType(ExampleBean.class).size(), is(equalTo(2)));
assertThat(this.context.getBeansOfType(CustomExampleBean.class).size(),
is(equalTo(1)));
}
@Configuration @Configuration
@ConditionalOnMissingBean(name = "foo") @ConditionalOnMissingBean(name = "foo")
protected static class OnBeanNameConfiguration { protected static class OnBeanNameConfiguration {
@ -299,6 +322,38 @@ public class ConditionalOnMissingBeanTests {
} }
} }
@Configuration
protected static class ConditionalOnIgnoredSubclass {
@Bean
@ConditionalOnMissingBean(value = ExampleBean.class, ignored = CustomExampleBean.class)
public ExampleBean exampleBean() {
return new ExampleBean("test");
}
}
@Configuration
protected static class ConditionalOnIgnoredSubclassByName {
@Bean
@ConditionalOnMissingBean(value = ExampleBean.class, ignoredType = "org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBeanTests.CustomExampleBean")
public ExampleBean exampleBean() {
return new ExampleBean("test");
}
}
@Configuration
protected static class CustomExampleBeanConfiguration {
@Bean
public CustomExampleBean customExampleBean() {
return new CustomExampleBean();
}
}
@Configuration @Configuration
@ConditionalOnMissingBean(annotation = EnableScheduling.class) @ConditionalOnMissingBean(annotation = EnableScheduling.class)
protected static class OnAnnotationConfiguration { protected static class OnAnnotationConfiguration {
@ -369,6 +424,14 @@ public class ConditionalOnMissingBeanTests {
} }
public static class CustomExampleBean extends ExampleBean {
public CustomExampleBean() {
super("custom subclass");
}
}
public static class ExampleFactoryBean implements FactoryBean<ExampleBean> { public static class ExampleFactoryBean implements FactoryBean<ExampleBean> {
public ExampleFactoryBean(String value) { public ExampleFactoryBean(String value) {

@ -18,15 +18,21 @@ package org.springframework.boot.autoconfigure.web;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration.MappingJackson2HttpMessageConverterConfiguration;
import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter; import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@ -36,7 +42,10 @@ import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConve
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson; import com.google.gson.Gson;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
/** /**
@ -187,6 +196,39 @@ public class HttpMessageConvertersAutoConfigurationTests {
assertConverterBeanRegisteredWithHttpMessageConverters(StringHttpMessageConverter.class); assertConverterBeanRegisteredWithHttpMessageConverters(StringHttpMessageConverter.class);
} }
@Test
public void typeConstrainedConverterDoesNotPreventAutoConfigurationOfJacksonConverter()
throws Exception {
this.context.register(JacksonObjectMapperBuilderConfig.class,
TypeConstrainedConverterConfiguration.class,
HttpMessageConvertersAutoConfiguration.class);
this.context.refresh();
BeanDefinition beanDefinition = this.context
.getBeanDefinition("mappingJackson2HttpMessageConverter");
assertThat(beanDefinition.getFactoryBeanName(),
is(equalTo(MappingJackson2HttpMessageConverterConfiguration.class
.getName())));
}
@Test
public void typeConstrainedConverterFromSpringDataDoesNotPreventAutoConfigurationOfJacksonConverter()
throws Exception {
this.context.register(JacksonObjectMapperBuilderConfig.class,
RepositoryRestMvcConfiguration.class,
HttpMessageConvertersAutoConfiguration.class);
this.context.refresh();
Map<String, MappingJackson2HttpMessageConverter> beansOfType = this.context
.getBeansOfType(MappingJackson2HttpMessageConverter.class);
System.out.println(beansOfType);
BeanDefinition beanDefinition = this.context
.getBeanDefinition("mappingJackson2HttpMessageConverter");
assertThat(beanDefinition.getFactoryBeanName(),
is(equalTo(MappingJackson2HttpMessageConverterConfiguration.class
.getName())));
}
private void assertConverterBeanExists(Class<?> type, String beanName) { private void assertConverterBeanExists(Class<?> type, String beanName) {
assertEquals(1, this.context.getBeansOfType(type).size()); assertEquals(1, this.context.getBeansOfType(type).size());
List<String> beanNames = Arrays.asList(this.context.getBeanDefinitionNames()); List<String> beanNames = Arrays.asList(this.context.getBeanDefinitionNames());
@ -254,4 +296,14 @@ public class HttpMessageConvertersAutoConfigurationTests {
} }
} }
@Configuration
protected static class TypeConstrainedConverterConfiguration {
@Bean
public TypeConstrainedMappingJackson2HttpMessageConverter typeConstrainedConverter() {
return new TypeConstrainedMappingJackson2HttpMessageConverter(
ResourceSupport.class);
}
}
} }

Loading…
Cancel
Save