Skip to content

Commit da9b38f

Browse files
fix(MethodContainer): the data source container based on single parameter method cannot correctly handle the set of input key values (Gitee #I9C5GA)
1 parent e841c22 commit da9b38f

File tree

6 files changed

+95
-73
lines changed

6 files changed

+95
-73
lines changed

crane4j-core/src/main/java/cn/crane4j/core/container/MethodInvokerContainer.java

Lines changed: 64 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
* @see MappingType
3737
*/
3838
@RequiredArgsConstructor
39-
public class MethodInvokerContainer implements Container<Object> {
39+
public abstract class MethodInvokerContainer implements Container<Object> {
4040

4141
/**
4242
* Namespace of method.
@@ -54,7 +54,7 @@ public class MethodInvokerContainer implements Container<Object> {
5454
* if method is static, this field can be null.
5555
*/
5656
@Nullable
57-
private final Object target;
57+
protected final Object target;
5858

5959
/**
6060
* Create a standard method data source container.
@@ -69,7 +69,7 @@ public class MethodInvokerContainer implements Container<Object> {
6969
public static MethodInvokerContainer create(
7070
String namespace, MethodInvoker methodInvoker, @Nullable Object target, boolean isMapped) {
7171
return isMapped ? new NoMapping(namespace, methodInvoker, target)
72-
: new MethodInvokerContainer(namespace, methodInvoker, target);
72+
: new StandardMethodInvokerContainer(namespace, methodInvoker, target);
7373
}
7474

7575
/**
@@ -120,53 +120,68 @@ public static MethodInvokerContainer oneToMany(
120120
}
121121

122122
/**
123-
* Enter a batch of key values to return data source objects grouped by key values.
123+
* The container for method with single parameter.
124124
*
125-
* @param keys keys
126-
* @return data source objects grouped by key value
125+
* @author huangchengxing
127126
*/
128-
@Override
129-
public Map<Object, ?> get(Collection<Object> keys) {
130-
Object[] arguments = resolveArguments(keys);
131-
Object result = methodInvoker.invoke(target, arguments);
132-
if (Objects.isNull(result)) {
133-
return Collections.emptyMap();
127+
protected static class SingleKey extends MethodInvokerContainer {
128+
129+
public SingleKey(String namespace, MethodInvoker methodInvoker, @Nullable Object target) {
130+
super(namespace, methodInvoker, target);
134131
}
135-
return resolveResult(keys, result);
136-
}
137132

138-
/**
139-
* Resolve arguments.
140-
*
141-
* @param keys keys
142-
* @return arguments
143-
*/
144-
protected Object[] resolveArguments(Collection<Object> keys) {
145-
return new Object[] {keys};
133+
/**
134+
* Enter a batch of key values to return data source objects grouped by key values.
135+
*
136+
* @param keys keys
137+
* @return data source objects grouped by key value
138+
*/
139+
@Override
140+
public Map<Object, ?> get(Collection<Object> keys) {
141+
Map<Object, Object> results = new HashMap<>(keys.size());
142+
keys.forEach(key -> {
143+
Object result = methodInvoker.invoke(target, key);
144+
results.put(key, result);
145+
});
146+
return results;
147+
}
146148
}
147149

148150
/**
149-
* Resolve result to map.
151+
* Standard method data source container.
150152
*
151-
* @param keys keys
152-
* @param result result
153-
* @return map
153+
* @author huangchengxing
154154
*/
155-
protected Map<Object, ?> resolveResult(Collection<Object> keys, Object result) {
156-
Collection<?> results = CollectionUtils.adaptObjectToCollection(result);
157-
Map<Object, Object> resultMap = new HashMap<>(keys.size());
158-
Iterator<?> valueIterator = results.iterator();
159-
for (Object key : keys) {
160-
Object value = valueIterator.hasNext() ? valueIterator.next() : null;
161-
resultMap.put(key, value);
155+
protected static class StandardMethodInvokerContainer extends MethodInvokerContainer {
156+
157+
public StandardMethodInvokerContainer(String namespace, MethodInvoker methodInvoker, @Nullable Object target) {
158+
super(namespace, methodInvoker, target);
162159
}
163-
return resultMap;
164-
}
165160

166-
protected static class SingleKey extends MethodInvokerContainer {
161+
/**
162+
* Enter a batch of key values to return data source objects grouped by key values.
163+
*
164+
* @param keys keys
165+
* @return data source objects grouped by key value
166+
*/
167+
@Override
168+
public Map<Object, ?> get(Collection<Object> keys) {
169+
Object[] arguments = resolveArguments(keys);
170+
Object result = methodInvoker.invoke(target, arguments);
171+
if (Objects.isNull(result)) {
172+
return Collections.emptyMap();
173+
}
174+
return resolveResult(keys, result);
175+
}
167176

168-
public SingleKey(String namespace, MethodInvoker methodInvoker, @Nullable Object target) {
169-
super(namespace, methodInvoker, target);
177+
/**
178+
* Resolve arguments.
179+
*
180+
* @param keys keys
181+
* @return arguments
182+
*/
183+
protected Object[] resolveArguments(Collection<Object> keys) {
184+
return new Object[] {keys};
170185
}
171186

172187
/**
@@ -176,9 +191,15 @@ public SingleKey(String namespace, MethodInvoker methodInvoker, @Nullable Object
176191
* @param result result
177192
* @return map
178193
*/
179-
@Override
180194
protected Map<Object, ?> resolveResult(Collection<Object> keys, Object result) {
181-
return Collections.singletonMap(CollectionUtils.getFirstNotNull(keys), result);
195+
Collection<?> results = CollectionUtils.adaptObjectToCollection(result);
196+
Map<Object, Object> resultMap = new HashMap<>(keys.size());
197+
Iterator<?> valueIterator = results.iterator();
198+
for (Object key : keys) {
199+
Object value = valueIterator.hasNext() ? valueIterator.next() : null;
200+
resultMap.put(key, value);
201+
}
202+
return resultMap;
182203
}
183204
}
184205

@@ -187,7 +208,7 @@ public SingleKey(String namespace, MethodInvoker methodInvoker, @Nullable Object
187208
*
188209
* @since 2.4.0
189210
*/
190-
protected static class NoMapping extends MethodInvokerContainer {
211+
protected static class NoMapping extends StandardMethodInvokerContainer {
191212

192213
public NoMapping(String namespace, MethodInvoker methodInvoker, @Nullable Object target) {
193214
super(namespace, methodInvoker, target);
@@ -212,7 +233,7 @@ public NoMapping(String namespace, MethodInvoker methodInvoker, @Nullable Object
212233
*
213234
* @since 2.4.0
214235
*/
215-
protected static class OneToOne extends MethodInvokerContainer {
236+
protected static class OneToOne extends StandardMethodInvokerContainer {
216237

217238
protected final KeyExtractor keyExtractor;
218239
private final DuplicateStrategy duplicateStrategy;
@@ -249,7 +270,7 @@ public OneToOne(
249270
*
250271
* @since 2.4.0
251272
*/
252-
protected static class OneToMany extends MethodInvokerContainer {
273+
protected static class OneToMany extends StandardMethodInvokerContainer {
253274

254275
private final KeyExtractor keyExtractor;
255276

crane4j-core/src/main/java/cn/crane4j/core/support/container/MethodInvokerContainerCreator.java

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@
99
import cn.crane4j.core.support.converter.ParameterConvertibleMethodInvoker;
1010
import cn.crane4j.core.support.reflect.PropertyOperator;
1111
import cn.crane4j.core.support.reflect.ReflectiveMethodInvoker;
12-
import cn.crane4j.core.util.ArrayUtils;
1312
import cn.crane4j.core.util.Asserts;
1413
import cn.crane4j.core.util.ClassUtils;
15-
import cn.crane4j.core.util.CollectionUtils;
1614
import cn.crane4j.core.util.StringUtils;
1715
import lombok.RequiredArgsConstructor;
1816
import lombok.extern.slf4j.Slf4j;
@@ -86,7 +84,6 @@ private MethodInvokerContainer doCreateContainer(
8684
@Nullable Object target, MethodInvoker methodInvoker, @Nullable Method method, MappingType mappingType,
8785
@Nullable String namespace, Class<?> resultType, String resultKey, DuplicateStrategy duplicateStrategy) {
8886

89-
methodInvoker = wrapInvokerIfNecessary(methodInvoker, method);
9087
namespace = getNamespace(method, namespace);
9188
MethodInvokerContainer container;
9289
if (mappingType == MappingType.NO_MAPPING || mappingType == MappingType.MAPPED) {
@@ -115,19 +112,6 @@ private MethodInvokerContainer doCreateContainer(
115112
return container;
116113
}
117114

118-
protected MethodInvoker wrapInvokerIfNecessary(
119-
MethodInvoker methodInvoker, @Nullable Method method) {
120-
if (Objects.nonNull(method)) {
121-
// if the method has only one parameter and the parameter is not a collection,
122-
// we will take the first element of the collection as the parameter to call the method
123-
boolean isSingleParameterMethod = isSingleParameterMethod(method);
124-
if (isSingleParameterMethod) {
125-
methodInvoker = new SingleParameterMethodInvoker(methodInvoker);
126-
}
127-
}
128-
return methodInvoker;
129-
}
130-
131115
private static boolean isSingleParameterMethod(@NonNull Method method) {
132116
return method.getParameterCount() == 1
133117
&& !Collection.class.isAssignableFrom(method.getParameterTypes()[0]);
@@ -245,14 +229,4 @@ protected MethodInvoker findKeyGetter(Class<?> resultType, String resultKey) {
245229
Asserts.isNotNull(keyGetter, "cannot find getter method [{}] on [{}]", resultKey, resultType);
246230
return keyGetter;
247231
}
248-
249-
@RequiredArgsConstructor
250-
protected static class SingleParameterMethodInvoker implements MethodInvoker {
251-
private final MethodInvoker delegate;
252-
@Override
253-
public Object invoke(Object target, Object... args) {
254-
Collection<?> firstArg = CollectionUtils.adaptObjectToCollection(ArrayUtils.get(args, 0));
255-
return delegate.invoke(target, CollectionUtils.getFirstNotNull(firstArg));
256-
}
257-
}
258232
}

crane4j-core/src/test/java/cn/crane4j/core/container/MethodInvokerContainerTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,22 @@ public void getWhenOneToMany() {
7979
Assert.assertTrue(data.isEmpty());
8080
}
8181

82+
@Test
83+
public void getWhenSingle() {
84+
MethodInvokerContainer container = MethodInvokerContainer.singleKey(
85+
MethodInvokerContainer.class.getSimpleName(),
86+
(t, arg) -> service.singleMethod((String) arg[0]),
87+
service
88+
);
89+
Assert.assertEquals(MethodInvokerContainer.class.getSimpleName(), container.getNamespace());
90+
91+
Map<Object, Foo> data = (Map<Object, Foo>) container.get(Arrays.asList("1", "2", "3", "4"));
92+
Assert.assertEquals("1", data.get("1").getKey());
93+
Assert.assertEquals("2", data.get("2").getKey());
94+
Assert.assertEquals("3", data.get("3").getKey());
95+
Assert.assertEquals("4", data.get("4").getKey());
96+
}
97+
8298
@Test
8399
@SuppressWarnings("unchecked")
84100
public void getWhenNotKeyExtractor() {
@@ -102,6 +118,9 @@ private static class Foo {
102118
}
103119

104120
private static class Service {
121+
public Foo singleMethod(String key) {
122+
return new Foo(key, key);
123+
}
105124
public Map<String, Foo> mappedMethod(Collection<String> key) {
106125
return Objects.isNull(key) ? null : Stream.of(foo1, foo2).collect(Collectors.toMap(Foo::getKey, Function.identity()));
107126
}

crane4j-core/src/test/java/cn/crane4j/core/support/container/DefaultMethodContainerFactoryTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ public void getWhenNoneMappedMethod() {
110110
Assert.assertEquals("noneMappedMethod", container.getNamespace());
111111

112112
Map<Object, ?> values = container.get(Arrays.asList("1", "2"));
113-
Assert.assertEquals(1, values.size());
113+
Assert.assertEquals(2, values.size());
114114
Assert.assertEquals("1", values.get("1"));
115-
Assert.assertNull(values.get("2"));
115+
Assert.assertEquals("2", values.get("2"));
116116
}
117117

118118
@Test

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545
<properties>
4646
<!--revision-->
47-
<revision>2.6.1</revision>
47+
<revision>2.6.2</revision>
4848
<!--build-->
4949
<java.version>1.8</java.version>
5050
<server.id>maven-central</server.id>

website/docs/other/changelog.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,4 +360,12 @@
360360

361361
**Fix**
362362

363-
- [当作为数据源容器的方法接受单个参数并返回集合类型结果时,只会填充集合中的首个元素](https://gitee.com/opengoofy/crane4j/issues/I97R7E)
363+
- [当作为数据源容器的方法接受单个参数并返回集合类型结果时,只会填充集合中的首个元素](https://gitee.com/opengoofy/crane4j/issues/I97R7E)
364+
365+
## 2.6.2 (2024-03-27)
366+
367+
这是一个 Bug 修复版本,请尽快升级。
368+
369+
**Fix**
370+
371+
- [将接受单个参数并返回单个对象的方法作为数据源容器时,填充出现问题](https://gitee.com/opengoofy/crane4j/issues/I9C5GA)

0 commit comments

Comments
 (0)