, ApplicationContextAware, MessageSourceAware, InitializingBean {
-
- private static final char[] EXACT_DELIMITERS = { '_', '.', '[' };
-
- private static final char[] TARGET_NAME_DELIMITERS = { '_', '.' };
-
- private static final Log logger = LogFactory.getLog(PropertiesConfigurationFactory.class);
-
- private boolean ignoreUnknownFields = true;
-
- private boolean ignoreInvalidFields;
-
- private boolean exceptionIfInvalid = true;
-
- private PropertySources propertySources;
-
- private final T target;
-
- private Validator validator;
-
- private ApplicationContext applicationContext;
-
- private MessageSource messageSource;
-
- private boolean hasBeenBound = false;
-
- private boolean ignoreNestedProperties = false;
-
- private String targetName;
-
- private ConversionService conversionService;
-
- private boolean resolvePlaceholders = true;
-
- /**
- * Create a new {@link PropertiesConfigurationFactory} instance.
- *
- * @param target the target object to bind too
- * @see #PropertiesConfigurationFactory(Class)
- */
- public PropertiesConfigurationFactory(T target){
- Assert.notNull(target, "target must not be null");
- this.target = target;
- }
-
- /**
- * Create a new {@link PropertiesConfigurationFactory} instance.
- *
- * @param type the target type
- * @see #PropertiesConfigurationFactory(Class)
- */
- @SuppressWarnings("unchecked")
- public PropertiesConfigurationFactory(Class> type){
- Assert.notNull(type, "type must not be null");
- this.target = (T) BeanUtils.instantiate(type);
- }
-
- /**
- * Flag to disable binding of nested properties (i.e. those with period
- * separators in their paths). Can be useful to disable this if the name prefix
- * is empty and you don't want to ignore unknown fields.
- *
- * @param ignoreNestedProperties the flag to set (default false)
- */
- public void setIgnoreNestedProperties(boolean ignoreNestedProperties) {
- this.ignoreNestedProperties = ignoreNestedProperties;
- }
-
- /**
- * Set whether to ignore unknown fields, that is, whether to ignore bind
- * parameters that do not have corresponding fields in the target object.
- *
- * Default is "true". Turn this off to enforce that all bind parameters must
- * have a matching field in the target object.
- *
- * @param ignoreUnknownFields if unknown fields should be ignored
- */
- public void setIgnoreUnknownFields(boolean ignoreUnknownFields) {
- this.ignoreUnknownFields = ignoreUnknownFields;
- }
-
- /**
- * Set whether to ignore invalid fields, that is, whether to ignore bind
- * parameters that have corresponding fields in the target object which are not
- * accessible (for example because of null values in the nested path).
- *
- * Default is "false". Turn this on to ignore bind parameters for nested objects
- * in non-existing parts of the target object graph.
- *
- * @param ignoreInvalidFields if invalid fields should be ignored
- */
- public void setIgnoreInvalidFields(boolean ignoreInvalidFields) {
- this.ignoreInvalidFields = ignoreInvalidFields;
- }
-
- /**
- * Set the target name.
- *
- * @param targetName the target name
- */
- public void setTargetName(String targetName) {
- this.targetName = targetName;
- }
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) {
- this.applicationContext = applicationContext;
- }
-
- /**
- * Set the message source.
- *
- * @param messageSource the message source
- */
- @Override
- public void setMessageSource(MessageSource messageSource) {
- this.messageSource = messageSource;
- }
-
- /**
- * Set the property sources.
- *
- * @param propertySources the property sources
- */
- public void setPropertySources(PropertySources propertySources) {
- this.propertySources = propertySources;
- }
-
- /**
- * Set the conversion service.
- *
- * @param conversionService the conversion service
- */
- public void setConversionService(ConversionService conversionService) {
- this.conversionService = conversionService;
- }
-
- /**
- * Set the validator.
- *
- * @param validator the validator
- */
- public void setValidator(Validator validator) {
- this.validator = validator;
- }
-
- /**
- * Set a flag to indicate that an exception should be raised if a Validator is
- * available and validation fails.
- *
- * @param exceptionIfInvalid the flag to set
- * @deprecated as of 1.5, do not specify a {@link Validator} if validation
- * should not occur
- */
- @Deprecated
- public void setExceptionIfInvalid(boolean exceptionIfInvalid) {
- this.exceptionIfInvalid = exceptionIfInvalid;
- }
-
- /**
- * Flag to indicate that placeholders should be replaced during binding. Default
- * is true.
- *
- * @param resolvePlaceholders flag value
- */
- public void setResolvePlaceholders(boolean resolvePlaceholders) {
- this.resolvePlaceholders = resolvePlaceholders;
- }
-
- @Override
- public void afterPropertiesSet() throws Exception {
- bindPropertiesToTarget();
- }
-
- @Override
- public Class> getObjectType() {
- if (this.target == null) {
- return Object.class;
- }
- return this.target.getClass();
- }
-
- @Override
- public boolean isSingleton() {
- return true;
- }
-
- @Override
- public T getObject() throws Exception {
- if (!this.hasBeenBound) {
- bindPropertiesToTarget();
- }
- return this.target;
- }
-
- public void bindPropertiesToTarget() throws BindException {
- Assert.state(this.propertySources != null, "PropertySources should not be null");
- try {
- if (logger.isTraceEnabled()) {
- logger.trace("Property Sources: " + this.propertySources);
-
- }
- this.hasBeenBound = true;
- doBindPropertiesToTarget();
- } catch (BindException ex) {
- if (this.exceptionIfInvalid) {
- throw ex;
- }
- logger.error("Failed to load Properties validation bean. " + "Your Properties may be invalid.", ex);
- }
- }
-
- private void doBindPropertiesToTarget() throws BindException {
- RelaxedDataBinder dataBinder = (this.targetName != null ? new RelaxedDataBinder(this.target,
- this.targetName) : new RelaxedDataBinder(this.target));
- if (this.validator != null && this.validator.supports(dataBinder.getTarget().getClass())) {
- dataBinder.setValidator(this.validator);
- }
- if (this.conversionService != null) {
- dataBinder.setConversionService(this.conversionService);
- }
- dataBinder.setAutoGrowCollectionLimit(Integer.MAX_VALUE);
- dataBinder.setIgnoreNestedProperties(this.ignoreNestedProperties);
- dataBinder.setIgnoreInvalidFields(this.ignoreInvalidFields);
- dataBinder.setIgnoreUnknownFields(this.ignoreUnknownFields);
- customizeBinder(dataBinder);
- if (this.applicationContext != null) {
- ResourceEditorRegistrar resourceEditorRegistrar = new ResourceEditorRegistrar(this.applicationContext,
- this.applicationContext.getEnvironment());
- resourceEditorRegistrar.registerCustomEditors(dataBinder);
- }
- Iterable relaxedTargetNames = getRelaxedTargetNames();
- Set names = getNames(relaxedTargetNames);
- PropertyValues propertyValues = getPropertySourcesPropertyValues(names, relaxedTargetNames);
- dataBinder.bind(propertyValues);
- if (this.validator != null) {
- dataBinder.validate();
- }
- checkForBindingErrors(dataBinder);
- }
-
- private Iterable getRelaxedTargetNames() {
- return (this.target != null
- && StringUtils.hasLength(this.targetName) ? new RelaxedNames(this.targetName) : null);
- }
-
- private Set getNames(Iterable prefixes) {
- Set names = new LinkedHashSet<>();
- if (this.target != null) {
- PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(this.target.getClass());
- for (PropertyDescriptor descriptor : descriptors) {
- String name = descriptor.getName();
- if (!name.equals("class")) {
- RelaxedNames relaxedNames = RelaxedNames.forCamelCase(name);
- if (prefixes == null) {
- for (String relaxedName : relaxedNames) {
- names.add(relaxedName);
- }
- } else {
- for (String prefix : prefixes) {
- for (String relaxedName : relaxedNames) {
- names.add(prefix + "." + relaxedName);
- names.add(prefix + "_" + relaxedName);
- }
- }
- }
- }
- }
- }
- return names;
- }
-
- private PropertyValues getPropertySourcesPropertyValues(Set names, Iterable relaxedTargetNames) {
- PropertyNamePatternsMatcher includes = getPropertyNamePatternsMatcher(names, relaxedTargetNames);
- return new PropertySourcesPropertyValues(this.propertySources, names, includes, this.resolvePlaceholders);
- }
-
- private PropertyNamePatternsMatcher getPropertyNamePatternsMatcher(Set names,
- Iterable relaxedTargetNames) {
- if (this.ignoreUnknownFields && !isMapTarget()) {
- // Since unknown fields are ignored we can filter them out early to save
- // unnecessary calls to the PropertySource.
- return new DefaultPropertyNamePatternsMatcher(EXACT_DELIMITERS, true, names);
- }
- if (relaxedTargetNames != null) {
- // We can filter properties to those starting with the target name, but
- // we can't do a complete filter since we need to trigger the
- // unknown fields check
- Set relaxedNames = new HashSet<>();
- for (String relaxedTargetName : relaxedTargetNames) {
- relaxedNames.add(relaxedTargetName);
- }
- return new DefaultPropertyNamePatternsMatcher(TARGET_NAME_DELIMITERS, true, relaxedNames);
- }
- // Not ideal, we basically can't filter anything
- return PropertyNamePatternsMatcher.ALL;
- }
-
- private boolean isMapTarget() {
- return this.target != null && Map.class.isAssignableFrom(this.target.getClass());
- }
-
- private void checkForBindingErrors(RelaxedDataBinder dataBinder) throws BindException {
- BindingResult errors = dataBinder.getBindingResult();
- if (errors.hasErrors()) {
- logger.error("Properties configuration failed validation");
- for (ObjectError error : errors.getAllErrors()) {
- logger.error(this.messageSource != null ? this.messageSource.getMessage(error, Locale.getDefault())
- + " (" + error + ")" : error);
- }
- if (this.exceptionIfInvalid) {
- throw new BindException(errors);
- }
- }
- }
-
- /**
- * Customize the data binder.
- *
- * @param dataBinder the data binder that will be used to bind and validate
- */
- protected void customizeBinder(DataBinder dataBinder) {
- }
-}
diff --git a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertyNamePatternsMatcher.java b/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertyNamePatternsMatcher.java
deleted file mode 100644
index 47d8a780cf..0000000000
--- a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertyNamePatternsMatcher.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.alibaba.otter.canal.client.adapter.config.bind;
-
-/**
- * Strategy interface used to check if a property name matches specific
- * criteria.
- *
- * @author Phillip Webb
- * @since 1.2.0
- */
-interface PropertyNamePatternsMatcher {
-
- PropertyNamePatternsMatcher ALL = propertyName -> true;
-
- PropertyNamePatternsMatcher NONE = propertyName -> false;
-
- /**
- * Return {@code true} of the property name matches.
- *
- * @param propertyName the property name
- * @return {@code true} if the property name matches
- */
- boolean matches(String propertyName);
-
-}
diff --git a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertyOrigin.java b/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertyOrigin.java
deleted file mode 100644
index 7ad35f1a63..0000000000
--- a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertyOrigin.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.alibaba.otter.canal.client.adapter.config.bind;
-
-import com.alibaba.otter.canal.client.adapter.config.common.PropertySource;
-
-/**
- * The origin of a property, specifically its source and its name before any
- * prefix was removed.
- *
- * @author Andy Wilkinson
- * @since 1.3.0
- */
-public class PropertyOrigin {
-
- private final PropertySource> source;
-
- private final String name;
-
- PropertyOrigin(PropertySource> source, String name){
- this.name = name;
- this.source = source;
- }
-
- public PropertySource> getSource() {
- return this.source;
- }
-
- public String getName() {
- return this.name;
- }
-}
diff --git a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertySourcesPropertyResolver.java b/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertySourcesPropertyResolver.java
deleted file mode 100644
index 520e857faa..0000000000
--- a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertySourcesPropertyResolver.java
+++ /dev/null
@@ -1,164 +0,0 @@
-package com.alibaba.otter.canal.client.adapter.config.bind;
-
-import org.springframework.core.convert.ConversionException;
-import org.springframework.core.env.AbstractEnvironment;
-import org.springframework.core.env.AbstractPropertyResolver;
-import org.springframework.core.env.PropertyResolver;
-import org.springframework.util.ClassUtils;
-
-import com.alibaba.otter.canal.client.adapter.config.common.PropertySource;
-import com.alibaba.otter.canal.client.adapter.config.common.PropertySources;
-
-/**
- * {@link PropertyResolver} implementation that resolves property values against
- * an underlying set of {@link PropertySources}.
- *
- * @author Chris Beams
- * @author Juergen Hoeller
- * @see PropertySource
- * @see PropertySources
- * @see AbstractEnvironment
- * @since 3.1
- */
-public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
-
- private final PropertySources propertySources;
-
- /**
- * Create a new resolver against the given property sources.
- *
- * @param propertySources the set of {@link PropertySource} objects to use
- */
- public PropertySourcesPropertyResolver(PropertySources propertySources){
- this.propertySources = propertySources;
- }
-
- @Override
- public boolean containsProperty(String key) {
- if (this.propertySources != null) {
- for (PropertySource> propertySource : this.propertySources) {
- if (propertySource.containsProperty(key)) {
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public String getProperty(String key) {
- return getProperty(key, String.class, true);
- }
-
- @Override
- public T getProperty(String key, Class targetValueType) {
- return getProperty(key, targetValueType, true);
- }
-
- @Override
- protected String getPropertyAsRawString(String key) {
- return getProperty(key, String.class, false);
- }
-
- protected T getProperty(String key, Class targetValueType, boolean resolveNestedPlaceholders) {
- if (this.propertySources != null) {
- for (PropertySource> propertySource : this.propertySources) {
- if (logger.isTraceEnabled()) {
- logger
- .trace("Searching for key '" + key + "' in PropertySource '" + propertySource.getName() + "'");
- }
- Object value = propertySource.getProperty(key);
- if (value != null) {
- if (resolveNestedPlaceholders && value instanceof String) {
- value = resolveNestedPlaceholders((String) value);
- }
- logKeyFound(key, propertySource, value);
- return convertValueIfNecessary(value, targetValueType);
- }
- }
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Could not find key '" + key + "' in any property source");
- }
- return null;
- }
-
- @Deprecated
- public Class getPropertyAsClass(String key, Class targetValueType) {
- if (this.propertySources != null) {
- for (PropertySource> propertySource : this.propertySources) {
- if (logger.isTraceEnabled()) {
- logger.trace(String.format("Searching for key '%s' in [%s]", key, propertySource.getName()));
- }
- Object value = propertySource.getProperty(key);
- if (value != null) {
- logKeyFound(key, propertySource, value);
- Class> clazz;
- if (value instanceof String) {
- try {
- clazz = ClassUtils.forName((String) value, null);
- } catch (Exception ex) {
- throw new PropertySourcesPropertyResolver.ClassConversionException((String) value,
- targetValueType,
- ex);
- }
- } else if (value instanceof Class) {
- clazz = (Class>) value;
- } else {
- clazz = value.getClass();
- }
- if (!targetValueType.isAssignableFrom(clazz)) {
- throw new PropertySourcesPropertyResolver.ClassConversionException(clazz, targetValueType);
- }
- @SuppressWarnings("unchecked")
- Class targetClass = (Class) clazz;
- return targetClass;
- }
- }
- }
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("Could not find key '%s' in any property source", key));
- }
- return null;
- }
-
- /**
- * Log the given key as found in the given {@link PropertySource}, resulting in
- * the given value.
- *
- * The default implementation writes a debug log message with key and source. As
- * of 4.3.3, this does not log the value anymore in order to avoid accidental
- * logging of sensitive settings. Subclasses may override this method to change
- * the log level and/or log message, including the property's value if desired.
- *
- * @param key the key found
- * @param propertySource the {@code PropertySource} that the key has been found
- * in
- * @param value the corresponding value
- * @since 4.3.1
- */
- protected void logKeyFound(String key, PropertySource> propertySource, Object value) {
- if (logger.isDebugEnabled()) {
- logger.debug("Found key '" + key + "' in PropertySource '" + propertySource.getName()
- + "' with value of type " + value.getClass().getSimpleName());
- }
- }
-
- @SuppressWarnings("serial")
- @Deprecated
- private static class ClassConversionException extends ConversionException {
-
- public ClassConversionException(Class> actual, Class> expected){
- super(String
- .format("Actual type %s is not assignable to expected type %s", actual.getName(), expected.getName()));
- }
-
- public ClassConversionException(String actual, Class> expected, Exception ex){
- super(
- String
- .format("Could not find/load class %s during attempt to convert to %s", actual, expected.getName()),
- ex);
- }
- }
-
-}
diff --git a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertySourcesPropertyValues.java b/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertySourcesPropertyValues.java
deleted file mode 100644
index 70ad5731af..0000000000
--- a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/PropertySourcesPropertyValues.java
+++ /dev/null
@@ -1,233 +0,0 @@
-package com.alibaba.otter.canal.client.adapter.config.bind;
-
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.regex.Pattern;
-
-import org.springframework.beans.MutablePropertyValues;
-import org.springframework.beans.PropertyValue;
-import org.springframework.beans.PropertyValues;
-import org.springframework.util.Assert;
-import org.springframework.validation.DataBinder;
-
-import com.alibaba.otter.canal.client.adapter.config.common.CompositePropertySource;
-import com.alibaba.otter.canal.client.adapter.config.common.EnumerablePropertySource;
-import com.alibaba.otter.canal.client.adapter.config.common.PropertySource;
-import com.alibaba.otter.canal.client.adapter.config.common.PropertySources;
-
-/**
- * A {@link PropertyValues} implementation backed by a {@link PropertySources},
- * bridging the two abstractions and allowing (for instance) a regular
- * {@link DataBinder} to be used with the latter.
- *
- * @author Dave Syer
- * @author Phillip Webb
- */
-public class PropertySourcesPropertyValues implements PropertyValues {
-
- private static final Pattern COLLECTION_PROPERTY = Pattern
- .compile("\\[(\\d+)\\](\\.\\S+)?");
-
- private final PropertySources propertySources;
-
- private final Collection nonEnumerableFallbackNames;
-
- private final PropertyNamePatternsMatcher includes;
-
- private final Map propertyValues = new LinkedHashMap<>();
-
- private final ConcurrentHashMap> collectionOwners = new ConcurrentHashMap<>();
-
- private final boolean resolvePlaceholders;
-
- /**
- * Create a new PropertyValues from the given PropertySources.
- *
- * @param propertySources a PropertySources instance
- */
- public PropertySourcesPropertyValues(PropertySources propertySources){
- this(propertySources, true);
- }
-
- /**
- * Create a new PropertyValues from the given PropertySources that will
- * optionally resolve placeholders.
- *
- * @param propertySources a PropertySources instance
- * @param resolvePlaceholders {@code true} if placeholders should be resolved.
- * @since 1.5.2
- */
- public PropertySourcesPropertyValues(PropertySources propertySources, boolean resolvePlaceholders){
- this(propertySources, (Collection) null, PropertyNamePatternsMatcher.ALL, resolvePlaceholders);
- }
-
- /**
- * Create a new PropertyValues from the given PropertySources.
- *
- * @param propertySources a PropertySources instance
- * @param includePatterns property name patterns to include from system
- * properties and environment variables
- * @param nonEnumerableFallbackNames the property names to try in lieu of an
- * {@link EnumerablePropertySource}.
- */
- public PropertySourcesPropertyValues(PropertySources propertySources, Collection includePatterns,
- Collection nonEnumerableFallbackNames){
- this(propertySources,
- nonEnumerableFallbackNames,
- new PatternPropertyNamePatternsMatcher(includePatterns),
- true);
- }
-
- /**
- * Create a new PropertyValues from the given PropertySources.
- *
- * @param propertySources a PropertySources instance
- * @param nonEnumerableFallbackNames the property names to try in lieu of an
- * {@link EnumerablePropertySource}.
- * @param includes the property name patterns to include
- * @param resolvePlaceholders flag to indicate the placeholders should be
- * resolved
- */
- PropertySourcesPropertyValues(PropertySources propertySources, Collection nonEnumerableFallbackNames,
- PropertyNamePatternsMatcher includes, boolean resolvePlaceholders){
- Assert.notNull(propertySources, "PropertySources must not be null");
- Assert.notNull(includes, "Includes must not be null");
- this.propertySources = propertySources;
- this.nonEnumerableFallbackNames = nonEnumerableFallbackNames;
- this.includes = includes;
- this.resolvePlaceholders = resolvePlaceholders;
- PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
- for (PropertySource> source : propertySources) {
- processPropertySource(source, resolver);
- }
- }
-
- private void processPropertySource(PropertySource> source, PropertySourcesPropertyResolver resolver) {
- if (source instanceof CompositePropertySource) {
- processCompositePropertySource((CompositePropertySource) source, resolver);
- } else if (source instanceof EnumerablePropertySource) {
- processEnumerablePropertySource((EnumerablePropertySource>) source, resolver, this.includes);
- } else {
- processNonEnumerablePropertySource(source, resolver);
- }
- }
-
- private void processCompositePropertySource(CompositePropertySource source,
- PropertySourcesPropertyResolver resolver) {
- for (PropertySource> nested : source.getPropertySources()) {
- processPropertySource(nested, resolver);
- }
- }
-
- private void processEnumerablePropertySource(EnumerablePropertySource> source,
- PropertySourcesPropertyResolver resolver,
- PropertyNamePatternsMatcher includes) {
- if (source.getPropertyNames().length > 0) {
- for (String propertyName : source.getPropertyNames()) {
- if (includes.matches(propertyName)) {
- Object value = getEnumerableProperty(source, resolver, propertyName);
- putIfAbsent(propertyName, value, source);
- }
- }
- }
- }
-
- private Object getEnumerableProperty(EnumerablePropertySource> source, PropertySourcesPropertyResolver resolver,
- String propertyName) {
- try {
- if (this.resolvePlaceholders) {
- return resolver.getProperty(propertyName, Object.class);
- }
- } catch (RuntimeException ex) {
- // Probably could not resolve placeholders, ignore it here
- }
- return source.getProperty(propertyName);
- }
-
- private void processNonEnumerablePropertySource(PropertySource> source,
- PropertySourcesPropertyResolver resolver) {
- // We can only do exact matches for non-enumerable property names, but
- // that's better than nothing...
- if (this.nonEnumerableFallbackNames == null) {
- return;
- }
- for (String propertyName : this.nonEnumerableFallbackNames) {
- if (!source.containsProperty(propertyName)) {
- continue;
- }
- Object value = null;
- try {
- value = resolver.getProperty(propertyName, Object.class);
- } catch (RuntimeException ex) {
- // Probably could not convert to Object, weird, but ignorable
- }
- if (value == null) {
- value = source.getProperty(propertyName.toUpperCase(Locale.ENGLISH));
- }
- putIfAbsent(propertyName, value, source);
- }
- }
-
- @Override
- public PropertyValue[] getPropertyValues() {
- Collection values = this.propertyValues.values();
- return values.toArray(new PropertyValue[values.size()]);
- }
-
- @Override
- public PropertyValue getPropertyValue(String propertyName) {
- PropertyValue propertyValue = this.propertyValues.get(propertyName);
- if (propertyValue != null) {
- return propertyValue;
- }
- for (PropertySource> source : this.propertySources) {
- Object value = source.getProperty(propertyName);
- propertyValue = putIfAbsent(propertyName, value, source);
- if (propertyValue != null) {
- return propertyValue;
- }
- }
- return null;
- }
-
- private PropertyValue putIfAbsent(String propertyName, Object value, PropertySource> source) {
- if (value != null && !this.propertyValues.containsKey(propertyName)) {
- PropertySource> collectionOwner = this.collectionOwners
- .putIfAbsent(COLLECTION_PROPERTY.matcher(propertyName).replaceAll("[]"), source);
- if (collectionOwner == null || collectionOwner == source) {
- PropertyValue propertyValue = new OriginCapablePropertyValue(propertyName, value, propertyName, source);
- this.propertyValues.put(propertyName, propertyValue);
- return propertyValue;
- }
- }
- return null;
- }
-
- @Override
- public PropertyValues changesSince(PropertyValues old) {
- MutablePropertyValues changes = new MutablePropertyValues();
- // for each property value in the new set
- for (PropertyValue newValue : getPropertyValues()) {
- // if there wasn't an old one, add it
- PropertyValue oldValue = old.getPropertyValue(newValue.getName());
- if (oldValue == null || !oldValue.equals(newValue)) {
- changes.addPropertyValue(newValue);
- }
- }
- return changes;
- }
-
- @Override
- public boolean contains(String propertyName) {
- return getPropertyValue(propertyName) != null;
- }
-
- @Override
- public boolean isEmpty() {
- return this.propertyValues.isEmpty();
- }
-
-}
diff --git a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/RelaxedConversionService.java b/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/RelaxedConversionService.java
deleted file mode 100644
index ab8e550673..0000000000
--- a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/RelaxedConversionService.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package com.alibaba.otter.canal.client.adapter.config.bind;
-
-import java.util.EnumSet;
-import java.util.Locale;
-import java.util.Set;
-
-import org.springframework.core.convert.ConversionFailedException;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.core.convert.TypeDescriptor;
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.core.convert.converter.ConverterFactory;
-import org.springframework.core.convert.support.DefaultConversionService;
-import org.springframework.core.convert.support.GenericConversionService;
-import org.springframework.util.Assert;
-
-/**
- * Internal {@link ConversionService} used by {@link RelaxedDataBinder} to
- * support additional relaxed conversion.
- *
- * @author Phillip Webb
- * @author Stephane Nicoll
- * @since 1.1.0
- */
-class RelaxedConversionService implements ConversionService {
-
- private final ConversionService conversionService;
-
- private final GenericConversionService additionalConverters;
-
- /**
- * Create a new {@link RelaxedConversionService} instance.
- *
- * @param conversionService and option root conversion service
- */
- RelaxedConversionService(ConversionService conversionService){
- this.conversionService = conversionService;
- this.additionalConverters = new GenericConversionService();
- DefaultConversionService.addCollectionConverters(this.additionalConverters);
- this.additionalConverters
- .addConverterFactory(new RelaxedConversionService.StringToEnumIgnoringCaseConverterFactory());
- this.additionalConverters.addConverter(new StringToCharArrayConverter());
- }
-
- @Override
- public boolean canConvert(Class> sourceType, Class> targetType) {
- return (this.conversionService != null && this.conversionService.canConvert(sourceType, targetType))
- || this.additionalConverters.canConvert(sourceType, targetType);
- }
-
- @Override
- public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
- return (this.conversionService != null && this.conversionService.canConvert(sourceType, targetType))
- || this.additionalConverters.canConvert(sourceType, targetType);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public T convert(Object source, Class targetType) {
- Assert.notNull(targetType, "The targetType to convert to cannot be null");
- return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
- }
-
- @Override
- public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
- if (this.conversionService != null) {
- try {
- return this.conversionService.convert(source, sourceType, targetType);
- } catch (ConversionFailedException ex) {
- // Ignore and try the additional converters
- }
- }
- return this.additionalConverters.convert(source, sourceType, targetType);
- }
-
- /**
- * Clone of Spring's package private StringToEnumConverterFactory, but ignoring
- * the case of the source.
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- private static class StringToEnumIgnoringCaseConverterFactory implements ConverterFactory {
-
- @Override
- public Converter getConverter(Class targetType) {
- Class> enumType = targetType;
- while (enumType != null && !enumType.isEnum()) {
- enumType = enumType.getSuperclass();
- }
- Assert.notNull(enumType, "The target type " + targetType.getName() + " does not refer to an enum");
- return new RelaxedConversionService.StringToEnumIgnoringCaseConverterFactory.StringToEnum(enumType);
- }
-
- private static class StringToEnum implements Converter {
-
- private final Class enumType;
-
- StringToEnum(Class enumType){
- this.enumType = enumType;
- }
-
- @Override
- public T convert(String source) {
- if (source.isEmpty()) {
- // It's an empty enum identifier: reset the enum value to null.
- return null;
- }
- source = source.trim();
- for (T candidate : (Set) EnumSet.allOf(this.enumType)) {
- RelaxedNames names = new RelaxedNames(
- candidate.name().replace('_', '-').toLowerCase(Locale.ENGLISH));
- for (String name : names) {
- if (name.equals(source)) {
- return candidate;
- }
- }
- if (candidate.name().equalsIgnoreCase(source)) {
- return candidate;
- }
- }
- throw new IllegalArgumentException(
- "No enum constant " + this.enumType.getCanonicalName() + "." + source);
- }
-
- }
-
- }
-
-}
diff --git a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/RelaxedDataBinder.java b/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/RelaxedDataBinder.java
deleted file mode 100644
index 7723eb0f16..0000000000
--- a/client-adapter/common/src/main/java/com/alibaba/otter/canal/client/adapter/config/bind/RelaxedDataBinder.java
+++ /dev/null
@@ -1,729 +0,0 @@
-package com.alibaba.otter.canal.client.adapter.config.bind;
-
-import java.beans.PropertyEditor;
-import java.net.InetAddress;
-import java.util.*;
-
-import org.springframework.beans.*;
-import org.springframework.beans.propertyeditors.FileEditor;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.core.convert.TypeDescriptor;
-import org.springframework.core.env.StandardEnvironment;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-import org.springframework.util.StringUtils;
-import org.springframework.validation.AbstractPropertyBindingResult;
-import org.springframework.validation.BeanPropertyBindingResult;
-import org.springframework.validation.DataBinder;
-
-/**
- * Binder implementation that allows caller to bind to maps and also allows
- * property names to match a bit loosely (if underscores or dashes are removed
- * and replaced with camel case for example).
- *
- * @author Dave Syer
- * @author Phillip Webb
- * @author Stephane Nicoll
- * @author Andy Wilkinson
- * @see RelaxedNames
- */
-public class RelaxedDataBinder extends DataBinder {
-
- private static final Set> EXCLUDED_EDITORS;
-
- static {
- Set> excluded = new HashSet<>();
- excluded.add(FileEditor.class);
- EXCLUDED_EDITORS = Collections.unmodifiableSet(excluded);
- }
-
- private static final Object BLANK = new Object();
-
- private String namePrefix;
-
- private boolean ignoreNestedProperties;
-
- private MultiValueMap nameAliases = new LinkedMultiValueMap<>();
-
- /**
- * Create a new {@link RelaxedDataBinder} instance.
- *
- * @param target the target into which properties are bound
- */
- public RelaxedDataBinder(Object target){
- super(wrapTarget(target));
- }
-
- /**
- * Create a new {@link RelaxedDataBinder} instance.
- *
- * @param target the target into which properties are bound
- * @param namePrefix An optional prefix to be used when reading properties
- */
- public RelaxedDataBinder(Object target, String namePrefix){
- super(wrapTarget(target), (StringUtils.hasLength(namePrefix) ? namePrefix : DEFAULT_OBJECT_NAME));
- this.namePrefix = cleanNamePrefix(namePrefix);
- }
-
- private String cleanNamePrefix(String namePrefix) {
- if (!StringUtils.hasLength(namePrefix)) {
- return null;
- }
- return (namePrefix.endsWith(".") ? namePrefix : namePrefix + ".");
- }
-
- /**
- * Flag to disable binding of nested properties (i.e. those with period
- * separators in their paths). Can be useful to disable this if the name prefix
- * is empty and you don't want to ignore unknown fields.
- *
- * @param ignoreNestedProperties the flag to set (default false)
- */
- public void setIgnoreNestedProperties(boolean ignoreNestedProperties) {
- this.ignoreNestedProperties = ignoreNestedProperties;
- }
-
- /**
- * Set name aliases.
- *
- * @param aliases a map of property name to aliases
- */
- public void setNameAliases(Map> aliases) {
- this.nameAliases = new LinkedMultiValueMap<>(aliases);
- }
-
- /**
- * Add aliases to the {@link DataBinder}.
- *
- * @param name the property name to alias
- * @param alias aliases for the property names
- * @return this instance
- */
- public RelaxedDataBinder withAlias(String name, String... alias) {
- for (String value : alias) {
- this.nameAliases.add(name, value);
- }
- return this;
- }
-
- @Override
- protected void doBind(MutablePropertyValues propertyValues) {
- super.doBind(modifyProperties(propertyValues, getTarget()));
- }
-
- /**
- * Modify the property values so that period separated property paths are valid
- * for map keys. Also creates new maps for properties of map type that are null
- * (assuming all maps are potentially nested). The standard bracket {@code[...]}
- * dereferencing is also accepted.
- *
- * @param propertyValues the property values
- * @param target the target object
- * @return modified property values
- */
- private MutablePropertyValues modifyProperties(MutablePropertyValues propertyValues, Object target) {
- propertyValues = getPropertyValuesForNamePrefix(propertyValues);
- if (target instanceof RelaxedDataBinder.MapHolder) {
- propertyValues = addMapPrefix(propertyValues);
- }
- BeanWrapper wrapper = new BeanWrapperImpl(target);
- wrapper.setConversionService(new RelaxedConversionService(getConversionService()));
- wrapper.setAutoGrowNestedPaths(true);
- List sortedValues = new ArrayList<>();
- Set modifiedNames = new HashSet<>();
- List sortedNames = getSortedPropertyNames(propertyValues);
- for (String name : sortedNames) {
- PropertyValue propertyValue = propertyValues.getPropertyValue(name);
- PropertyValue modifiedProperty = modifyProperty(wrapper, propertyValue);
- if (modifiedNames.add(modifiedProperty.getName())) {
- sortedValues.add(modifiedProperty);
- }
- }
- return new MutablePropertyValues(sortedValues);
- }
-
- private List getSortedPropertyNames(MutablePropertyValues propertyValues) {
- List names = new LinkedList<>();
- for (PropertyValue propertyValue : propertyValues.getPropertyValueList()) {
- names.add(propertyValue.getName());
- }
- sortPropertyNames(names);
- return names;
- }
-
- /**
- * Sort by name so that parent properties get processed first (e.g. 'foo.bar'
- * before 'foo.bar.spam'). Don't use Collections.sort() because the order might
- * be significant for other property names (it shouldn't be but who knows what
- * people might be relying on, e.g. HSQL has a JDBCXADataSource where
- * "databaseName" is a synonym for "url").
- *
- * @param names the names to sort
- */
- private void sortPropertyNames(List names) {
- for (String name : new ArrayList<>(names)) {
- int propertyIndex = names.indexOf(name);
- RelaxedDataBinder.BeanPath path = new RelaxedDataBinder.BeanPath(name);
- for (String prefix : path.prefixes()) {
- int prefixIndex = names.indexOf(prefix);
- if (prefixIndex >= propertyIndex) {
- // The child property has a parent in the list in the wrong order
- names.remove(name);
- names.add(prefixIndex, name);
- }
- }
- }
- }
-
- private MutablePropertyValues addMapPrefix(MutablePropertyValues propertyValues) {
- MutablePropertyValues rtn = new MutablePropertyValues();
- for (PropertyValue pv : propertyValues.getPropertyValues()) {
- rtn.add("map." + pv.getName(), pv.getValue());
- }
- return rtn;
- }
-
- private MutablePropertyValues getPropertyValuesForNamePrefix(MutablePropertyValues propertyValues) {
- if (!StringUtils.hasText(this.namePrefix) && !this.ignoreNestedProperties) {
- return propertyValues;
- }
- MutablePropertyValues rtn = new MutablePropertyValues();
- for (PropertyValue value : propertyValues.getPropertyValues()) {
- String name = value.getName();
- for (String prefix : new RelaxedNames(stripLastDot(this.namePrefix))) {
- for (String separator : new String[] { ".", "_" }) {
- String candidate = (StringUtils.hasLength(prefix) ? prefix + separator : prefix);
- if (name.startsWith(candidate)) {
- name = name.substring(candidate.length());
- if (!(this.ignoreNestedProperties && name.contains("."))) {
- PropertyOrigin propertyOrigin = OriginCapablePropertyValue.getOrigin(value);
- rtn.addPropertyValue(
- new OriginCapablePropertyValue(name, value.getValue(), propertyOrigin));
- }
- }
- }
- }
- }
- return rtn;
- }
-
- private String stripLastDot(String string) {
- if (StringUtils.hasLength(string) && string.endsWith(".")) {
- string = string.substring(0, string.length() - 1);
- }
- return string;
- }
-
- private PropertyValue modifyProperty(BeanWrapper target, PropertyValue propertyValue) {
- String name = propertyValue.getName();
- String normalizedName = normalizePath(target, name);
- if (!normalizedName.equals(name)) {
- return new PropertyValue(normalizedName, propertyValue.getValue());
- }
- return propertyValue;
- }
-
- /**
- * Normalize a bean property path to a format understood by a BeanWrapper. This
- * is used so that
- *
- * - Fuzzy matching can be employed for bean property names
- * - Period separators can be used instead of indexing ([...]) for map
- * keys
- *
- *
- * @param wrapper a bean wrapper for the object to bind
- * @param path the bean path to bind
- * @return a transformed path with correct bean wrapper syntax
- */
- protected String normalizePath(BeanWrapper wrapper, String path) {
- return initializePath(wrapper, new RelaxedDataBinder.BeanPath(path), 0);
- }
-
- @Override
- protected AbstractPropertyBindingResult createBeanPropertyBindingResult() {
- return new RelaxedDataBinder.RelaxedBeanPropertyBindingResult(getTarget(),
- getObjectName(),
- isAutoGrowNestedPaths(),
- getAutoGrowCollectionLimit(),
- getConversionService());
- }
-
- private String initializePath(BeanWrapper wrapper, RelaxedDataBinder.BeanPath path, int index) {
- String prefix = path.prefix(index);
- String key = path.name(index);
- if (path.isProperty(index)) {
- key = getActualPropertyName(wrapper, prefix, key);
- path.rename(index, key);
- }
- if (path.name(++index) == null) {
- return path.toString();
- }
- String name = path.prefix(index);
- TypeDescriptor descriptor = wrapper.getPropertyTypeDescriptor(name);
- if (descriptor == null || descriptor.isMap()) {
- if (isMapValueStringType(descriptor) || isBlanked(wrapper, name, path.name(index))) {
- path.collapseKeys(index);
- }
- path.mapIndex(index);
- extendMapIfNecessary(wrapper, path, index);
- } else if (descriptor.isCollection()) {
- extendCollectionIfNecessary(wrapper, path, index);
- } else if (descriptor.getType().equals(Object.class)) {
- if (isBlanked(wrapper, name, path.name(index))) {
- path.collapseKeys(index);
- }
- path.mapIndex(index);
- if (path.isLastNode(index)) {
- wrapper.setPropertyValue(path.toString(), BLANK);
- } else {
- String next = path.prefix(index + 1);
- if (wrapper.getPropertyValue(next) == null) {
- wrapper.setPropertyValue(next, new LinkedHashMap());
- }
- }
- }
- return initializePath(wrapper, path, index);
- }
-
- private boolean isMapValueStringType(TypeDescriptor descriptor) {
- if (descriptor == null || descriptor.getMapValueTypeDescriptor() == null) {
- return false;
- }
- if (Properties.class.isAssignableFrom(descriptor.getObjectType())) {
- // Properties is declared as Map