Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #8378 parameter convert error #8379

Merged
merged 1 commit into from Aug 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -16,12 +16,12 @@
*/
package org.apache.dubbo.config.spring.beans.factory.annotation;

import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.config.ConsumerConfig;
import org.apache.dubbo.config.MethodConfig;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.util.DubboAnnotationUtils;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationAttributes;
Expand All @@ -39,7 +39,6 @@
import static org.apache.dubbo.config.spring.util.DubboAnnotationUtils.resolveServiceInterfaceClass;
import static org.apache.dubbo.config.spring.util.DubboBeanUtils.getOptionalBean;
import static org.springframework.core.annotation.AnnotationAttributes.fromMap;
import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;

/**
* {@link ReferenceBean} Builder
Expand Down Expand Up @@ -124,19 +123,11 @@ protected void preConfigureBean(AnnotationAttributes attributes, ReferenceBean r
dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true));
dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws java.lang.IllegalArgumentException {
// Trim all whitespace
String content = StringUtils.trimAllWhitespace(text);
if (!StringUtils.hasText(content)) { // No content , ignore directly
return;
public void setValue(Object value) {
if (value instanceof String[]) {
value = DubboAnnotationUtils.convertParameters((String[]) value);
}
// replace "=" to ","
content = StringUtils.replace(content, "=", ",");
// replace ":" to ","
content = StringUtils.replace(content, ":", ",");
// String[] to Map
Map<String, String> parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content));
setValue(parameters);
super.setValue(value);
}
});

Expand Down
Expand Up @@ -18,7 +18,6 @@

import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.config.MethodConfig;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.annotation.Method;
Expand All @@ -27,7 +26,7 @@
import org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener;
import org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner;
import org.apache.dubbo.config.spring.schema.AnnotationBeanDefinitionParser;

import org.apache.dubbo.config.spring.util.DubboAnnotationUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware;
Expand Down Expand Up @@ -62,10 +61,8 @@
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

Expand Down Expand Up @@ -414,7 +411,7 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnno
// Set interface
builder.addPropertyValue("interface", interfaceClass.getName());
// Convert parameters into map
builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));
builder.addPropertyValue("parameters", DubboAnnotationUtils.convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));
// Add methods parameters
List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
if (!methodConfigs.isEmpty()) {
Expand Down Expand Up @@ -511,22 +508,6 @@ private void addPropertyReference(BeanDefinitionBuilder builder, String property
builder.addPropertyReference(propertyName, resolvedBeanName);
}

private Map<String, String> convertParameters(String[] parameters) {
if (ArrayUtils.isEmpty(parameters)) {
return null;
}

if (parameters.length % 2 != 0) {
throw new IllegalArgumentException("parameter attribute must be paired with key followed by value");
}

Map<String, String> map = new HashMap<>();
for (int i = 0; i < parameters.length; i += 2) {
map.put(parameters[i], parameters[i + 1]);
}
return map;
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

Expand Down
Expand Up @@ -16,13 +16,20 @@
*/
package org.apache.dubbo.config.spring.util;

import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;

import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.alibaba.spring.util.AnnotationUtils.getAttribute;
import static org.springframework.util.ClassUtils.getAllInterfacesForClass;
import static org.springframework.util.ClassUtils.resolveClassName;
Expand Down Expand Up @@ -147,4 +154,59 @@ public static String resolveInterfaceName(Reference reference, Class<?> defaultI

return interfaceName;
}

/**
* Resolve the parameters of {@link org.apache.dubbo.config.annotation.DubboService}
* and {@link org.apache.dubbo.config.annotation.DubboReference} from the specified.
* It iterate elements in order.The former element plays as key or key&value role, it would be
* spilt if it contain specific string, for instance, ":" and "=". As for later element can't
* be split in anytime.It will throw IllegalArgumentException If converted array length isn't
* even number.
* The convert cases below work in right way,which are best practice.
* <p>
* (array->map)
* ["a","b"] ==> {a=b}
* [" a "," b "] ==> {a=b}
* ["a=b"] ==>{a=b}
* ["a:b"] ==>{a=b}
* ["a=b","c","d"] ==>{a=b,c=d}
* ["a","a:b"] ==>{a=a:b}
* </p>
*
* @param parameters
* @return
*/
public static Map<String, String> convertParameters(String[] parameters) {
if (ArrayUtils.isEmpty(parameters)) {
return null;
}

List<String> compatibleParameterArray = Arrays.stream(parameters)
.map(String::trim)
.reduce(new ArrayList<>(parameters.length), (list, parameter) ->
{
if (list.size() % 2 == 1) {
//value doesn't split
list.add(parameter);
return list;
}

String[] sp1 = parameter.split(":");
if (sp1.length > 0 && sp1.length % 2 == 0) {
//key split
list.addAll(Arrays.stream(sp1).map(String::trim).collect(Collectors.toList()));
return list;
}
sp1 = parameter.split("=");
if (sp1.length > 0 && sp1.length % 2 == 0) {
list.addAll(Arrays.stream(sp1).map(String::trim).collect(Collectors.toList()));
return list;
}
list.add(parameter);
return list;
}
, (a, b) -> a);

return CollectionUtils.toStringMap(compatibleParameterArray.toArray(new String[0]));
}
}
@@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring.beans.factory.annotation;

import org.apache.dubbo.config.spring.util.DubboAnnotationUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.test.annotation.DirtiesContext;

import java.util.HashMap;
import java.util.Map;

/**
* {@link DubboAnnotationUtils#convertParameters} Test
*/
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class ParameterConvertTest {

@Test
public void test() {
/**
* (array->map)
* ["a","b"] ==> {a=b}
* [" a "," b "] ==> {a=b}
* ["a=b"] ==>{a=b}
* ["a:b"] ==>{a=b}
* ["a=b","c","d"] ==>{a=b,c=d}
* ["a=b","c:d"] ==>{a=b,c=d}
* ["a","a:b"] ==>{a=a:b}
*/
Map<String, String> parametersMap = new HashMap<>();
parametersMap.put("a", "b");
Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[]{"a", "b"}));
Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[]{" a ", " b "}));
Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[]{"a=b"}));
Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[]{"a:b"}));

parametersMap.put("c", "d");
Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[]{"a=b", "c", "d"}));
Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[]{"a:b", "c=d"}));

parametersMap.clear();
parametersMap.put("a", "a:b");
Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[]{"a", "a:b"}));
}
}