in dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java [780:939]
private void assignProperties(
Object obj,
Environment environment,
Map<String, String> properties,
InmemoryConfiguration configuration,
ConfigMode configMode) {
// if old one (this) contains non-null value, do not override
boolean overrideIfAbsent = configMode == ConfigMode.OVERRIDE_IF_ABSENT;
// even if old one (this) contains non-null value, do override
boolean overrideAll = configMode == ConfigMode.OVERRIDE_ALL;
FrameworkModel frameworkModel = ScopeModelUtil.getFrameworkModel(getScopeModel());
// loop methods, get override value and set the new value back to method
List<Method> methods =
MethodUtils.getMethods(obj.getClass(), method -> method.getDeclaringClass() != Object.class);
for (Method method : methods) {
// filter non attribute
Parameter parameter = method.getAnnotation(Parameter.class);
if (parameter != null && !parameter.attribute()) {
continue;
}
if (isPropertySetter(method)) {
String propertyName = extractPropertyName(method.getName());
// if config mode is OVERRIDE_IF_ABSENT and property has set, skip
if (overrideIfAbsent && isPropertySet(methods, propertyName)) {
continue;
}
// convert camelCase/snake_case to kebab-case
String kebabPropertyName = StringUtils.convertToSplitName(propertyName, "-");
try {
String value = StringUtils.trim(configuration.getString(kebabPropertyName));
Class<?> paramType = method.getParameterTypes()[0];
if (paramType.isArray()) {
if (isIgnoredAttribute(obj.getClass(), propertyName)) {
continue;
}
Class<?> itemType = paramType.getComponentType();
List<Object> items = new ArrayList<>();
if (StringUtils.hasText(value)) {
value = environment.resolvePlaceholders(value);
if (StringUtils.hasText(value)) {
for (String item : StringUtils.tokenize(value, ',')) {
items.add(ClassUtils.convertPrimitive(frameworkModel, itemType, item));
}
}
} else {
for (int i = 0; ; i++) {
value = StringUtils.trim(configuration.getString(kebabPropertyName + '[' + i + ']'));
if (value == null) {
break;
}
if (StringUtils.hasText(value)) {
value = environment.resolvePlaceholders(value);
if (StringUtils.hasText(value)) {
items.add(ClassUtils.convertPrimitive(frameworkModel, itemType, value));
}
}
}
}
int len = items.size();
if (len > 0) {
Object array = Array.newInstance(itemType, len);
for (int i = 0; i < len; i++) {
Array.set(array, i, items.get(i));
}
method.invoke(obj, array);
}
continue;
}
// isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two
// 'setGeneric' methods in ReferenceConfig.
if (StringUtils.hasText(value)
&& ClassUtils.isTypeMatch(paramType, value)
&& !isIgnoredAttribute(obj.getClass(), propertyName)) {
value = environment.resolvePlaceholders(value);
if (StringUtils.hasText(value)) {
Object arg = ClassUtils.convertPrimitive(frameworkModel, paramType, value);
if (arg != null) {
method.invoke(obj, arg);
}
}
}
} catch (Exception e) {
logger.info("Failed to override the property " + method.getName() + " in "
+ obj.getClass().getSimpleName()
+ ", please make sure every property has getter/setter method provided.");
}
} else if (isParametersSetter(method)) {
String propertyName = extractPropertyName(method.getName());
String value = StringUtils.trim(configuration.getString(propertyName));
Map<String, String> parameterMap;
if (StringUtils.hasText(value)) {
parameterMap = StringUtils.parseParameters(value);
} else {
// in this case, maybe parameters.item3=value3.
parameterMap = ConfigurationUtils.getSubProperties(properties, PARAMETERS);
}
Map<String, String> newMap = convert(parameterMap, "");
if (CollectionUtils.isEmptyMap(newMap)) {
continue;
}
// get old map from original obj
Map<String, String> oldMap = null;
try {
String getterName = calculatePropertyToGetter(propertyName);
Method getterMethod = this.getClass().getMethod(getterName);
Object oldOne = getterMethod.invoke(this);
if (oldOne instanceof Map) {
oldMap = (Map) oldOne;
}
} catch (Exception ignore) {
}
// if old map is null, directly set params
if (oldMap == null) {
invokeSetParameters(newMap, obj);
continue;
}
// if mode is OVERRIDE_IF_ABSENT, put all old map entries to new map, will override the same key
// if mode is OVERRIDE_ALL, put all keyed entries not in new map from old map to new map (ignore the
// same key appeared in old map)
// if mode is others, override with new map
if (overrideIfAbsent) {
newMap.putAll(oldMap);
} else if (overrideAll) {
oldMap.forEach(newMap::putIfAbsent);
}
invokeSetParameters(newMap, obj);
} else if (isNestedSetter(obj, method)) {
try {
Class<?> clazz = method.getParameterTypes()[0];
Object inner = clazz.getDeclaredConstructor().newInstance();
String fieldName = MethodUtils.extractFieldName(method);
Map<String, String> subProperties = ConfigurationUtils.getSubProperties(properties, fieldName);
InmemoryConfiguration subPropsConfiguration = new InmemoryConfiguration(subProperties);
assignProperties(inner, environment, subProperties, subPropsConfiguration, configMode);
method.invoke(obj, inner);
} catch (ReflectiveOperationException e) {
throw new IllegalStateException(
"Cannot assign nested class when refreshing config: "
+ obj.getClass().getName(),
e);
}
}
}
}