やりたいこと
APIの本数が増えてきたので、実装済みのAPIのURIの一覧を出力したい
→Spring bootのControllerクラスで定義したパスを一覧として取得するの内容の踏襲でほぼいけたのですが、PJの実装ルール的に少し考慮が必要な部分があったので、その部分を書き記しておきます
アレンジした部分
クラスに@RequestMappingを付与して基幹部分のパスを、メソッドにリクエストメソッドに応じたアノテーションを付与して相対パスを定義するルールなので、以下2点実現できるように手を加えました。
- リクエストメソッドに応じたアノテーションからリクエストメソッドと相対パスを出力する
- クラスに定義された親パスとメソッドに定義された相対パスの関係性が分かるように出力する
// 略
for (BeanDefinition def : beanSet) {
Class<?> clazz = Class.forName(def.getBeanClassName());
RequestMapping requestMappingClazz = clazz.getAnnotation(RequestMapping.class);
// Controllerクラスに設定されているパスを出力
System.out.println(requestMappingClazz.value()[0]);
// Controllerメソッドに設定されているパスを出力
Arrays.stream(clazz.getDeclaredMethods()).forEach(a -> writeUri(a));
}
// 略
private static void writeUri(Method method) {
GetMapping getMapping = method.getAnnotation(GetMapping.class);
if (Objects.nonNull(getMapping)) {
writeValue("GET", getMapping.value());
}
PostMapping postMapping = method.getAnnotation(PostMapping.class);
if (Objects.nonNull(postMapping)) {
writeValue("POST", postMapping.value());
}
PutMapping putMapping = method.getAnnotation(PutMapping.class);
if (Objects.nonNull(putMapping)) {
writeValue("PUT", putMapping.value());
}
DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
if (Objects.nonNull(deleteMapping)) {
writeValue("DELETE", deleteMapping.value());
}
}
private static void writeValue(String methodType, String[] value) {
System.out.println("\t" + methodType + "\t" + (value.length == 0 ? "/" : value[0]));
}
(余談ですが、アノテーションのvalueってなんとなくStringと思い込んでいましたが、String配列でした。ひとつのクラス・メソッドに対して複数のパスをマッピングできるみたいですが、需要あります…?)
最後に
出力イメージはこんな感じです。超便利!
/hoge1/fuga1
GET /
POST /piyo1
/hoge2/fuga2
PUT /piyo2
DELETE /piyo3
今回は質よりスピード重視だったので妥協してしまいましたが、
調べる中で、@{リクエストメソッド}Mappingクラスは@RequestMappingのエイリアス的な位置付けであることが分かりました。
@AliasForあたりの詳細が解析出来たらwriteUri()に記載しているアノテーション毎の処理は共通化出来そうな気がしています。
(余力があったらチャレンジしてみます)
package org.springframework.web.bind.annotation
// 略
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
// @RequestMappingのメソッドを指定
@RequestMapping(
method = {RequestMethod.GET}
)
public @interface GetMapping {
// @RequestMappingの同名設定値のエイリアスであることを示す?
@AliasFor(
annotation = RequestMapping.class
)
String name() default "";
// 略