|
20 | 20 | import java.util.HashMap;
|
21 | 21 | import java.util.Map;
|
22 | 22 |
|
| 23 | +import org.apache.commons.logging.Log; |
| 24 | +import org.apache.commons.logging.LogFactory; |
| 25 | + |
23 | 26 | import org.springframework.beans.BeanUtils;
|
24 | 27 | import org.springframework.beans.BeansException;
|
25 | 28 | import org.springframework.boot.context.properties.bind.Bindable;
|
26 | 29 | 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; |
29 | 32 | import org.springframework.context.ApplicationContext;
|
30 | 33 | import org.springframework.context.ApplicationContextAware;
|
31 | 34 | import org.springframework.context.ConfigurableApplicationContext;
|
32 | 35 | 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; |
33 | 41 | /**
|
34 | 42 | * Base implementation of {@link ExtendedBindingProperties}.
|
35 | 43 | *
|
|
39 | 47 | * @author Oleg Zhurakousky
|
40 | 48 | * @since 2.1
|
41 | 49 | */
|
| 50 | +@Validated |
42 | 51 | public abstract class AbstractExtendedBindingProperties<C, P, T extends BinderSpecificPropertiesProvider>
|
43 | 52 | implements ExtendedBindingProperties<C, P>, ApplicationContextAware {
|
44 | 53 |
|
| 54 | + static Log logger = LogFactory.getLog(AbstractExtendedBindingProperties.class); |
| 55 | + |
45 | 56 | private final Map<String, T> bindings = new HashMap<>();
|
46 | 57 |
|
47 | 58 | private ConfigurableApplicationContext applicationContext = new GenericApplicationContext();
|
@@ -83,21 +94,69 @@ private void bindIfNecessary(String bindingName) {
|
83 | 94 | private void bindToDefault(String binding) {
|
84 | 95 | T extendedBindingPropertiesTarget = (T) BeanUtils
|
85 | 96 | .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 | + } |
96 | 109 | this.bindings.put(binding, extendedBindingPropertiesTarget);
|
97 | 110 | }
|
98 | 111 |
|
99 | 112 | protected Map<String, T> doGetBindings() {
|
100 | 113 | return Collections.unmodifiableMap(this.bindings);
|
101 | 114 | }
|
102 | 115 |
|
| 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 | + } |
103 | 162 | }
|
0 commit comments