Skip to content

Commit 5131b00

Browse files
committed
Entrypointのパス周りの解釈結果をEntryPointMappingとし、Entrypoint生成時に作り切る形にした。
1 parent 4f8019c commit 5131b00

3 files changed

Lines changed: 127 additions & 102 deletions

File tree

Lines changed: 14 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,10 @@
11
package org.dddjava.jig.domain.model.information.inputs;
22

33
import org.dddjava.jig.domain.model.data.packages.PackageId;
4-
import org.dddjava.jig.domain.model.data.types.JigAnnotationReference;
54
import org.dddjava.jig.domain.model.data.types.TypeId;
65
import org.dddjava.jig.domain.model.information.members.CallerMethods;
76
import org.dddjava.jig.domain.model.information.members.JigMethod;
87
import org.dddjava.jig.domain.model.information.types.JigType;
9-
import org.slf4j.Logger;
10-
import org.slf4j.LoggerFactory;
11-
12-
import java.util.Arrays;
13-
import java.util.Locale;
14-
import java.util.function.Predicate;
15-
16-
import static java.util.stream.Collectors.joining;
178

189
/**
1910
* 入力アダプタのエントリーポイント
@@ -24,7 +15,7 @@
2415
* 制限事項:RequestMappingをメタアノテーションとした独自アノテーションが付与されたメソッドは、ハンドラとして扱われません。
2516
*/
2617
public record Entrypoint(EntrypointType entrypointType, JigType jigType, JigMethod jigMethod,
27-
JigAnnotationReference httpMappingAnnotation) {
18+
EntrypointMapping entrypointMapping) {
2819

2920
public boolean anyMatch(CallerMethods callerMethods) {
3021
return callerMethods.contains(jigMethod.jigMethodId());
@@ -46,90 +37,29 @@ public PackageId packageId() {
4637
* それ以外は種別の文字列表現。
4738
*/
4839
public String pathText() {
49-
return switch (entrypointType()) {
50-
case HTTP_API -> {
51-
var httpEndpoint = HttpEntrypointPath.from(this);
52-
// これだとクラスのパスがはいってない
53-
yield "%s %s".formatted(httpEndpoint.method(), httpEndpoint.methodPath());
54-
}
55-
case QUEUE_LISTENER -> "queue: %s".formatted(MessageListener.from(this).queueName());
56-
default -> this.entrypointType().toString();
57-
};
40+
return entrypointMapping.shortPathText();
5841
}
5942

6043
public String methodLabelText() {
6144
if (entrypointType() == EntrypointType.HTTP_API) {
62-
return HttpEntrypointPath.from(this).entrypointName();
45+
return resolveEntrypointName();
6346
}
6447
return jigMethod().labelText();
6548
}
6649

6750
public String fullPathText() {
68-
return HttpEntrypointPath.from(this).pathText();
51+
return entrypointMapping.fullPathText();
6952
}
7053

71-
/**
72-
* HTTPリクエストのエンドポイント
73-
*
74-
* エントリーポイントから情報を抜き出したもの。
75-
*/
76-
private record HttpEntrypointPath(String method, String entrypointName, String classPath, String methodPath) {
77-
private static final Logger logger = LoggerFactory.getLogger(HttpEntrypointPath.class);
78-
79-
public static HttpEntrypointPath from(Entrypoint entrypoint) {
80-
var jigMethod = entrypoint.jigMethod();
81-
82-
// NOTE: valueとpathの両方が指定されている場合は起動失敗(AnnotationConfigurationException)になるので、単純に合わせる
83-
// org.springframework.core.annotation.AbstractAliasAwareAnnotationAttributeExtractor.getAttributeValue
84-
// 複数( @RequestMapping({"a", "b"}) など)への対応は、そのうち。
85-
String classPath = entrypoint.jigType()
86-
.annotationValueOf(TypeId.valueOf("org.springframework.web.bind.annotation.RequestMapping"), "value", "path")
87-
.filter(value -> !"/".equals(value)).orElse("");
88-
89-
var entrypointName = resolveEntrypointName(jigMethod);
90-
var requestMappingForMethod = entrypoint.httpMappingAnnotation();
91-
92-
if (requestMappingForMethod != null) {
93-
var methodPath = resolveMethodPath(requestMappingForMethod);
94-
var httpMethod = resolveHttpMethod(requestMappingForMethod);
95-
return new HttpEntrypointPath(httpMethod, entrypointName, classPath, methodPath);
96-
}
97-
// RequestMappingでないものをEntrypointと認識しているのはおかしい。
98-
// Entrypointの時点で解決しているはずなので、ここで分岐があるのが設計ミス。
99-
logger.warn("{} のRequestMapping系アノテーションが検出されませんでした。JIGの不具合もしくは設定ミスです。", jigMethod.simpleText());
100-
return new HttpEntrypointPath("???", entrypointName, classPath, "");
101-
}
102-
103-
private static String resolveHttpMethod(JigAnnotationReference requestMappingForMethod) {
104-
var simpleText = requestMappingForMethod.id().asSimpleText();
105-
// アノテーション名からHTTPメソッド名を解決する。
106-
// RequestMappingはmethod要素の指定次第となるが、解決するのも手間だし、RequestMappingなどよりGetMappingの使用が推奨なので扱わない。
107-
return "RequestMapping".equals(simpleText) ? "???" : simpleText.replace("Mapping", "").toUpperCase(Locale.ROOT);
108-
}
109-
110-
private static String resolveEntrypointName(JigMethod jigMethod) {
111-
return jigMethod
112-
// Swaggerのアノテーションのsummaryが記述されていればそれを採用
113-
.declarationAnnotationStream()
114-
.filter(methodAnnotation -> methodAnnotation.id().equals(TypeId.valueOf("io.swagger.v3.oas.annotations.Operation")))
115-
.flatMap(methodAnnotation -> methodAnnotation.elementTextOf("summary").stream())
116-
// アノテーションの仕様上、同じアノテーションが複数あることもあるし、要素の文字列も配列で定義可能なのでAnyで取得。実際は0..1になる。
117-
.findAny()
118-
// OpenAPIドキュメントの自動生成をしていないなど、解決できない場合は通常のメソッドラベル
119-
.orElseGet(jigMethod::labelText);
120-
}
121-
122-
private static String resolveMethodPath(JigAnnotationReference requestMappingForMethod) {
123-
return requestMappingForMethod.elementTextOf("value")
124-
.or(() -> requestMappingForMethod.elementTextOf("path"))
125-
.filter(Predicate.not(String::isEmpty))
126-
.orElse("/");
127-
}
128-
129-
public String pathText() {
130-
return Arrays.stream((classPath + '/' + methodPath).split("/", -1))
131-
.filter(string -> !string.isEmpty())
132-
.collect(joining("/", "/", ""));
133-
}
54+
private String resolveEntrypointName() {
55+
return jigMethod
56+
// Swaggerのアノテーションのsummaryが記述されていればそれを採用
57+
.declarationAnnotationStream()
58+
.filter(methodAnnotation -> methodAnnotation.id().equals(TypeId.valueOf("io.swagger.v3.oas.annotations.Operation")))
59+
.flatMap(methodAnnotation -> methodAnnotation.elementTextOf("summary").stream())
60+
// アノテーションの仕様上、同じアノテーションが複数あることもあるし、要素の文字列も配列で定義可能なのでAnyで取得。実際は0..1になる。
61+
.findAny()
62+
// OpenAPIドキュメントの自動生成をしていないなど、解決できない場合は通常のメソッドラベル
63+
.orElseGet(jigMethod::labelText);
13464
}
13565
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package org.dddjava.jig.domain.model.information.inputs;
2+
3+
import org.dddjava.jig.domain.model.data.types.JigAnnotationReference;
4+
import org.dddjava.jig.domain.model.data.types.TypeId;
5+
import org.dddjava.jig.domain.model.information.members.JigMethod;
6+
import org.dddjava.jig.domain.model.information.types.JigType;
7+
8+
import java.util.Arrays;
9+
import java.util.Locale;
10+
import java.util.function.Predicate;
11+
12+
import static java.util.stream.Collectors.joining;
13+
14+
public interface EntrypointMapping {
15+
default String shortPathText() {
16+
return fullPathText();
17+
}
18+
19+
default String fullPathText() {
20+
// パスを実装していないEntrypointで呼び出されるパターン
21+
return "???";
22+
}
23+
}
24+
25+
record HttpEntrypointMapping(String httpMethod, String classPath, String methodPath) implements EntrypointMapping {
26+
27+
public static HttpEntrypointMapping from(JigType jigType, JigAnnotationReference methodMappingAnnotation) {
28+
29+
// NOTE: valueとpathの両方が指定されている場合は起動失敗(AnnotationConfigurationException)になるので、単純に合わせる
30+
// org.springframework.core.annotation.AbstractAliasAwareAnnotationAttributeExtractor.getAttributeValue
31+
// 複数( @RequestMapping({"a", "b"}) など)への対応は、そのうち。
32+
String classPath = jigType
33+
.annotationValueOf(TypeId.valueOf("org.springframework.web.bind.annotation.RequestMapping"), "value", "path")
34+
.filter(value -> !"/".equals(value)).orElse("");
35+
36+
var methodPath = resolveMethodPath(methodMappingAnnotation);
37+
var httpMethod = resolveHttpMethod(methodMappingAnnotation);
38+
return new HttpEntrypointMapping(httpMethod, classPath, methodPath);
39+
}
40+
41+
@Override
42+
public String shortPathText() {
43+
// クラスのパスが入らないパターン
44+
return "%s %s".formatted(httpMethod, methodPath);
45+
}
46+
47+
@Override
48+
public String fullPathText() {
49+
// HTTPメソッドが入らないパターン
50+
return Arrays.stream((classPath + '/' + methodPath).split("/", -1))
51+
.filter(string -> !string.isEmpty())
52+
.collect(joining("/", "/", ""));
53+
}
54+
55+
private static String resolveHttpMethod(JigAnnotationReference requestMappingForMethod) {
56+
var simpleText = requestMappingForMethod.id().asSimpleText();
57+
// アノテーション名からHTTPメソッド名を解決する。
58+
// RequestMappingはmethod要素の指定次第となるが、解決するのも手間だし、RequestMappingなどよりGetMappingの使用が推奨なので扱わない。
59+
return "RequestMapping".equals(simpleText) ? "???" : simpleText.replace("Mapping", "").toUpperCase(Locale.ROOT);
60+
}
61+
62+
private static String resolveMethodPath(JigAnnotationReference requestMappingForMethod) {
63+
return requestMappingForMethod.elementTextOf("value")
64+
.or(() -> requestMappingForMethod.elementTextOf("path"))
65+
.filter(Predicate.not(String::isEmpty))
66+
.orElse("/");
67+
}
68+
}
69+
70+
record QueueListenerEntrypointMapping(JigMethod jigMethod) implements EntrypointMapping {
71+
72+
@Override
73+
public String fullPathText() {
74+
return jigMethod.declarationAnnotationStream()
75+
.filter(jigAnnotationReference -> jigAnnotationReference.id().equals(TypeId.valueOf("org.springframework.amqp.rabbit.annotation.RabbitListener")))
76+
.map(jigAnnotationReference -> {
77+
// queueは複数記述できるが、たぶんしないので一件目をとってくる
78+
return jigAnnotationReference.elementTextOf("queues").orElse("???");
79+
})
80+
// RabbitListenerアノテーションは複数取れないはずなのでAnyでOK。
81+
.findAny()
82+
.orElse("???");
83+
}
84+
}

jig-core/src/main/java/org/dddjava/jig/domain/model/information/inputs/EntrypointMethodDetector.java

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.dddjava.jig.domain.model.data.types.JigAnnotationReference;
44
import org.dddjava.jig.domain.model.data.types.TypeId;
5+
import org.dddjava.jig.domain.model.information.members.JigMethod;
56
import org.dddjava.jig.domain.model.information.types.JigType;
67
import org.slf4j.Logger;
78
import org.slf4j.LoggerFactory;
@@ -54,28 +55,38 @@ Collection<Entrypoint> collectMethod(JigType jigType) {
5455
.filter(jigMethod -> entrypointAnnotation.methodAnnotations().stream().map(TypeId::valueOf)
5556
.anyMatch(jigMethod::hasAnnotation))
5657
.map(jigMethod -> {
57-
JigAnnotationReference httpMapping = null;
58-
if (entrypointAnnotation.entrypointType() == EntrypointType.HTTP_API) {
59-
var methodAnnotations = jigMethod.declarationAnnotationStream()
60-
.filter(jigAnnotationReference -> {
61-
var typeId = jigAnnotationReference.id();
62-
return entrypointAnnotation.methodAnnotations().stream()
63-
.map(TypeId::valueOf)
64-
.anyMatch(typeId::equals);
65-
})
66-
.toList();
67-
if (!methodAnnotations.isEmpty()) {
68-
httpMapping = methodAnnotations.get(0);
69-
if (methodAnnotations.size() > 1) {
70-
logger.warn("{} にマッピングアノテーションが複数記述されているため、正しい検出が行えません。出力には1件目を採用します。", jigMethod.simpleText());
71-
}
72-
}
73-
}
74-
return new Entrypoint(entrypointAnnotation.entrypointType(), jigType, jigMethod, httpMapping);
58+
var entrypointMapping = getEntrypointMapping(jigType, entrypointAnnotation, jigMethod);
59+
return new Entrypoint(entrypointAnnotation.entrypointType(), jigType, jigMethod, entrypointMapping);
7560
});
7661
}
7762
return Stream.empty();
7863
})
7964
.toList();
8065
}
66+
67+
private EntrypointMapping getEntrypointMapping(JigType jigType, EntrypointAnnotation entrypointAnnotation, JigMethod jigMethod) {
68+
if (entrypointAnnotation.entrypointType() == EntrypointType.HTTP_API) {
69+
var methodAnnotations = jigMethod.declarationAnnotationStream()
70+
.filter(jigAnnotationReference -> {
71+
var typeId = jigAnnotationReference.id();
72+
return entrypointAnnotation.methodAnnotations().stream()
73+
.map(TypeId::valueOf)
74+
.anyMatch(typeId::equals);
75+
})
76+
.toList();
77+
if (!methodAnnotations.isEmpty()) {
78+
JigAnnotationReference httpMapping = methodAnnotations.get(0);
79+
if (methodAnnotations.size() > 1) {
80+
logger.warn("{} にマッピングアノテーションが複数記述されているため、正しい検出が行えません。出力には1件目を採用します。", jigMethod.simpleText());
81+
}
82+
// HTTPハンドラメソッド
83+
return HttpEntrypointMapping.from(jigType, httpMapping);
84+
}
85+
} else if (entrypointAnnotation.entrypointType() == EntrypointType.QUEUE_LISTENER) {
86+
return new QueueListenerEntrypointMapping(jigMethod);
87+
}
88+
// デフォルト
89+
return new EntrypointMapping() {
90+
};
91+
}
8192
}

0 commit comments

Comments
 (0)