Merge branch '1.5.x'
This commit is contained in:
commit
81fef71fcb
|
|
@ -42,6 +42,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
|||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
|
|
@ -85,15 +86,16 @@ public class EndpointMvcIntegrationTests {
|
|||
@Test
|
||||
public void envEndpointNotHidden() throws InterruptedException {
|
||||
String body = new TestRestTemplate().getForObject(
|
||||
"http://localhost:" + this.port + "/application/env/foo.bar", String.class);
|
||||
"http://localhost:" + this.port + "/application/env/foo.bar",
|
||||
String.class);
|
||||
assertThat(body).isNotNull().contains("\"baz\"");
|
||||
assertThat(this.interceptor.invoked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthEndpointNotHidden() throws InterruptedException {
|
||||
String body = new TestRestTemplate()
|
||||
.getForObject("http://localhost:" + this.port + "/application/health", String.class);
|
||||
String body = new TestRestTemplate().getForObject(
|
||||
"http://localhost:" + this.port + "/application/health", String.class);
|
||||
assertThat(body).isNotNull().contains("status");
|
||||
assertThat(this.interceptor.invoked()).isTrue();
|
||||
}
|
||||
|
|
@ -153,9 +155,9 @@ public class EndpointMvcIntegrationTests {
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import({ ServletWebServerFactoryAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
|
||||
protected @interface MinimalWebConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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.autoconfigure.validation;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.validation.MessageInterpolatorFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
/**
|
||||
* Default validator configuration imported by {@link ValidationAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
class DefaultValidatorConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(type = { "javax.validation.Validator",
|
||||
"org.springframework.validation.Validator" })
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public static LocalValidatorFactoryBean defaultValidator() {
|
||||
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
|
||||
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
|
||||
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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.autoconfigure.validation;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.SmartValidator;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
|
||||
|
||||
/**
|
||||
* {@link Validator} implementation that delegates calls to another {@link Validator}.
|
||||
* This {@link Validator} implements Spring's {@link SmartValidator} interface but does
|
||||
* not implement the JSR-303 {@code javax.validator.Validator} interface.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.5.3
|
||||
*/
|
||||
public class DelegatingValidator implements SmartValidator {
|
||||
|
||||
private final Validator delegate;
|
||||
|
||||
/**
|
||||
* Create a new {@link DelegatingValidator} instance.
|
||||
* @param targetValidator the target JSR validator
|
||||
*/
|
||||
public DelegatingValidator(javax.validation.Validator targetValidator) {
|
||||
this.delegate = new SpringValidatorAdapter(targetValidator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link DelegatingValidator} instance.
|
||||
* @param targetValidator the target validator
|
||||
*/
|
||||
public DelegatingValidator(Validator targetValidator) {
|
||||
Assert.notNull(targetValidator, "Target Validator must not be null");
|
||||
this.delegate = targetValidator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return this.delegate.supports(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors) {
|
||||
this.delegate.validate(target, errors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors, Object... validationHints) {
|
||||
if (this.delegate instanceof SmartValidator) {
|
||||
((SmartValidator) this.delegate).validate(target, errors, validationHints);
|
||||
}
|
||||
else {
|
||||
this.delegate.validate(target, errors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the delegate validator.
|
||||
* @return the delegate validator
|
||||
*/
|
||||
protected final Validator getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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.autoconfigure.validation;
|
||||
|
||||
import javax.validation.Validator;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.validation.SmartValidator;
|
||||
|
||||
/**
|
||||
* JSR 303 adapter configration imported by {@link ValidationAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
class Jsr303ValidatorAdapterConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnSingleCandidate(Validator.class)
|
||||
@ConditionalOnMissingBean(org.springframework.validation.Validator.class)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public SmartValidator jsr303ValidatorAdapter(Validator validator) {
|
||||
return new DelegatingValidator(validator);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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.autoconfigure.validation;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.validation.MessageInterpolatorFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.SmartValidator;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
|
||||
|
||||
/**
|
||||
* A {@link SmartValidator} exposed as a bean for WebMvc use. Wraps existing
|
||||
* {@link SpringValidatorAdapter} instances so that only the Spring's {@link Validator}
|
||||
* type is exposed. This prevents such a bean to expose both the Spring and JSR-303
|
||||
* validator contract at the same time.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class SpringValidator implements SmartValidator, ApplicationContextAware,
|
||||
InitializingBean, DisposableBean {
|
||||
|
||||
private final SpringValidatorAdapter target;
|
||||
|
||||
private final boolean existingBean;
|
||||
|
||||
public SpringValidator(SpringValidatorAdapter target, boolean existingBean) {
|
||||
this.target = target;
|
||||
this.existingBean = existingBean;
|
||||
}
|
||||
|
||||
public final SpringValidatorAdapter getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return this.target.supports(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors) {
|
||||
this.target.validate(target, errors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors, Object... validationHints) {
|
||||
this.target.validate(target, errors, validationHints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
if (!this.existingBean && this.target instanceof ApplicationContextAware) {
|
||||
((ApplicationContextAware) this.target)
|
||||
.setApplicationContext(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (!this.existingBean && this.target instanceof InitializingBean) {
|
||||
((InitializingBean) this.target).afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (!this.existingBean && this.target instanceof DisposableBean) {
|
||||
((DisposableBean) this.target).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public static Validator get(ApplicationContext applicationContext,
|
||||
Validator validator) {
|
||||
if (validator != null) {
|
||||
return wrap(validator, false);
|
||||
}
|
||||
return getExistingOrCreate(applicationContext);
|
||||
}
|
||||
|
||||
private static Validator getExistingOrCreate(ApplicationContext applicationContext) {
|
||||
Validator existing = getExisting(applicationContext);
|
||||
if (existing != null) {
|
||||
return wrap(existing, true);
|
||||
}
|
||||
return create();
|
||||
}
|
||||
|
||||
private static Validator getExisting(ApplicationContext applicationContext) {
|
||||
try {
|
||||
javax.validation.Validator validator = applicationContext
|
||||
.getBean(javax.validation.Validator.class);
|
||||
if (validator instanceof Validator) {
|
||||
return (Validator) validator;
|
||||
}
|
||||
return new SpringValidatorAdapter(validator);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Validator create() {
|
||||
OptionalValidatorFactoryBean validator = new OptionalValidatorFactoryBean();
|
||||
validator.setMessageInterpolator(new MessageInterpolatorFactory().getObject());
|
||||
return wrap(validator, false);
|
||||
}
|
||||
|
||||
private static Validator wrap(Validator validator, boolean existingBean) {
|
||||
if (validator instanceof javax.validation.Validator) {
|
||||
if (validator instanceof SpringValidatorAdapter) {
|
||||
return new SpringValidator((SpringValidatorAdapter) validator,
|
||||
existingBean);
|
||||
}
|
||||
return new SpringValidator(
|
||||
new SpringValidatorAdapter((javax.validation.Validator) validator),
|
||||
existingBean);
|
||||
}
|
||||
return validator;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,18 +19,16 @@ package org.springframework.boot.autoconfigure.validation;
|
|||
import javax.validation.Validator;
|
||||
import javax.validation.executable.ExecutableValidator;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
import org.springframework.boot.validation.MessageInterpolatorFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
|
||||
/**
|
||||
|
|
@ -43,19 +41,12 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
|
|||
@Configuration
|
||||
@ConditionalOnClass(ExecutableValidator.class)
|
||||
@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")
|
||||
@Import({ DefaultValidatorConfiguration.class,
|
||||
Jsr303ValidatorAdapterConfiguration.class })
|
||||
public class ValidationAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
@ConditionalOnMissingBean
|
||||
public static Validator jsr303Validator() {
|
||||
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
|
||||
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
|
||||
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(Validator.class)
|
||||
@ConditionalOnMissingBean
|
||||
public static MethodValidationPostProcessor methodValidationPostProcessor(
|
||||
Environment environment, Validator validator) {
|
||||
|
|
|
|||
|
|
@ -23,30 +23,50 @@ import java.util.concurrent.TimeUnit;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.validation.SpringValidator;
|
||||
import org.springframework.boot.autoconfigure.validation.DelegatingValidator;
|
||||
import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;
|
||||
import org.springframework.boot.autoconfigure.web.ResourceProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ConfigurationCondition;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.reactive.config.DelegatingWebFluxConfiguration;
|
||||
import org.springframework.web.reactive.config.EnableWebFlux;
|
||||
|
|
@ -82,6 +102,12 @@ import org.springframework.web.reactive.result.view.ViewResolver;
|
|||
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
|
||||
public class WebFluxAnnotationAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public static WebFluxValidatorPostProcessor mvcValidatorAliasPostProcessor() {
|
||||
return new WebFluxValidatorPostProcessor();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({ ResourceProperties.class, WebFluxProperties.class })
|
||||
@Import(EnableWebFluxConfiguration.class)
|
||||
|
|
@ -190,17 +216,29 @@ public class WebFluxAnnotationAutoConfiguration {
|
|||
* Configuration equivalent to {@code @EnableWebFlux}.
|
||||
*/
|
||||
@Configuration
|
||||
public static class EnableWebFluxConfiguration
|
||||
extends DelegatingWebFluxConfiguration {
|
||||
public static class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration
|
||||
implements InitializingBean {
|
||||
|
||||
private final ApplicationContext context;
|
||||
|
||||
public EnableWebFluxConfiguration(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
@Conditional(DisableWebFluxValidatorCondition.class)
|
||||
public Validator webFluxValidator() {
|
||||
return this.context.getBean("webFluxValidator", Validator.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public Validator webFluxValidator() {
|
||||
if (!ClassUtils.isPresent("javax.validation.Validator",
|
||||
getClass().getClassLoader())) {
|
||||
return super.webFluxValidator();
|
||||
}
|
||||
return SpringValidator.get(getApplicationContext(), getValidator());
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(getValidator() == null,
|
||||
"Found unexpected validator configuration. A Spring Boot WebFlux "
|
||||
+ "validator should be registered as bean named "
|
||||
+ "'webFluxValidator' and not returned from "
|
||||
+ "WebFluxConfigurer.getValidator()");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -266,4 +304,128 @@ public class WebFluxAnnotationAutoConfiguration {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition used to disable the default WebFlux validator registration. The
|
||||
* {@link WebFluxValidatorPostProcessor} is used to configure the
|
||||
* {@code webFluxValidator} bean.
|
||||
*/
|
||||
static class DisableWebFluxValidatorCondition implements ConfigurationCondition {
|
||||
|
||||
@Override
|
||||
public ConfigurationPhase getConfigurationPhase() {
|
||||
return ConfigurationPhase.REGISTER_BEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} to deal with the MVC validator bean registration.
|
||||
* Applies the following rules:
|
||||
* <ul>
|
||||
* <li>With no validators - Uses standard
|
||||
* {@link WebFluxConfigurationSupport#webFluxValidator()} logic.</li>
|
||||
* <li>With a single validator - Uses an alias.</li>
|
||||
* <li>With multiple validators - Registers a mvcValidator bean if not already
|
||||
* defined.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class WebFluxValidatorPostProcessor
|
||||
implements BeanDefinitionRegistryPostProcessor {
|
||||
|
||||
private static final String JSR303_VALIDATOR_CLASS = "javax.validation.Validator";
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
|
||||
throws BeansException {
|
||||
if (registry instanceof ListableBeanFactory) {
|
||||
postProcess(registry, (ListableBeanFactory) registry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
}
|
||||
|
||||
private void postProcess(BeanDefinitionRegistry registry,
|
||||
ListableBeanFactory beanFactory) {
|
||||
String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
beanFactory, Validator.class, false, false);
|
||||
if (validatorBeans.length == 0) {
|
||||
registerMvcValidator(registry, beanFactory);
|
||||
}
|
||||
else if (validatorBeans.length == 1) {
|
||||
registry.registerAlias(validatorBeans[0], "webFluxValidator");
|
||||
}
|
||||
else {
|
||||
if (!ObjectUtils.containsElement(validatorBeans, "webFluxValidator")) {
|
||||
registerMvcValidator(registry, beanFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerMvcValidator(BeanDefinitionRegistry registry,
|
||||
ListableBeanFactory beanFactory) {
|
||||
RootBeanDefinition definition = new RootBeanDefinition();
|
||||
definition.setBeanClass(getClass());
|
||||
definition.setFactoryMethodName("webFluxValidator");
|
||||
registry.registerBeanDefinition("webFluxValidator", definition);
|
||||
}
|
||||
|
||||
static Validator webFluxValidator() {
|
||||
Validator validator = new WebFluxConfigurationSupport().webFluxValidator();
|
||||
try {
|
||||
if (ClassUtils.forName(JSR303_VALIDATOR_CLASS, null)
|
||||
.isInstance(validator)) {
|
||||
return new DelegatingWebFluxValidator(validator);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
return validator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link DelegatingValidator} for the WebFlux validator.
|
||||
*/
|
||||
static class DelegatingWebFluxValidator extends DelegatingValidator
|
||||
implements ApplicationContextAware, InitializingBean, DisposableBean {
|
||||
|
||||
DelegatingWebFluxValidator(Validator targetValidator) {
|
||||
super(targetValidator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
if (getDelegate() instanceof ApplicationContextAware) {
|
||||
((ApplicationContextAware) getDelegate())
|
||||
.setApplicationContext(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (getDelegate() instanceof InitializingBean) {
|
||||
((InitializingBean) getDelegate()).afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (getDelegate() instanceof DisposableBean) {
|
||||
((DisposableBean) getDelegate()).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,11 +30,21 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
|
|
@ -45,7 +55,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.boot.autoconfigure.validation.SpringValidator;
|
||||
import org.springframework.boot.autoconfigure.validation.DelegatingValidator;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;
|
||||
import org.springframework.boot.autoconfigure.web.ResourceProperties;
|
||||
|
|
@ -54,21 +64,31 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
|||
import org.springframework.boot.web.servlet.filter.OrderedHiddenHttpMethodFilter;
|
||||
import org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter;
|
||||
import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ConfigurationCondition;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.datetime.DateFormatter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.DefaultMessageCodesResolver;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
|
|
@ -147,6 +167,12 @@ public class WebMvcAutoConfiguration {
|
|||
public static final String SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class
|
||||
.getName() + ".SKIP";
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public static MvcValidatorPostProcessor mvcValidatorAliasPostProcessor() {
|
||||
return new MvcValidatorPostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
|
||||
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
|
||||
|
|
@ -372,21 +398,22 @@ public class WebMvcAutoConfiguration {
|
|||
* Configuration equivalent to {@code @EnableWebMvc}.
|
||||
*/
|
||||
@Configuration
|
||||
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
|
||||
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration
|
||||
implements InitializingBean {
|
||||
|
||||
private final WebMvcProperties mvcProperties;
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
private final ApplicationContext context;
|
||||
|
||||
private final WebMvcRegistrations mvcRegistrations;
|
||||
|
||||
public EnableWebMvcConfiguration(
|
||||
ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
|
||||
ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider,
|
||||
ListableBeanFactory beanFactory) {
|
||||
ApplicationContext context) {
|
||||
this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
|
||||
this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
|
||||
this.beanFactory = beanFactory;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
@ -417,12 +444,9 @@ public class WebMvcAutoConfiguration {
|
|||
|
||||
@Bean
|
||||
@Override
|
||||
@Conditional(DisableMvcValidatorCondition.class)
|
||||
public Validator mvcValidator() {
|
||||
if (!ClassUtils.isPresent("javax.validation.Validator",
|
||||
getClass().getClassLoader())) {
|
||||
return super.mvcValidator();
|
||||
}
|
||||
return SpringValidator.get(getApplicationContext(), getValidator());
|
||||
return this.context.getBean("mvcValidator", Validator.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -437,7 +461,7 @@ public class WebMvcAutoConfiguration {
|
|||
@Override
|
||||
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
|
||||
try {
|
||||
return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
|
||||
return this.context.getBean(ConfigurableWebBindingInitializer.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
return super.getConfigurableWebBindingInitializer();
|
||||
|
|
@ -486,6 +510,15 @@ public class WebMvcAutoConfiguration {
|
|||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(getValidator() == null,
|
||||
"Found unexpected validator configuration. A Spring Boot MVC "
|
||||
+ "validator should be registered as bean named "
|
||||
+ "'mvcValidator' and not returned from "
|
||||
+ "WebMvcConfigurer.getValidator()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
|
@ -611,4 +644,128 @@ public class WebMvcAutoConfiguration {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition used to disable the default MVC validator registration. The
|
||||
* {@link MvcValidatorPostProcessor} is used to configure the {@code mvcValidator}
|
||||
* bean.
|
||||
*/
|
||||
static class DisableMvcValidatorCondition implements ConfigurationCondition {
|
||||
|
||||
@Override
|
||||
public ConfigurationPhase getConfigurationPhase() {
|
||||
return ConfigurationPhase.REGISTER_BEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} to deal with the MVC validator bean registration.
|
||||
* Applies the following rules:
|
||||
* <ul>
|
||||
* <li>With no validators - Uses standard
|
||||
* {@link WebMvcConfigurationSupport#mvcValidator()} logic.</li>
|
||||
* <li>With a single validator - Uses an alias.</li>
|
||||
* <li>With multiple validators - Registers a mvcValidator bean if not already
|
||||
* defined.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class MvcValidatorPostProcessor
|
||||
implements BeanDefinitionRegistryPostProcessor {
|
||||
|
||||
private static final String JSR303_VALIDATOR_CLASS = "javax.validation.Validator";
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
|
||||
throws BeansException {
|
||||
if (registry instanceof ListableBeanFactory) {
|
||||
postProcess(registry, (ListableBeanFactory) registry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
}
|
||||
|
||||
private void postProcess(BeanDefinitionRegistry registry,
|
||||
ListableBeanFactory beanFactory) {
|
||||
String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
beanFactory, Validator.class, false, false);
|
||||
if (validatorBeans.length == 0) {
|
||||
registerMvcValidator(registry, beanFactory);
|
||||
}
|
||||
else if (validatorBeans.length == 1) {
|
||||
registry.registerAlias(validatorBeans[0], "mvcValidator");
|
||||
}
|
||||
else {
|
||||
if (!ObjectUtils.containsElement(validatorBeans, "mvcValidator")) {
|
||||
registerMvcValidator(registry, beanFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerMvcValidator(BeanDefinitionRegistry registry,
|
||||
ListableBeanFactory beanFactory) {
|
||||
RootBeanDefinition definition = new RootBeanDefinition();
|
||||
definition.setBeanClass(getClass());
|
||||
definition.setFactoryMethodName("mvcValidator");
|
||||
registry.registerBeanDefinition("mvcValidator", definition);
|
||||
}
|
||||
|
||||
static Validator mvcValidator() {
|
||||
Validator validator = new WebMvcConfigurationSupport().mvcValidator();
|
||||
try {
|
||||
if (ClassUtils.forName(JSR303_VALIDATOR_CLASS, null)
|
||||
.isInstance(validator)) {
|
||||
return new DelegatingWebMvcValidator(validator);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
return validator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link DelegatingValidator} for the MVC validator.
|
||||
*/
|
||||
static class DelegatingWebMvcValidator extends DelegatingValidator
|
||||
implements ApplicationContextAware, InitializingBean, DisposableBean {
|
||||
|
||||
DelegatingWebMvcValidator(Validator targetValidator) {
|
||||
super(targetValidator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
if (getDelegate() instanceof ApplicationContextAware) {
|
||||
((ApplicationContextAware) getDelegate())
|
||||
.setApplicationContext(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (getDelegate() instanceof InitializingBean) {
|
||||
((InitializingBean) getDelegate()).afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (getDelegate() instanceof DisposableBean) {
|
||||
((DisposableBean) getDelegate()).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
|
|
@ -322,9 +323,9 @@ public class SpringBootWebSecurityConfigurationTests {
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import({ ServletWebServerFactoryAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
|
||||
protected @interface MinimalWebConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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.autoconfigure.validation;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.SmartValidator;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link DelegatingValidator}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class DelegatingValidatorTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Mock
|
||||
private SmartValidator delegate;
|
||||
|
||||
private DelegatingValidator delegating;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
this.delegating = new DelegatingValidator(this.delegate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWhenJsrValidatorIsNullShouldThrowException() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("Target Validator must not be null");
|
||||
new DelegatingValidator((javax.validation.Validator) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithJsrValidatorShouldAdapt() throws Exception {
|
||||
javax.validation.Validator delegate = mock(javax.validation.Validator.class);
|
||||
Validator delegating = new DelegatingValidator(delegate);
|
||||
Object target = new Object();
|
||||
Errors errors = new BeanPropertyBindingResult(target, "foo");
|
||||
delegating.validate(target, errors);
|
||||
verify(delegate).validate(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithSpringValidatorWhenValidatorIsNullShouldThrowException()
|
||||
throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("Target Validator must not be null");
|
||||
new DelegatingValidator((Validator) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsShouldDelegateToValidator() throws Exception {
|
||||
this.delegating.supports(Object.class);
|
||||
verify(this.delegate).supports(Object.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateShouldDelegateToValidator() throws Exception {
|
||||
Object target = new Object();
|
||||
Errors errors = new BeanPropertyBindingResult(target, "foo");
|
||||
this.delegating.validate(target, errors);
|
||||
verify(this.delegate).validate(target, errors);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWithHintsShouldDelegateToValidator() throws Exception {
|
||||
Object target = new Object();
|
||||
Errors errors = new BeanPropertyBindingResult(target, "foo");
|
||||
Object[] hints = { "foo", "bar" };
|
||||
this.delegating.validate(target, errors, hints);
|
||||
verify(this.delegate).validate(target, errors, hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWithHintsWhenDelegateIsNotSmartShouldDelegateToSimpleValidator()
|
||||
throws Exception {
|
||||
Validator delegate = mock(Validator.class);
|
||||
DelegatingValidator delegating = new DelegatingValidator(delegate);
|
||||
Object target = new Object();
|
||||
Errors errors = new BeanPropertyBindingResult(target, "foo");
|
||||
Object[] hints = { "foo", "bar" };
|
||||
delegating.validate(target, errors, hints);
|
||||
verify(delegate).validate(target, errors);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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.autoconfigure.validation;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.MapBindingResult;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link SpringValidator}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class SpringValidatorTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapLocalValidatorFactoryBean() {
|
||||
SpringValidator wrapper = load(LocalValidatorFactoryBeanConfig.class);
|
||||
assertThat(wrapper.supports(SampleData.class)).isTrue();
|
||||
MapBindingResult errors = new MapBindingResult(new HashMap<String, Object>(),
|
||||
"test");
|
||||
wrapper.validate(new SampleData(40), errors);
|
||||
assertThat(errors.getErrorCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapperInvokesCallbackOnNonManagedBean() {
|
||||
load(NonManagedBeanConfig.class);
|
||||
LocalValidatorFactoryBean validator = this.context
|
||||
.getBean(NonManagedBeanConfig.class).validator;
|
||||
verify(validator, times(1)).setApplicationContext(any(ApplicationContext.class));
|
||||
verify(validator, times(1)).afterPropertiesSet();
|
||||
verify(validator, times(0)).destroy();
|
||||
this.context.close();
|
||||
this.context = null;
|
||||
verify(validator, times(1)).destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapperDoesNotInvokeCallbackOnManagedBean() {
|
||||
load(ManagedBeanConfig.class);
|
||||
LocalValidatorFactoryBean validator = this.context
|
||||
.getBean(ManagedBeanConfig.class).validator;
|
||||
verify(validator, times(0)).setApplicationContext(any(ApplicationContext.class));
|
||||
verify(validator, times(0)).afterPropertiesSet();
|
||||
verify(validator, times(0)).destroy();
|
||||
this.context.close();
|
||||
this.context = null;
|
||||
verify(validator, times(0)).destroy();
|
||||
}
|
||||
|
||||
private SpringValidator load(Class<?> config) {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(config);
|
||||
ctx.refresh();
|
||||
this.context = ctx;
|
||||
return this.context.getBean(SpringValidator.class);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class LocalValidatorFactoryBeanConfig {
|
||||
|
||||
@Bean
|
||||
public LocalValidatorFactoryBean validator() {
|
||||
return new LocalValidatorFactoryBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpringValidator wrapper() {
|
||||
return new SpringValidator(validator(), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class NonManagedBeanConfig {
|
||||
|
||||
private final LocalValidatorFactoryBean validator = mock(
|
||||
LocalValidatorFactoryBean.class);
|
||||
|
||||
@Bean
|
||||
public SpringValidator wrapper() {
|
||||
return new SpringValidator(this.validator, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ManagedBeanConfig {
|
||||
|
||||
private final LocalValidatorFactoryBean validator = mock(
|
||||
LocalValidatorFactoryBean.class);
|
||||
|
||||
@Bean
|
||||
public SpringValidator wrapper() {
|
||||
return new SpringValidator(this.validator, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SampleData {
|
||||
|
||||
@Min(42)
|
||||
private int counter;
|
||||
|
||||
SampleData(int counter) {
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -32,9 +32,12 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link ValidationAutoConfiguration}.
|
||||
|
|
@ -56,45 +59,94 @@ public class ValidationAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void validationIsEnabled() {
|
||||
load(SampleService.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
SampleService service = this.context.getBean(SampleService.class);
|
||||
service.doSomething("Valid");
|
||||
this.thrown.expect(ConstraintViolationException.class);
|
||||
service.doSomething("KO");
|
||||
public void validationAutoConfigurationShouldConfigureJsrAndSpringValidator()
|
||||
throws Exception {
|
||||
load(Config.class);
|
||||
Validator jsrValidator = this.context.getBean(Validator.class);
|
||||
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
|
||||
org.springframework.validation.Validator springValidator = this.context
|
||||
.getBean(org.springframework.validation.Validator.class);
|
||||
String[] springValidatorNames = this.context
|
||||
.getBeanNamesForType(org.springframework.validation.Validator.class);
|
||||
assertThat(jsrValidator).isInstanceOf(LocalValidatorFactoryBean.class);
|
||||
assertThat(jsrValidator).isEqualTo(springValidator);
|
||||
assertThat(jsrValidatorNames).containsExactly("defaultValidator");
|
||||
assertThat(springValidatorNames).containsExactly("defaultValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationUsesCglibProxy() {
|
||||
load(DefaultAnotherSampleService.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
DefaultAnotherSampleService service = this.context
|
||||
.getBean(DefaultAnotherSampleService.class);
|
||||
service.doSomething(42);
|
||||
this.thrown.expect(ConstraintViolationException.class);
|
||||
service.doSomething(2);
|
||||
public void validationAutoConfigurationWhenUserProvidesValidatorShouldBackOff()
|
||||
throws Exception {
|
||||
load(UserDefinedValidatorConfig.class);
|
||||
Validator jsrValidator = this.context.getBean(Validator.class);
|
||||
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
|
||||
org.springframework.validation.Validator springValidator = this.context
|
||||
.getBean(org.springframework.validation.Validator.class);
|
||||
String[] springValidatorNames = this.context
|
||||
.getBeanNamesForType(org.springframework.validation.Validator.class);
|
||||
assertThat(jsrValidator).isInstanceOf(OptionalValidatorFactoryBean.class);
|
||||
assertThat(jsrValidator).isEqualTo(springValidator);
|
||||
assertThat(jsrValidatorNames).containsExactly("customValidator");
|
||||
assertThat(springValidatorNames).containsExactly("customValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationCanBeConfiguredToUseJdkProxy() {
|
||||
public void validationAutoConfigurationWhenUserProvidesJsrOnlyShouldAdaptIt()
|
||||
throws Exception {
|
||||
load(UserDefinedJsrValidatorConfig.class);
|
||||
Validator jsrValidator = this.context.getBean(Validator.class);
|
||||
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
|
||||
org.springframework.validation.Validator springValidator = this.context
|
||||
.getBean(org.springframework.validation.Validator.class);
|
||||
String[] springValidatorNames = this.context
|
||||
.getBeanNamesForType(org.springframework.validation.Validator.class);
|
||||
assertThat(jsrValidator).isNotEqualTo(springValidator);
|
||||
assertThat(springValidator).isInstanceOf(DelegatingValidator.class);
|
||||
assertThat(jsrValidatorNames).containsExactly("customValidator");
|
||||
assertThat(springValidatorNames).containsExactly("jsr303ValidatorAdapter");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationAutoConfigurationShouldBeEnabled() {
|
||||
load(ClassWithConstraint.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
ClassWithConstraint service = this.context.getBean(ClassWithConstraint.class);
|
||||
service.call("Valid");
|
||||
this.thrown.expect(ConstraintViolationException.class);
|
||||
service.call("KO");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationAutoConfigurationShouldUseCglibProxy() {
|
||||
load(ImplementationOfInterfaceWithConstraint.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
ImplementationOfInterfaceWithConstraint service = this.context
|
||||
.getBean(ImplementationOfInterfaceWithConstraint.class);
|
||||
service.call(42);
|
||||
this.thrown.expect(ConstraintViolationException.class);
|
||||
service.call(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationAutoConfigurationWhenProxyTargetClassIsFalseShouldUseJdkProxy() {
|
||||
load(AnotherSampleServiceConfiguration.class,
|
||||
"spring.aop.proxy-target-class=false");
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(DefaultAnotherSampleService.class))
|
||||
.isEmpty();
|
||||
AnotherSampleService service = this.context.getBean(AnotherSampleService.class);
|
||||
service.doSomething(42);
|
||||
assertThat(this.context
|
||||
.getBeansOfType(ImplementationOfInterfaceWithConstraint.class)).isEmpty();
|
||||
InterfaceWithConstraint service = this.context
|
||||
.getBean(InterfaceWithConstraint.class);
|
||||
service.call(42);
|
||||
this.thrown.expect(ConstraintViolationException.class);
|
||||
service.doSomething(2);
|
||||
service.call(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userDefinedMethodValidationPostProcessorTakesPrecedence() {
|
||||
load(SampleConfiguration.class);
|
||||
public void validationAutoConfigurationWhenUserDefinesMethodValidationPostProcessorShouldBackOff() {
|
||||
load(UserDefinedMethodValidationConfig.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Object userMethodValidationPostProcessor = this.context
|
||||
.getBean("testMethodValidationPostProcessor");
|
||||
.getBean("customMethodValidationPostProcessor");
|
||||
assertThat(this.context.getBean(MethodValidationPostProcessor.class))
|
||||
.isSameAs(userMethodValidationPostProcessor);
|
||||
assertThat(this.context.getBeansOfType(MethodValidationPostProcessor.class))
|
||||
|
|
@ -115,47 +167,73 @@ public class ValidationAutoConfigurationTests {
|
|||
this.context = ctx;
|
||||
}
|
||||
|
||||
@Validated
|
||||
static class SampleService {
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
public void doSomething(@Size(min = 3, max = 10) String name) {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserDefinedValidatorConfig {
|
||||
|
||||
@Bean
|
||||
public OptionalValidatorFactoryBean customValidator() {
|
||||
return new OptionalValidatorFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface AnotherSampleService {
|
||||
@Configuration
|
||||
static class UserDefinedJsrValidatorConfig {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
void doSomething(@Min(42) Integer counter);
|
||||
}
|
||||
|
||||
@Validated
|
||||
static class DefaultAnotherSampleService implements AnotherSampleService {
|
||||
|
||||
@Override
|
||||
public void doSomething(Integer counter) {
|
||||
@Configuration
|
||||
static class UserDefinedMethodValidationConfig {
|
||||
|
||||
@Bean
|
||||
public MethodValidationPostProcessor customMethodValidationPostProcessor() {
|
||||
return new MethodValidationPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AnotherSampleServiceConfiguration {
|
||||
|
||||
@Bean
|
||||
public AnotherSampleService anotherSampleService() {
|
||||
return new DefaultAnotherSampleService();
|
||||
public InterfaceWithConstraint implementationOfInterfaceWithConstraint() {
|
||||
return new ImplementationOfInterfaceWithConstraint();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SampleConfiguration {
|
||||
@Validated
|
||||
static class ClassWithConstraint {
|
||||
|
||||
public void call(@Size(min = 3, max = 10) String name) {
|
||||
|
||||
@Bean
|
||||
public MethodValidationPostProcessor testMethodValidationPostProcessor() {
|
||||
return new MethodValidationPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface InterfaceWithConstraint {
|
||||
|
||||
void call(@Min(42) Integer counter);
|
||||
}
|
||||
|
||||
@Validated
|
||||
static class ImplementationOfInterfaceWithConstraint
|
||||
implements InterfaceWithConstraint {
|
||||
|
||||
@Override
|
||||
public void call(Integer counter) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,19 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.web.reactive;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.validation.ValidatorFactory;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.boot.autoconfigure.validation.SpringValidator;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.boot.autoconfigure.validation.DelegatingValidator;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfigurationTests.Config;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
||||
import org.springframework.boot.web.reactive.context.GenericReactiveWebApplicationContext;
|
||||
|
|
@ -36,9 +40,9 @@ import org.springframework.core.annotation.Order;
|
|||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.server.reactive.HttpHandler;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.accept.CompositeContentTypeResolver;
|
||||
import org.springframework.web.reactive.config.WebFluxConfigurationSupport;
|
||||
|
|
@ -65,6 +69,9 @@ import static org.mockito.Mockito.mock;
|
|||
*/
|
||||
public class WebFluxAnnotationAutoConfigurationTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private GenericReactiveWebApplicationContext context;
|
||||
|
||||
@Test
|
||||
|
|
@ -165,64 +172,134 @@ public class WebFluxAnnotationAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void validationNoJsr303ValidatorExposedByDefault() {
|
||||
public void validatorWhenSuppliedByConfigurerShouldThrowException() throws Exception {
|
||||
this.thrown.expect(BeanCreationException.class);
|
||||
this.thrown.expectMessage("unexpected validator configuration");
|
||||
load(ValidatorWebFluxConfigurer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenAutoConfiguredShouldUseAlias() throws Exception {
|
||||
load();
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Object defaultValidator = this.context.getBean("defaultValidator");
|
||||
Object webFluxValidator = this.context.getBean("webFluxValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(webFluxValidator).isSameAs(defaultValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("defaultValidator");
|
||||
assertThat(jsrValidatorBeans).containsExactly("defaultValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationCustomConfigurerTakesPrecedence() {
|
||||
load(WebFluxValidator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Validator validator = this.context.getBean(Validator.class);
|
||||
assertThat(validator)
|
||||
.isSameAs(this.context.getBean(WebFluxValidator.class).validator);
|
||||
public void validatorWhenUserDefinedSpringOnlyShouldUseDefined() throws Exception {
|
||||
load(UserDefinedSpringOnlyValidator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object webFluxValidator = this.context.getBean("webFluxValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(webFluxValidator).isSameAs(customValidator);
|
||||
assertThat(this.context.getBean(Validator.class)).isEqualTo(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationCustomConfigurerTakesPrecedenceAndDoNotExposeJsr303() {
|
||||
load(WebFluxJsr303Validator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Validator validator = this.context.getBean(Validator.class);
|
||||
assertThat(validator).isInstanceOf(SpringValidator.class);
|
||||
assertThat(((SpringValidator) validator).getTarget())
|
||||
.isSameAs(this.context.getBean(WebFluxJsr303Validator.class).validator);
|
||||
public void validatorWhenUserDefinedJsr303ShouldAdapt() throws Exception {
|
||||
load(UserDefinedJsr303Validator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object webFluxValidator = this.context.getBean("webFluxValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(webFluxValidator).isNotSameAs(customValidator);
|
||||
assertThat(this.context.getBean(javax.validation.Validator.class))
|
||||
.isEqualTo(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("jsr303ValidatorAdapter");
|
||||
assertThat(jsrValidatorBeans).containsExactly("customValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationJsr303CustomValidatorReusedAsSpringValidator() {
|
||||
load(CustomValidator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(2);
|
||||
Validator validator = this.context.getBean("webFluxValidator", Validator.class);
|
||||
assertThat(validator).isInstanceOf(SpringValidator.class);
|
||||
assertThat(((SpringValidator) validator).getTarget())
|
||||
.isSameAs(this.context.getBean(javax.validation.Validator.class));
|
||||
public void validatorWhenUserDefinedSingleJsr303AndSpringShouldUseDefined()
|
||||
throws Exception {
|
||||
load(UserDefinedSingleJsr303AndSpringValidator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object webFluxValidator = this.context.getBean("webFluxValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(webFluxValidator).isSameAs(customValidator);
|
||||
assertThat(this.context.getBean(javax.validation.Validator.class))
|
||||
.isEqualTo(customValidator);
|
||||
assertThat(this.context.getBean(Validator.class)).isEqualTo(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator");
|
||||
assertThat(jsrValidatorBeans).containsExactly("customValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationJsr303ValidatorExposedAsSpringValidator() {
|
||||
load(Jsr303Validator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Validator validator = this.context.getBean(Validator.class);
|
||||
assertThat(validator).isInstanceOf(SpringValidator.class);
|
||||
SpringValidatorAdapter target = ((SpringValidator) validator).getTarget();
|
||||
assertThat(new DirectFieldAccessor(target).getPropertyValue("targetValidator"))
|
||||
.isSameAs(this.context.getBean(javax.validation.Validator.class));
|
||||
public void validatorWhenUserDefinedJsr303AndSpringShouldUseDefined()
|
||||
throws Exception {
|
||||
load(UserDefinedJsr303AndSpringValidator.class);
|
||||
Object customJsrValidator = this.context.getBean("customJsrValidator");
|
||||
Object customSpringValidator = this.context.getBean("customSpringValidator");
|
||||
Object webFluxValidator = this.context.getBean("webFluxValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(customJsrValidator).isNotSameAs(customSpringValidator);
|
||||
assertThat(webFluxValidator).isSameAs(customSpringValidator);
|
||||
assertThat(this.context.getBean(javax.validation.Validator.class))
|
||||
.isEqualTo(customJsrValidator);
|
||||
assertThat(this.context.getBean(Validator.class))
|
||||
.isEqualTo(customSpringValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customSpringValidator");
|
||||
assertThat(jsrValidatorBeans).containsExactly("customJsrValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenExcludingValidatorAutoConfigurationShouldUseMvc()
|
||||
throws Exception {
|
||||
load(null, new Class[] { ValidationAutoConfiguration.class });
|
||||
Object webFluxValidator = this.context.getBean("webFluxValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(webFluxValidator).isInstanceOf(DelegatingValidator.class);
|
||||
assertThat(springValidatorBeans).containsExactly("webFluxValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenMultipleValidatorsAndNoWebFluxValidatorShouldAddMvc()
|
||||
throws Exception {
|
||||
load(MultipleValidatorsAndNoWebFluxValidator.class);
|
||||
Object customValidator1 = this.context.getBean("customValidator1");
|
||||
Object customValidator2 = this.context.getBean("customValidator2");
|
||||
Object webFluxValidator = this.context.getBean("webFluxValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(webFluxValidator).isNotSameAs(customValidator1)
|
||||
.isNotSameAs(customValidator2);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator1",
|
||||
"customValidator2", "webFluxValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenMultipleValidatorsAndWebFluxValidatorShouldUseMvc()
|
||||
throws Exception {
|
||||
load(MultipleValidatorsAndWebFluxValidator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object webFluxValidator = this.context.getBean("webFluxValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(webFluxValidator).isNotSameAs(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator",
|
||||
"webFluxValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
private void load(String... environment) {
|
||||
|
|
@ -230,13 +307,24 @@ public class WebFluxAnnotationAutoConfigurationTests {
|
|||
}
|
||||
|
||||
private void load(Class<?> config, String... environment) {
|
||||
load(config, null, environment);
|
||||
}
|
||||
|
||||
private void load(Class<?> config, Class<?>[] exclude, String... environment) {
|
||||
this.context = new GenericReactiveWebApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context, environment);
|
||||
List<Class<?>> configClasses = new ArrayList<>();
|
||||
if (config != null) {
|
||||
this.context.register(config);
|
||||
configClasses.add(config);
|
||||
}
|
||||
this.context.register(BaseConfiguration.class);
|
||||
configClasses.addAll(Arrays.asList(Config.class,
|
||||
ValidationAutoConfiguration.class, BaseConfiguration.class));
|
||||
if (!ObjectUtils.isEmpty(exclude)) {
|
||||
configClasses.removeAll(Arrays.asList(exclude));
|
||||
}
|
||||
this.context.register(configClasses.toArray(new Class<?>[configClasses.size()]));
|
||||
this.context.refresh();
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
|
@ -291,47 +379,88 @@ public class WebFluxAnnotationAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
protected static class WebFluxValidator implements WebFluxConfigurer {
|
||||
|
||||
private final Validator validator = mock(Validator.class);
|
||||
protected static class ValidatorWebFluxConfigurer implements WebFluxConfigurer {
|
||||
|
||||
@Override
|
||||
public Optional<Validator> getValidator() {
|
||||
return Optional.of(this.validator);
|
||||
return Optional.of(mock(Validator.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class WebFluxJsr303Validator implements WebFluxConfigurer {
|
||||
|
||||
private final LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
|
||||
@Override
|
||||
public Optional<Validator> getValidator() {
|
||||
return Optional.of(this.validator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Jsr303Validator {
|
||||
static class UserDefinedSpringOnlyValidator {
|
||||
|
||||
@Bean
|
||||
public javax.validation.Validator jsr303Validator() {
|
||||
public Validator customValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserDefinedJsr303Validator {
|
||||
|
||||
@Bean
|
||||
public javax.validation.Validator customValidator() {
|
||||
return mock(javax.validation.Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomValidator {
|
||||
static class UserDefinedSingleJsr303AndSpringValidator {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator() {
|
||||
public LocalValidatorFactoryBean customValidator() {
|
||||
return new LocalValidatorFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserDefinedJsr303AndSpringValidator {
|
||||
|
||||
@Bean
|
||||
public javax.validation.Validator customJsrValidator() {
|
||||
return mock(javax.validation.Validator.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator customSpringValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleValidatorsAndNoWebFluxValidator {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator1() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator customValidator2() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleValidatorsAndWebFluxValidator {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator webFluxValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import java.util.Map;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.ValidatorFactory;
|
||||
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.joda.time.DateTime;
|
||||
|
|
@ -37,11 +36,13 @@ import org.junit.Test;
|
|||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.SpringValidator;
|
||||
import org.springframework.boot.autoconfigure.validation.DelegatingValidator;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WelcomePageHandlerMapping;
|
||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
||||
|
|
@ -62,11 +63,11 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
|||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
||||
import org.springframework.web.filter.HttpPutFormContentFilter;
|
||||
|
|
@ -658,76 +659,154 @@ public class WebMvcAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void validationNoJsr303ValidatorExposedByDefault() {
|
||||
public void validatorWhenSuppliedByConfigurerShouldThrowException() throws Exception {
|
||||
this.thrown.expect(BeanCreationException.class);
|
||||
this.thrown.expectMessage("unexpected validator configuration");
|
||||
load(ValidatorWebMvcConfigurer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenAutoConfiguredShouldUseAlias() throws Exception {
|
||||
load();
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Object defaultValidator = this.context.getBean("defaultValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isSameAs(defaultValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("defaultValidator");
|
||||
assertThat(jsrValidatorBeans).containsExactly("defaultValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationCustomConfigurerTakesPrecedence() {
|
||||
load(MvcValidator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Validator validator = this.context.getBean(Validator.class);
|
||||
assertThat(validator)
|
||||
.isSameAs(this.context.getBean(MvcValidator.class).validator);
|
||||
public void validatorWhenUserDefinedSpringOnlyShouldUseDefined() throws Exception {
|
||||
load(UserDefinedSpringOnlyValidator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isSameAs(customValidator);
|
||||
assertThat(this.context.getBean(Validator.class)).isEqualTo(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationCustomConfigurerTakesPrecedenceAndDoNotExposeJsr303() {
|
||||
load(MvcJsr303Validator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Validator validator = this.context.getBean(Validator.class);
|
||||
assertThat(validator).isInstanceOf(SpringValidator.class);
|
||||
assertThat(((SpringValidator) validator).getTarget())
|
||||
.isSameAs(this.context.getBean(MvcJsr303Validator.class).validator);
|
||||
public void validatorWhenUserDefinedJsr303ShouldAdapt() throws Exception {
|
||||
load(UserDefinedJsr303Validator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isNotSameAs(customValidator);
|
||||
assertThat(this.context.getBean(javax.validation.Validator.class))
|
||||
.isEqualTo(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("jsr303ValidatorAdapter");
|
||||
assertThat(jsrValidatorBeans).containsExactly("customValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationJsr303CustomValidatorReusedAsSpringValidator() {
|
||||
load(CustomValidator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(2);
|
||||
Validator validator = this.context.getBean("mvcValidator", Validator.class);
|
||||
assertThat(validator).isInstanceOf(SpringValidator.class);
|
||||
assertThat(((SpringValidator) validator).getTarget())
|
||||
.isSameAs(this.context.getBean(javax.validation.Validator.class));
|
||||
public void validatorWhenUserDefinedSingleJsr303AndSpringShouldUseDefined()
|
||||
throws Exception {
|
||||
load(UserDefinedSingleJsr303AndSpringValidator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isSameAs(customValidator);
|
||||
assertThat(this.context.getBean(javax.validation.Validator.class))
|
||||
.isEqualTo(customValidator);
|
||||
assertThat(this.context.getBean(Validator.class)).isEqualTo(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator");
|
||||
assertThat(jsrValidatorBeans).containsExactly("customValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationJsr303ValidatorExposedAsSpringValidator() {
|
||||
load(Jsr303Validator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Validator validator = this.context.getBean(Validator.class);
|
||||
assertThat(validator).isInstanceOf(SpringValidator.class);
|
||||
SpringValidatorAdapter target = ((SpringValidator) validator).getTarget();
|
||||
assertThat(new DirectFieldAccessor(target).getPropertyValue("targetValidator"))
|
||||
.isSameAs(this.context.getBean(javax.validation.Validator.class));
|
||||
public void validatorWhenUserDefinedJsr303AndSpringShouldUseDefined()
|
||||
throws Exception {
|
||||
load(UserDefinedJsr303AndSpringValidator.class);
|
||||
Object customJsrValidator = this.context.getBean("customJsrValidator");
|
||||
Object customSpringValidator = this.context.getBean("customSpringValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(customJsrValidator).isNotSameAs(customSpringValidator);
|
||||
assertThat(mvcValidator).isSameAs(customSpringValidator);
|
||||
assertThat(this.context.getBean(javax.validation.Validator.class))
|
||||
.isEqualTo(customJsrValidator);
|
||||
assertThat(this.context.getBean(Validator.class))
|
||||
.isEqualTo(customSpringValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customSpringValidator");
|
||||
assertThat(jsrValidatorBeans).containsExactly("customJsrValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenExcludingValidatorAutoConfigurationShouldUseMvc()
|
||||
throws Exception {
|
||||
load(null, new Class[] { ValidationAutoConfiguration.class });
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isInstanceOf(DelegatingValidator.class);
|
||||
assertThat(springValidatorBeans).containsExactly("mvcValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenMultipleValidatorsAndNoMvcValidatorShouldAddMvc()
|
||||
throws Exception {
|
||||
load(MultipleValidatorsAndNoMvcValidator.class);
|
||||
Object customValidator1 = this.context.getBean("customValidator1");
|
||||
Object customValidator2 = this.context.getBean("customValidator2");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isNotSameAs(customValidator1)
|
||||
.isNotSameAs(customValidator2);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator1",
|
||||
"customValidator2", "mvcValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenMultipleValidatorsAndMvcValidatorShouldUseMvc()
|
||||
throws Exception {
|
||||
load(MultipleValidatorsAndMvcValidator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isNotSameAs(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator",
|
||||
"mvcValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
private void load(Class<?> config, String... environment) {
|
||||
load(config, null, environment);
|
||||
}
|
||||
|
||||
private void load(Class<?> config, Class<?>[] exclude, String... environment) {
|
||||
this.context = new AnnotationConfigServletWebServerApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context, environment);
|
||||
List<Class<?>> configClasses = new ArrayList<>();
|
||||
if (config != null) {
|
||||
configClasses.add(config);
|
||||
}
|
||||
configClasses.addAll(Arrays.asList(Config.class, WebMvcAutoConfiguration.class,
|
||||
configClasses.addAll(Arrays.asList(Config.class,
|
||||
ValidationAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class));
|
||||
if (!ObjectUtils.isEmpty(exclude)) {
|
||||
configClasses.removeAll(Arrays.asList(exclude));
|
||||
}
|
||||
this.context.register(configClasses.toArray(new Class<?>[configClasses.size()]));
|
||||
this.context.refresh();
|
||||
}
|
||||
|
|
@ -897,47 +976,88 @@ public class WebMvcAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
protected static class MvcValidator extends WebMvcConfigurerAdapter {
|
||||
|
||||
private final Validator validator = mock(Validator.class);
|
||||
protected static class ValidatorWebMvcConfigurer extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public Validator getValidator() {
|
||||
return this.validator;
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class MvcJsr303Validator extends WebMvcConfigurerAdapter {
|
||||
|
||||
private final LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
|
||||
@Override
|
||||
public Validator getValidator() {
|
||||
return this.validator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Jsr303Validator {
|
||||
static class UserDefinedSpringOnlyValidator {
|
||||
|
||||
@Bean
|
||||
public javax.validation.Validator jsr303Validator() {
|
||||
public Validator customValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserDefinedJsr303Validator {
|
||||
|
||||
@Bean
|
||||
public javax.validation.Validator customValidator() {
|
||||
return mock(javax.validation.Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomValidator {
|
||||
static class UserDefinedSingleJsr303AndSpringValidator {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator() {
|
||||
public LocalValidatorFactoryBean customValidator() {
|
||||
return new LocalValidatorFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserDefinedJsr303AndSpringValidator {
|
||||
|
||||
@Bean
|
||||
public javax.validation.Validator customJsrValidator() {
|
||||
return mock(javax.validation.Validator.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator customSpringValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleValidatorsAndNoMvcValidator {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator1() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator customValidator2() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleValidatorsAndMvcValidator {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator mvcValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import org.junit.rules.ExpectedException;
|
|||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
|
|
@ -129,9 +130,9 @@ public class BasicErrorControllerDirectMockMvcTests {
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import({ ServletWebServerFactoryAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
|
||||
protected @interface MinimalWebConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
|
|
@ -131,9 +132,9 @@ public class BasicErrorControllerMockMvcTests {
|
|||
@Documented
|
||||
@Import({ ServletWebServerFactoryAutoConfiguration.EmbeddedTomcat.class,
|
||||
ServletWebServerFactoryAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
|
||||
private @interface MinimalWebConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,4 +92,9 @@ public class OptionSetGroovyCompilerConfiguration implements GroovyCompilerConfi
|
|||
return this.repositoryConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQuiet() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ public class RunCommand extends OptionParsingCommand {
|
|||
|
||||
@Override
|
||||
public Level getLogLevel() {
|
||||
if (getOptions().has(RunOptionHandler.this.quietOption)) {
|
||||
if (isQuiet()) {
|
||||
return Level.OFF;
|
||||
}
|
||||
if (getOptions().has(RunOptionHandler.this.verboseOption)) {
|
||||
|
|
@ -149,6 +149,11 @@ public class RunCommand extends OptionParsingCommand {
|
|||
return Level.INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQuiet() {
|
||||
return getOptions().has(RunOptionHandler.this.quietOption);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,8 @@ public class GroovyCompiler {
|
|||
new SpringBootDependenciesDependencyManagement());
|
||||
|
||||
AetherGrapeEngine grapeEngine = AetherGrapeEngineFactory.create(this.loader,
|
||||
configuration.getRepositoryConfiguration(), resolutionContext);
|
||||
configuration.getRepositoryConfiguration(), resolutionContext,
|
||||
configuration.isQuiet());
|
||||
|
||||
GrapeEngineInstaller.install(grapeEngine);
|
||||
|
||||
|
|
|
|||
|
|
@ -71,4 +71,10 @@ public interface GroovyCompilerConfiguration {
|
|||
*/
|
||||
List<RepositoryConfiguration> getRepositoryConfiguration();
|
||||
|
||||
/**
|
||||
* Returns if running in quiet mode.
|
||||
* @return {@code true} if running in quiet mode
|
||||
*/
|
||||
boolean isQuiet();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public class AetherGrapeEngine implements GrapeEngine {
|
|||
RepositorySystem repositorySystem,
|
||||
DefaultRepositorySystemSession repositorySystemSession,
|
||||
List<RemoteRepository> remoteRepositories,
|
||||
DependencyResolutionContext resolutionContext) {
|
||||
DependencyResolutionContext resolutionContext, boolean quiet) {
|
||||
this.classLoader = classLoader;
|
||||
this.repositorySystem = repositorySystem;
|
||||
this.session = repositorySystemSession;
|
||||
|
|
@ -88,12 +88,14 @@ public class AetherGrapeEngine implements GrapeEngine {
|
|||
for (RemoteRepository repository : remotes) {
|
||||
addRepository(repository);
|
||||
}
|
||||
this.progressReporter = getProgressReporter(this.session);
|
||||
this.progressReporter = getProgressReporter(this.session, quiet);
|
||||
}
|
||||
|
||||
private ProgressReporter getProgressReporter(DefaultRepositorySystemSession session) {
|
||||
String progressReporter = System.getProperty(
|
||||
"org.springframework.boot.cli.compiler.grape.ProgressReporter");
|
||||
private ProgressReporter getProgressReporter(DefaultRepositorySystemSession session,
|
||||
boolean quiet) {
|
||||
String progressReporter = (quiet ? "none"
|
||||
: System.getProperty(
|
||||
"org.springframework.boot.cli.compiler.grape.ProgressReporter"));
|
||||
if ("detail".equals(progressReporter)
|
||||
|| Boolean.getBoolean("groovy.grape.report.downloads")) {
|
||||
return new DetailedProgressReporter(session, System.out);
|
||||
|
|
|
|||
|
|
@ -44,27 +44,21 @@ public abstract class AetherGrapeEngineFactory {
|
|||
|
||||
public static AetherGrapeEngine create(GroovyClassLoader classLoader,
|
||||
List<RepositoryConfiguration> repositoryConfigurations,
|
||||
DependencyResolutionContext dependencyResolutionContext) {
|
||||
|
||||
DependencyResolutionContext dependencyResolutionContext, boolean quiet) {
|
||||
RepositorySystem repositorySystem = createServiceLocator()
|
||||
.getService(RepositorySystem.class);
|
||||
|
||||
DefaultRepositorySystemSession repositorySystemSession = MavenRepositorySystemUtils
|
||||
.newSession();
|
||||
|
||||
ServiceLoader<RepositorySystemSessionAutoConfiguration> autoConfigurations = ServiceLoader
|
||||
.load(RepositorySystemSessionAutoConfiguration.class);
|
||||
|
||||
for (RepositorySystemSessionAutoConfiguration autoConfiguration : autoConfigurations) {
|
||||
autoConfiguration.apply(repositorySystemSession, repositorySystem);
|
||||
}
|
||||
|
||||
new DefaultRepositorySystemSessionAutoConfiguration()
|
||||
.apply(repositorySystemSession, repositorySystem);
|
||||
|
||||
return new AetherGrapeEngine(classLoader, repositorySystem,
|
||||
repositorySystemSession, createRepositories(repositoryConfigurations),
|
||||
dependencyResolutionContext);
|
||||
dependencyResolutionContext, quiet);
|
||||
}
|
||||
|
||||
private static ServiceLocator createServiceLocator() {
|
||||
|
|
|
|||
|
|
@ -81,6 +81,11 @@ public class GroovyGrabDependencyResolverTests {
|
|||
return new String[] { "." };
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQuiet() {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
this.resolver = new GroovyGrabDependencyResolver(configuration);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public class AetherGrapeEngineTests {
|
|||
dependencyResolutionContext.addDependencyManagement(
|
||||
new SpringBootDependenciesDependencyManagement());
|
||||
return AetherGrapeEngineFactory.create(this.groovyClassLoader,
|
||||
repositoryConfigurations, dependencyResolutionContext);
|
||||
repositoryConfigurations, dependencyResolutionContext, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -283,6 +283,8 @@ the `Main-Class` attribute and leave out `Start-Class`.
|
|||
* `loader.path` can contain directories (scanned recursively for jar and zip files),
|
||||
archive paths, a directory within an archive that is scanned for jar files (for
|
||||
example, `dependencies.jar!/lib`), or wildcard patterns (for the default JVM behavior).
|
||||
Archive paths can be relative to `loader.home`, or anywhere in the file system with a
|
||||
`jar:file:` prefix.
|
||||
* `loader.path` (if empty) defaults to `BOOT-INF/lib` (meaning a local directory or a
|
||||
nested one if running from an archive). Because of this `PropertiesLauncher` behaves the
|
||||
same as `JarLauncher` when no additional configuration is provided.
|
||||
|
|
|
|||
|
|
@ -250,8 +250,7 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
|
|||
protected Class<?>[] getOrFindConfigurationClasses(
|
||||
MergedContextConfiguration mergedConfig) {
|
||||
Class<?>[] classes = mergedConfig.getClasses();
|
||||
if (containsNonTestComponent(classes) || mergedConfig.hasLocations()
|
||||
|| !mergedConfig.getContextInitializerClasses().isEmpty()) {
|
||||
if (containsNonTestComponent(classes) || mergedConfig.hasLocations()) {
|
||||
return classes;
|
||||
}
|
||||
Class<?> found = new SpringBootConfigurationFinder()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.test.context.bootstrap;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
|
||||
import org.springframework.boot.test.context.bootstrap.SpringBootTestContextBootstrapperWithInitializersTests.CustomInitializer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.test.context.BootstrapWith;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link SpringBootTestContextBootstrapper} with and
|
||||
* {@link ApplicationContextInitializer}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@BootstrapWith(SpringBootTestContextBootstrapper.class)
|
||||
@ContextConfiguration(initializers = CustomInitializer.class)
|
||||
public class SpringBootTestContextBootstrapperWithInitializersTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
@Test
|
||||
public void foundConfiguration() throws Exception {
|
||||
Object bean = this.context
|
||||
.getBean(SpringBootTestContextBootstrapperExampleConfig.class);
|
||||
assertThat(bean).isNotNull();
|
||||
}
|
||||
|
||||
// gh-8483
|
||||
|
||||
public static class CustomInitializer
|
||||
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -25,8 +25,10 @@ import java.net.URL;
|
|||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
|
@ -299,11 +301,9 @@ public class PropertiesLauncher extends Launcher {
|
|||
List<String> paths = new ArrayList<>();
|
||||
for (String path : commaSeparatedPaths.split(",")) {
|
||||
path = cleanupPath(path);
|
||||
// Empty path (i.e. the archive itself if running from a JAR) is always added
|
||||
// to the classpath so no need for it to be explicitly listed
|
||||
if (!path.equals("")) {
|
||||
paths.add(path);
|
||||
}
|
||||
// "" means the user wants root of archive but not current directory
|
||||
path = ("".equals(path) ? "/" : path);
|
||||
paths.add(path);
|
||||
}
|
||||
if (paths.isEmpty()) {
|
||||
paths.add("lib");
|
||||
|
|
@ -336,7 +336,13 @@ public class PropertiesLauncher extends Launcher {
|
|||
|
||||
@Override
|
||||
protected ClassLoader createClassLoader(List<Archive> archives) throws Exception {
|
||||
ClassLoader loader = super.createClassLoader(archives);
|
||||
Set<URL> urls = new LinkedHashSet<URL>(archives.size());
|
||||
for (Archive archive : archives) {
|
||||
urls.add(archive.getUrl());
|
||||
}
|
||||
ClassLoader loader = new LaunchedURLClassLoader(urls.toArray(new URL[0]),
|
||||
getClass().getClassLoader());
|
||||
debug("Classpath: " + urls);
|
||||
String customLoaderClassName = getProperty("loader.classLoader");
|
||||
if (customLoaderClassName != null) {
|
||||
loader = wrapWithCustomClassLoader(loader, customLoaderClassName);
|
||||
|
|
@ -454,13 +460,15 @@ public class PropertiesLauncher extends Launcher {
|
|||
String root = cleanupPath(stripFileUrlPrefix(path));
|
||||
List<Archive> lib = new ArrayList<>();
|
||||
File file = new File(root);
|
||||
if (!isAbsolutePath(root)) {
|
||||
file = new File(this.home, root);
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
debug("Adding classpath entries from " + file);
|
||||
Archive archive = new ExplodedArchive(file, false);
|
||||
lib.add(archive);
|
||||
if (!"/".equals(root)) {
|
||||
if (!isAbsolutePath(root)) {
|
||||
file = new File(this.home, root);
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
debug("Adding classpath entries from " + file);
|
||||
Archive archive = new ExplodedArchive(file, false);
|
||||
lib.add(archive);
|
||||
}
|
||||
}
|
||||
Archive archive = getArchive(file);
|
||||
if (archive != null) {
|
||||
|
|
@ -488,24 +496,46 @@ public class PropertiesLauncher extends Launcher {
|
|||
return null;
|
||||
}
|
||||
|
||||
private List<Archive> getNestedArchives(String root) throws Exception {
|
||||
if (root.startsWith("/")
|
||||
|| this.parent.getUrl().equals(this.home.toURI().toURL())) {
|
||||
private List<Archive> getNestedArchives(String path) throws Exception {
|
||||
Archive parent = this.parent;
|
||||
String root = path;
|
||||
if (!root.equals("/") && root.startsWith("/")
|
||||
|| parent.getUrl().equals(this.home.toURI().toURL())) {
|
||||
// If home dir is same as parent archive, no need to add it twice.
|
||||
return null;
|
||||
}
|
||||
Archive parent = this.parent;
|
||||
if (root.startsWith("jar:file:") && root.contains("!")) {
|
||||
if (root.contains("!")) {
|
||||
int index = root.indexOf("!");
|
||||
String file = root.substring("jar:file:".length(), index);
|
||||
parent = new JarFileArchive(new File(file));
|
||||
File file = new File(this.home, root.substring(0, index));
|
||||
if (root.startsWith("jar:file:")) {
|
||||
file = new File(root.substring("jar:file:".length(), index));
|
||||
}
|
||||
parent = new JarFileArchive(file);
|
||||
root = root.substring(index + 1, root.length());
|
||||
while (root.startsWith("/")) {
|
||||
root = root.substring(1);
|
||||
}
|
||||
}
|
||||
if (root.endsWith(".jar")) {
|
||||
File file = new File(this.home, root);
|
||||
if (file.exists()) {
|
||||
parent = new JarFileArchive(file);
|
||||
root = "";
|
||||
}
|
||||
}
|
||||
if (root.equals("/") || root.equals("./") || root.equals(".")) {
|
||||
// The prefix for nested jars is actually empty if it's at the root
|
||||
root = "";
|
||||
}
|
||||
EntryFilter filter = new PrefixMatchingArchiveFilter(root);
|
||||
return parent.getNestedArchives(filter);
|
||||
List<Archive> archives = new ArrayList<Archive>(parent.getNestedArchives(filter));
|
||||
if (("".equals(root) || ".".equals(root)) && !path.endsWith(".jar")
|
||||
&& parent != this.parent) {
|
||||
// You can't find the root with an entry filter so it has to be added
|
||||
// explicitly. But don't add the root of the parent archive.
|
||||
archives.add(parent);
|
||||
}
|
||||
return archives;
|
||||
}
|
||||
|
||||
private void addNestedEntries(List<Archive> lib) {
|
||||
|
|
@ -518,7 +548,7 @@ public class PropertiesLauncher extends Launcher {
|
|||
@Override
|
||||
public boolean matches(Entry entry) {
|
||||
if (entry.isDirectory()) {
|
||||
return entry.getName().startsWith(JarLauncher.BOOT_INF_CLASSES);
|
||||
return entry.getName().equals(JarLauncher.BOOT_INF_CLASSES);
|
||||
}
|
||||
return entry.getName().startsWith(JarLauncher.BOOT_INF_LIB);
|
||||
}
|
||||
|
|
@ -607,6 +637,9 @@ public class PropertiesLauncher extends Launcher {
|
|||
|
||||
@Override
|
||||
public boolean matches(Entry entry) {
|
||||
if (entry.isDirectory()) {
|
||||
return entry.getName().equals(this.prefix);
|
||||
}
|
||||
return entry.getName().startsWith(this.prefix) && this.filter.matches(entry);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,13 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
|
@ -36,6 +37,9 @@ import org.junit.rules.TemporaryFolder;
|
|||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
|
@ -72,6 +76,7 @@ public class PropertiesLauncherTests {
|
|||
System.clearProperty("loader.config.name");
|
||||
System.clearProperty("loader.config.location");
|
||||
System.clearProperty("loader.system");
|
||||
System.clearProperty("loader.classLoader");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -131,6 +136,16 @@ public class PropertiesLauncherTests {
|
|||
.isEqualTo("[.]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedSlashPath() throws Exception {
|
||||
System.setProperty("loader.path", "jars/");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[jars/]");
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).areExactly(1, endingWith("app.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedWildcardPath() throws Exception {
|
||||
System.setProperty("loader.path", "jars/*");
|
||||
|
|
@ -153,13 +168,44 @@ public class PropertiesLauncherTests {
|
|||
waitFor("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedRootOfJarPath() throws Exception {
|
||||
System.setProperty("loader.path",
|
||||
"jar:file:./src/test/resources/nested-jars/app.jar!/");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[jar:file:./src/test/resources/nested-jars/app.jar!/]");
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
|
||||
assertThat(archives).areExactly(1, endingWith("app.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedRootOfJarPathWithDot() throws Exception {
|
||||
System.setProperty("loader.path", "nested-jars/app.jar!/./");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
|
||||
assertThat(archives).areExactly(1, endingWith("app.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedRootOfJarPathWithDotAndJarPrefix() throws Exception {
|
||||
System.setProperty("loader.path",
|
||||
"jar:file:./src/test/resources/nested-jars/app.jar!/./");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedJarFileWithNestedArchives() throws Exception {
|
||||
System.setProperty("loader.path", "nested-jars/app.jar");
|
||||
System.setProperty("loader.main", "demo.Application");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
launcher.launch(new String[0]);
|
||||
waitFor("Hello World");
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
|
||||
assertThat(archives).areExactly(1, endingWith("app.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -209,11 +255,28 @@ public class PropertiesLauncherTests {
|
|||
public void testCustomClassLoaderCreation() throws Exception {
|
||||
System.setProperty("loader.classLoader", TestLoader.class.getName());
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
ClassLoader loader = launcher.createClassLoader(Collections.<Archive>emptyList());
|
||||
ClassLoader loader = launcher.createClassLoader(archives());
|
||||
assertThat(loader).isNotNull();
|
||||
assertThat(loader.getClass().getName()).isEqualTo(TestLoader.class.getName());
|
||||
}
|
||||
|
||||
private List<Archive> archives() throws Exception {
|
||||
List<Archive> archives = new ArrayList<Archive>();
|
||||
String path = System.getProperty("java.class.path");
|
||||
for (String url : path.split(File.pathSeparator)) {
|
||||
archives.add(archive(url));
|
||||
}
|
||||
return archives;
|
||||
}
|
||||
|
||||
private Archive archive(String url) throws IOException {
|
||||
File file = new FileSystemResource(url).getFile();
|
||||
if (url.endsWith(".jar")) {
|
||||
return new JarFileArchive(file);
|
||||
}
|
||||
return new ExplodedArchive(file);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedConfigPathWins() throws Exception {
|
||||
|
||||
|
|
@ -280,6 +343,17 @@ public class PropertiesLauncherTests {
|
|||
assertThat(timeout).as("Timed out waiting for (" + value + ")").isTrue();
|
||||
}
|
||||
|
||||
private Condition<Archive> endingWith(final String value) {
|
||||
return new Condition<Archive>() {
|
||||
|
||||
@Override
|
||||
public boolean matches(Archive archive) {
|
||||
return archive.toString().endsWith(value);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static class TestLoader extends URLClassLoader {
|
||||
|
||||
public TestLoader(ClassLoader parent) {
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue