Skip to content

Commit e642cad

Browse files
committed
GH-2974 Fix validation when only 'default' properties are used
Resolves #2974
1 parent 8148d55 commit e642cad

File tree

1 file changed

+71
-12
lines changed

1 file changed

+71
-12
lines changed

core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractExtendedBindingProperties.java

+71-12
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,24 @@
2020
import java.util.HashMap;
2121
import java.util.Map;
2222

23+
import org.apache.commons.logging.Log;
24+
import org.apache.commons.logging.LogFactory;
25+
2326
import org.springframework.beans.BeanUtils;
2427
import org.springframework.beans.BeansException;
2528
import org.springframework.boot.context.properties.bind.Bindable;
2629
import org.springframework.boot.context.properties.bind.Binder;
27-
import org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver;
28-
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
30+
import org.springframework.boot.context.properties.bind.validation.ValidationBindHandler;
31+
import org.springframework.boot.validation.MessageInterpolatorFactory;
2932
import org.springframework.context.ApplicationContext;
3033
import org.springframework.context.ApplicationContextAware;
3134
import org.springframework.context.ConfigurableApplicationContext;
3235
import org.springframework.context.support.GenericApplicationContext;
36+
import org.springframework.util.ClassUtils;
37+
import org.springframework.validation.Errors;
38+
import org.springframework.validation.Validator;
39+
import org.springframework.validation.annotation.Validated;
40+
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
3341
/**
3442
* Base implementation of {@link ExtendedBindingProperties}.
3543
*
@@ -39,9 +47,12 @@
3947
* @author Oleg Zhurakousky
4048
* @since 2.1
4149
*/
50+
@Validated
4251
public abstract class AbstractExtendedBindingProperties<C, P, T extends BinderSpecificPropertiesProvider>
4352
implements ExtendedBindingProperties<C, P>, ApplicationContextAware {
4453

54+
static Log logger = LogFactory.getLog(AbstractExtendedBindingProperties.class);
55+
4556
private final Map<String, T> bindings = new HashMap<>();
4657

4758
private ConfigurableApplicationContext applicationContext = new GenericApplicationContext();
@@ -83,21 +94,69 @@ private void bindIfNecessary(String bindingName) {
8394
private void bindToDefault(String binding) {
8495
T extendedBindingPropertiesTarget = (T) BeanUtils
8596
.instantiateClass(this.getExtendedPropertiesEntryClass());
86-
Binder binder = new Binder(
87-
ConfigurationPropertySources
88-
.get(this.applicationContext.getEnvironment()),
89-
new PropertySourcesPlaceholdersResolver(
90-
this.applicationContext.getEnvironment()),
91-
this.applicationContext.getBeanFactory().getConversionService(),
92-
null);
93-
94-
binder.bind(this.getDefaultsPrefix(),
95-
Bindable.ofInstance(extendedBindingPropertiesTarget));
97+
98+
Binder binder = Binder.get(this.applicationContext.getEnvironment());
99+
100+
if (Jsr303Validator.isJsr303Present(this.applicationContext)) {
101+
Jsr303Validator validator = new Jsr303Validator(this.applicationContext);
102+
binder.bind(this.getDefaultsPrefix(),
103+
Bindable.ofInstance(extendedBindingPropertiesTarget), new ValidationBindHandler(validator));
104+
}
105+
else {
106+
binder.bind(this.getDefaultsPrefix(),
107+
Bindable.ofInstance(extendedBindingPropertiesTarget));
108+
}
96109
this.bindings.put(binding, extendedBindingPropertiesTarget);
97110
}
98111

99112
protected Map<String, T> doGetBindings() {
100113
return Collections.unmodifiableMap(this.bindings);
101114
}
102115

116+
private class Jsr303Validator implements Validator {
117+
118+
private static final String[] VALIDATOR_CLASSES = { "jakarta.validation.Validator",
119+
"jakarta.validation.ValidatorFactory", "jakarta.validation.bootstrap.GenericBootstrap" };
120+
121+
private final Delegate delegate;
122+
123+
Jsr303Validator(ApplicationContext applicationContext) {
124+
this.delegate = new Delegate(applicationContext);
125+
}
126+
127+
@Override
128+
public boolean supports(Class<?> type) {
129+
return this.delegate.supports(type);
130+
}
131+
132+
@Override
133+
public void validate(Object target, Errors errors) {
134+
this.delegate.validate(target, errors);
135+
}
136+
137+
static boolean isJsr303Present(ApplicationContext applicationContext) {
138+
ClassLoader classLoader = applicationContext.getClassLoader();
139+
for (String validatorClass : VALIDATOR_CLASSES) {
140+
if (!ClassUtils.isPresent(validatorClass, classLoader)) {
141+
return false;
142+
}
143+
}
144+
return true;
145+
}
146+
147+
private static class Delegate extends LocalValidatorFactoryBean {
148+
149+
Delegate(ApplicationContext applicationContext) {
150+
setApplicationContext(applicationContext);
151+
setMessageInterpolator(new MessageInterpolatorFactory(applicationContext).getObject());
152+
try {
153+
afterPropertiesSet();
154+
}
155+
catch (Exception e) {
156+
logger.warn("Failed to execute afterPropertiesSet() on aplication context", e);
157+
}
158+
}
159+
160+
}
161+
}
103162
}

0 commit comments

Comments
 (0)