|
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