Upgrade to hibernate-validator 5.3.4

Upgrade to `hibernate-validator` 5.3.4 and introduce a new
`MessageInterpolatorFactory` that creates a suitable
`MessageInterpolator` (taking into account missing EL dependencies).

Rework `ConfigurationPropertiesBindingPostProcessor` and
`ValidationAutoConfiguration` to make use of the new factory.

Fixes gh-7598
This commit is contained in:
Phillip Webb 2017-01-04 18:28:32 -08:00
parent d80f22c227
commit eb22220961
7 changed files with 211 additions and 2 deletions

View File

@ -27,6 +27,7 @@ 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.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.validation.MessageInterpolatorFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
@ -51,7 +52,10 @@ public class ValidationAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public Validator validator() {
return new LocalValidatorFactoryBean();
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
return factoryBean;
}
@Bean

View File

@ -87,7 +87,7 @@
<hazelcast-hibernate4.version>3.7.1</hazelcast-hibernate4.version>
<hazelcast-hibernate5.version>1.1.3</hazelcast-hibernate5.version>
<hibernate.version>5.0.11.Final</hibernate.version>
<hibernate-validator.version>5.2.4.Final</hibernate-validator.version>
<hibernate-validator.version>5.3.4.Final</hibernate-validator.version>
<hikaricp.version>2.5.1</hikaricp.version>
<hikaricp-java6.version>2.3.13</hikaricp-java6.version>
<hsqldb.version>2.3.3</hsqldb.version>

View File

@ -35,6 +35,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.bind.PropertiesConfigurationFactory;
import org.springframework.boot.validation.MessageInterpolatorFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
@ -400,7 +401,9 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
public Validator run(ApplicationContext applicationContext) {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
validator.setApplicationContext(applicationContext);
validator.setMessageInterpolator(interpolatorFactory.getObject());
validator.afterPropertiesSet();
return validator;
}

View File

@ -0,0 +1,83 @@
/*
* 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.validation;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.validation.MessageInterpolator;
import javax.validation.Validation;
import javax.validation.ValidationException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.util.ClassUtils;
/**
* {@link ObjectFactory} that can be used to create a {@link MessageInterpolatorFactory}.
* Attempts to pick the most appropriate {@link MessageInterpolator} based on the
* classpath.
*
* @author Phillip Webb
*/
public class MessageInterpolatorFactory implements ObjectFactory<MessageInterpolator> {
private static final Set<String> FALLBACKS;
static {
Set<String> fallbacks = new LinkedHashSet<String>();
fallbacks.add("org.hibernate.validator.messageinterpolation"
+ ".ParameterMessageInterpolator");
FALLBACKS = Collections.unmodifiableSet(fallbacks);
}
@Override
public MessageInterpolator getObject() throws BeansException {
try {
return Validation.byDefaultProvider().configure()
.getDefaultMessageInterpolator();
}
catch (ValidationException ex) {
MessageInterpolator fallback = getFallback();
if (fallback != null) {
return fallback;
}
throw ex;
}
}
private MessageInterpolator getFallback() {
for (String fallback : FALLBACKS) {
try {
return getFallback(fallback);
}
catch (Exception ex) {
// Swallow an continue
}
}
return null;
}
private MessageInterpolator getFallback(String fallback) {
Class<?> interpolatorClass = ClassUtils.resolveClassName(fallback, null);
Object interpolator = BeanUtils.instantiate(interpolatorClass);
return (MessageInterpolator) interpolator;
}
}

View File

@ -0,0 +1,20 @@
/*
* 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.
*/
/**
* Utilities and classes related to validation.
*/
package org.springframework.boot.validation;

View File

@ -0,0 +1,39 @@
/*
* 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.validation;
import javax.validation.MessageInterpolator;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MessageInterpolatorFactory}.
*
* @author Phillip Webb
*/
public class MessageInterpolatorFactoryTests {
@Test
public void getObjectShouldReturnResourceBundleMessageInterpolator() {
MessageInterpolator interpolator = new MessageInterpolatorFactory().getObject();
assertThat(interpolator).isInstanceOf(ResourceBundleMessageInterpolator.class);
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.validation;
import javax.validation.MessageInterpolator;
import javax.validation.Validation;
import javax.validation.ValidationException;
import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.springframework.boot.junit.runner.classpath.ClassPathExclusions;
import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link MessageInterpolatorFactory} without EL.
*
* @author Phillip Webb
*/
@RunWith(ModifiedClassPathRunner.class)
@ClassPathExclusions("tomcat-embed-el-*.jar")
public class MessageInterpolatorFactoryWithoutElIntegrationTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void defaultMessageInterpolatorShouldFail() throws Exception {
// Sanity test
this.thrown.expect(ValidationException.class);
this.thrown.expectMessage("javax.el.ExpressionFactory");
Validation.byDefaultProvider().configure().getDefaultMessageInterpolator();
}
@Test
public void getObjectShouldUseFallback() {
MessageInterpolator interpolator = new MessageInterpolatorFactory().getObject();
assertThat(interpolator).isInstanceOf(ParameterMessageInterpolator.class);
}
}