Skip to content

Commit

Permalink
feat(AutoOperate): support obtaining operation configurations from an…
Browse files Browse the repository at this point in the history
…notated method or parameter (GitHub #223)
  • Loading branch information
Createsequence committed Feb 28, 2024
1 parent ec1c2f6 commit 119dbff
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@
*/
Class<?> type() default Object.class;

/**
* <p>Whether to resolve the operations from the current element
* when annotated on method.<br/>
* When this option is true, {@link #type()} will be ignored.
*
* @return true if resolve from current element, otherwise false
* @since 2.7.0
*/
boolean resolveOperationsFromCurrentElement() default false;

/**
* <p>When the return value is a wrapper class,
* we can specify to obtain the data set to be processed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ protected AutoOperateAnnotatedElement createAutoOperateAnnotatedElement(
return null;
}

// resolve type for the element
if (annotation.resolveOperationsFromCurrentElement()) {
BeanOperations beanOperations = parser.parse(element);
return beanOperations.isEmpty() ?
null : DefaultAutoOperateAnnotatedElement.forStaticTypeOperation(
annotation, element, extractor, filter, beanOperations, executor
);
}

// type is specified in annotation
Class<?> annotationSpecifiedType = annotation.type();
if (!ClassUtils.isObjectOrVoid(annotationSpecifiedType)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,45 @@ public void beforeMethodInvoke() {
support.afterMethodInvoke(null, method, foo, new Object[]{ Arrays.asList(1, 2) });
}

@Test
public void beforeMethodInvokeWhenResolveOperationsFromCurrentElement() {
Method method = ReflectUtils.getMethod(this.getClass(), "methodWhenResolveOperationsFromCurrentElement", Collection.class);
Assert.assertNotNull(method);
AutoOperate annotation = method.getAnnotation(AutoOperate.class);
Assert.assertNotNull(annotation);
Result<Foo2> foo = new Result<>(new Foo2(1));
support.afterMethodInvoke(annotation, method, foo, new Object[]{ Arrays.asList(1, 2) });
Assert.assertEquals("name1", foo.getData().getName());
support.afterMethodInvoke(null, method, foo, new Object[]{ Arrays.asList(1, 2) });
}

@Test
public void beforeMethodInvokeWhenCannotResolveOperationsFromCurrentElement() {
Method method = ReflectUtils.getMethod(this.getClass(), "methodWhenCannotResolveOperationsFromCurrentElement", Collection.class);
Assert.assertNotNull(method);
AutoOperate annotation = method.getAnnotation(AutoOperate.class);
Assert.assertNotNull(annotation);
Result<Foo2> foo = new Result<>(new Foo2(1));
support.afterMethodInvoke(annotation, method, foo, new Object[]{ Arrays.asList(1, 2) });
Assert.assertNull(foo.getData().getName());
}

@AutoOperate(on = "data", condition = "true")
private Result<Collection<Foo>> method(Collection<Integer> ids) {
return new Result<>(ids.stream().map(Foo::new).collect(Collectors.toList()));
}

@Assemble(key = "id", container = "test", props = @Mapping("name"))
@AutoOperate(on = "data", condition = "true", resolveOperationsFromCurrentElement = true)
private Result<Collection<Foo2>> methodWhenResolveOperationsFromCurrentElement(Collection<Integer> ids) {
return new Result<>(ids.stream().map(Foo2::new).collect(Collectors.toList()));
}

@AutoOperate(on = "data", condition = "true", resolveOperationsFromCurrentElement = true)
private Result<Collection<Foo2>> methodWhenCannotResolveOperationsFromCurrentElement(Collection<Integer> ids) {
return new Result<>(ids.stream().map(Foo2::new).collect(Collectors.toList()));
}

@Getter
@RequiredArgsConstructor
private static class Result<T> {
Expand All @@ -85,4 +119,12 @@ private static class Foo {
private final Integer id;
private String name;
}

@AllArgsConstructor
@RequiredArgsConstructor
@Data
private static class Foo2 {
private final Integer id;
private String name;
}
}
25 changes: 25 additions & 0 deletions website/docs/basic/trigger_operation.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,28 @@ public List<Foo> getFoo(Integer type) {

:::

### 2.7.从注解元素获取配置

在 2.7.0 及以上版本,你可以不配置 `type` 或通过动态解析返回值类型来获取操作配置,而是直接从被 `@AutoOperate` 注解的方法或者参数上获取操作配置。

比如:

~~~java
@Assemble(key = "id", container = "foo")
@AutoOperate(resolveOperationsFromCurrentElement = true) // 从 listByIds 方法上解析操作配置
public List<Foo> listByIds(Collection<Integer> ids);

public void preocessFoo(
@Assemble(key = "id", container = "foo")
@AutoOperate(resolveOperationsFromCurrentElement = true) // 从 targets 方法参数上解析操作配置
Collection<Foo> targets
);
~~~

在上面这个写法中,你可以不必在 `Foo` 类中配置任何注解,当执行时,crane4j 将根据你在方法上的操作配置对返回值进行填充,或根据你在参数上的操作配置对入参进行填充。

:::tip

如果你希望基于一个独立的方法进行填充,那么可以参考 [基于方法填充](./../advanced/operator_interface.md) 一节,它同样也可做到类似的效果,并且更加灵活。

:::
2 changes: 1 addition & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "svuepress dev docs",
"dev": "vuepress dev docs",
"build": "vuepress build docs",
"postinstall": "patch-package"
},
Expand Down

0 comments on commit 119dbff

Please sign in to comment.