Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
950bba9
feat(client):add many path register for spring mvc client.
wy471x May 22, 2026
6d95947
feat(client):improve code coverage for SpringMvcClientEventListener.
wy471x May 22, 2026
ebf2470
Merge branch 'master' into feat_addMultiPathController#6327
wy471x May 22, 2026
bda0005
feat(client):add many path register for spring mvc client.
wy471x May 23, 2026
42eee2b
feat(client):add integrated test cases for SpringMvcClientEventListener.
wy471x May 23, 2026
eb5655c
feat(client):add integrated test cases for SpringMvcClientEventListener.
wy471x May 23, 2026
1fd46e7
feat(client):add multipath register test controller.
wy471x May 25, 2026
36a604a
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 4, 2026
e420695
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 8, 2026
1832784
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 8, 2026
dcec735
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 9, 2026
55a5723
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 9, 2026
fa98b45
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 11, 2026
0279a79
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 11, 2026
90f4b04
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 11, 2026
eba9c9d
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 12, 2026
935ba67
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 12, 2026
4f04947
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 14, 2026
9b27f7f
Merge branch 'master' into feat_addMultiPathController#6327
Aias00 Jun 16, 2026
588d368
Merge branch 'master' into feat_addMultiPathController#6327
wy471x Jul 14, 2026
63adcae
fix: generate API docs for all super-paths on multi-path controllers
wy471x Jul 14, 2026
765056c
fix: remove fragile endsWith heuristic from buildApiPath
wy471x Jul 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,7 @@ private List<ApiDocRegisterDTO> buildApiDocDTO(final Object bean, final Method m
return Collections.emptyList();
}
Class<?> clazz = AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) : bean.getClass();
String superPath = buildApiSuperPath(clazz, AnnotatedElementUtils.findMergedAnnotation(clazz, getAnnotationType()));
if (superPath.contains("*")) {
superPath = superPath.substring(0, superPath.lastIndexOf("/"));
}
List<String> superPaths = buildApiSuperPaths(clazz, AnnotatedElementUtils.findMergedAnnotation(clazz, getAnnotationType()));
Annotation annotation = AnnotatedElementUtils.findMergedAnnotation(clazz, getAnnotationType());
if (Objects.isNull(annotation)) {
return Lists.newArrayList();
Expand All @@ -208,30 +205,33 @@ private List<ApiDocRegisterDTO> buildApiDocDTO(final Object bean, final Method m
String contextPath = getContextPath();
String[] value0 = sextet.getValue0();
List<ApiDocRegisterDTO> list = Lists.newArrayList();
for (String value : value0) {
String apiPath = pathJoin(contextPath, superPath, value);
ApiHttpMethodEnum[] value3 = sextet.getValue3();
for (ApiHttpMethodEnum apiHttpMethodEnum : value3) {
String documentJson = buildDocumentJson(pairs.getRight(), apiPath, method, sextet.getValue4());
String extJson = buildExtJson(method);
ApiDocRegisterDTO build = ApiDocRegisterDTO.builder()
.consume(sextet.getValue1())
.produce(sextet.getValue2())
.httpMethod(apiHttpMethodEnum.getValue())
.contextPath(contextPath)
.ext(extJson)
.document(documentJson)
.rpcType(sextet.getValue4().getName())
.version(sextet.getValue5())
.apiDesc(pairs.getLeft())
.tags(pairs.getRight())
.apiPath(apiPath)
.apiSource(ApiSourceEnum.ANNOTATION_GENERATION.getValue())
.state(ApiStateEnum.UNPUBLISHED.getState())
.apiOwner("admin")
.eventType(EventType.REGISTER)
.build();
list.add(build);
for (String rawPath : superPaths) {
String superPath = rawPath.contains("*") ? rawPath.substring(0, rawPath.lastIndexOf("/")) : rawPath;
for (String value : value0) {
String apiPath = pathJoin(contextPath, superPath, value);
ApiHttpMethodEnum[] value3 = sextet.getValue3();
for (ApiHttpMethodEnum apiHttpMethodEnum : value3) {
String documentJson = buildDocumentJson(pairs.getRight(), apiPath, method, sextet.getValue4());
String extJson = buildExtJson(method);
ApiDocRegisterDTO build = ApiDocRegisterDTO.builder()
.consume(sextet.getValue1())
.produce(sextet.getValue2())
.httpMethod(apiHttpMethodEnum.getValue())
.contextPath(contextPath)
.ext(extJson)
.document(documentJson)
.rpcType(sextet.getValue4().getName())
.version(sextet.getValue5())
.apiDesc(pairs.getLeft())
.tags(pairs.getRight())
.apiPath(apiPath)
.apiSource(ApiSourceEnum.ANNOTATION_GENERATION.getValue())
.state(ApiStateEnum.UNPUBLISHED.getState())
.apiOwner("admin")
.eventType(EventType.REGISTER)
.build();
list.add(build);
}
}
}
return list;
Expand Down Expand Up @@ -298,6 +298,11 @@ protected Class<?> getCorrectedClass(final T bean) {
protected abstract String buildApiSuperPath(Class<?> clazz,
@Nullable A beanShenyuClient);

protected List<String> buildApiSuperPaths(final Class<?> clazz,
@Nullable final A beanShenyuClient) {
return Collections.singletonList(buildApiSuperPath(clazz, beanShenyuClient));
}

protected void handleClass(final Class<?> clazz,
final T bean,
@NonNull final A beanShenyuClient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Controller;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.util.UriComponentsBuilder;
Expand Down Expand Up @@ -167,20 +168,58 @@ protected String getClientName() {
return RpcTypeEnum.HTTP.getName();
}

@Override
protected void handle(final String beanName, final Object bean) {
Class<?> clazz = getCorrectedClass(bean);
final ShenyuSpringMvcClient beanShenyuClient = AnnotatedElementUtils.findMergedAnnotation(clazz, getAnnotationType());
final List<String> superPaths = buildApiSuperPaths(clazz, beanShenyuClient);
final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(clazz);
for (String superPath : superPaths) {
if (Objects.nonNull(beanShenyuClient) && superPath.contains("*")) {
handleClass(clazz, bean, beanShenyuClient, superPath);
continue;
}
for (Method method : methods) {
handleMethod(bean, clazz, beanShenyuClient, method, superPath);
}
}
}

@Override
protected String buildApiSuperPath(final Class<?> clazz, @Nullable final ShenyuSpringMvcClient beanShenyuClient) {
final String servletPath = StringUtils.defaultString(this.env.getProperty("spring.mvc.servlet.path"), "");
final String servletContextPath = StringUtils.defaultString(this.env.getProperty("server.servlet.context-path"), "");
final String rootPath = String.format("/%s/%s/", servletContextPath, servletPath);
if (Objects.nonNull(beanShenyuClient) && StringUtils.isNotBlank(beanShenyuClient.path()[0])) {
return formatPath(String.format("%s/%s", rootPath, beanShenyuClient.path()[0]));
List<String> paths = buildApiSuperPaths(clazz, beanShenyuClient);
return paths.isEmpty() ? formatPath(buildRootPath()) : paths.get(0);
}
Comment thread
wy471x marked this conversation as resolved.

@Override
protected List<String> buildApiSuperPaths(final Class<?> clazz, @Nullable final ShenyuSpringMvcClient beanShenyuClient) {
final String rootPath = buildRootPath();
if (Objects.nonNull(beanShenyuClient) && ArrayUtils.isNotEmpty(beanShenyuClient.path())) {
List<String> paths = Arrays.stream(beanShenyuClient.path())
.filter(StringUtils::isNotBlank)
.map(p -> formatPath(String.format("%s/%s", rootPath, p)))
.collect(Collectors.toList());
if (!paths.isEmpty()) {
return paths;
}
}
RequestMapping requestMapping = AnnotationUtils.findAnnotation(clazz, RequestMapping.class);
// Only the first path is supported temporarily
if (Objects.nonNull(requestMapping) && ArrayUtils.isNotEmpty(requestMapping.path()) && StringUtils.isNotBlank(requestMapping.path()[0])) {
return formatPath(String.format("%s/%s", rootPath, requestMapping.path()[0]));
if (Objects.nonNull(requestMapping) && ArrayUtils.isNotEmpty(requestMapping.path())) {
List<String> paths = Arrays.stream(requestMapping.path())
.filter(StringUtils::isNotBlank)
.map(p -> formatPath(String.format("%s/%s", rootPath, p)))
.collect(Collectors.toList());
if (!paths.isEmpty()) {
return paths;
}
}
return formatPath(rootPath);
return Collections.singletonList(formatPath(rootPath));
}

private String buildRootPath() {
final String servletPath = Optional.ofNullable(this.env.getProperty("spring.mvc.servlet.path")).orElse("");
final String servletContextPath = Optional.ofNullable(this.env.getProperty("server.servlet.context-path")).orElse("");
return String.format("/%s/%s/", servletContextPath, servletPath);
}

@Override
Expand All @@ -194,14 +233,18 @@ protected void handleMethod(final Object bean, final Class<?> clazz,
final Method method, final String superPath) {
final RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
ShenyuSpringMvcClient methodShenyuClient = AnnotatedElementUtils.findMergedAnnotation(method, ShenyuSpringMvcClient.class);
methodShenyuClient = Objects.isNull(methodShenyuClient) ? beanShenyuClient : methodShenyuClient;
final boolean hasMethodAnnotation = Objects.nonNull(methodShenyuClient);
methodShenyuClient = hasMethodAnnotation ? methodShenyuClient : beanShenyuClient;
// the result of ReflectionUtils#getUniqueDeclaredMethods contains method such as hashCode, wait, toSting
// add Objects.nonNull(requestMapping) to make sure not register wrong method
if (Objects.nonNull(methodShenyuClient) && Objects.nonNull(requestMapping)) {
List<String> namespaceIds = super.getNamespace();
for (String namespaceId : namespaceIds) {
final String apiPath = hasMethodAnnotation
? buildApiPath(method, superPath, methodShenyuClient)
: buildApiPathFromRequestMapping(method, superPath);
final MetaDataRegisterDTO metaData = buildMetaDataDTO(bean, methodShenyuClient,
buildApiPath(method, superPath, methodShenyuClient), clazz, method, namespaceId);
apiPath, clazz, method, namespaceId);
getPublisher().publishEvent(metaData);
getMetaDataMap().put(method, metaData);
}
Expand All @@ -212,8 +255,10 @@ protected void handleMethod(final Object bean, final Class<?> clazz,
protected String buildApiPath(final Method method, final String superPath,
@NonNull final ShenyuSpringMvcClient methodShenyuClient) {
String contextPath = getContextPath();
if (StringUtils.isNotBlank(methodShenyuClient.path()[0])) {
return pathJoin(contextPath, superPath, methodShenyuClient.path()[0]);
final String[] annotationPaths = methodShenyuClient.path();
final String annotationPath = ArrayUtils.isNotEmpty(annotationPaths) ? annotationPaths[0] : "";
if (StringUtils.isNotBlank(annotationPath)) {
return pathJoin(contextPath, superPath, annotationPath);
}
final String path = getPathByMethod(method);
if (StringUtils.isNotBlank(path)) {
Expand All @@ -222,6 +267,15 @@ protected String buildApiPath(final Method method, final String superPath,
return pathJoin(contextPath, superPath);
}

String buildApiPathFromRequestMapping(final Method method, final String superPath) {
String contextPath = getContextPath();
final String path = getPathByMethod(method);
if (StringUtils.isNotBlank(path)) {
return pathJoin(contextPath, superPath, path);
}
return pathJoin(contextPath, superPath);
}

private String formatPath(final String path) {
return path.replaceAll("/+", "/").replaceFirst("/$", "");
}
Expand Down
Loading
Loading