Using Enums as Request Parameters in Spring
Springboot において Enum を Request Parameter に用いる方法
en: Using Enums as Request Parameters in Spring
テストした当時の環境は:
openjdk version "17.0.8.1" 2023-08-24
OpenJDK Runtime Environment (build 17.0.8.1+1-Ubuntu-0ubuntu122.04)
OpenJDK 64-Bit Server VM (build 17.0.8.1+1-Ubuntu-0ubuntu122.04, mixed mode, sharing)
Springframework.boot が 'org.springframework.boot' version '3.1.5'
である。
大体の部分においては、Using Enums as Request Parameters in Spring に準じれば良いが、2点注意が必要であった。
1点目は、@Component
を使った方が良さそうという点である。
2点目は、Enum が値をもつ場合の扱いについてである。
@Component
について
Spring's @RequestParam with Enum の回答
https://stackoverflow.com/questions/39774427/springs-requestparam-with-enum/53266048#53266048
に、
If you are using Spring Boot, this is the reason that you should not use
WebMvcConfigurationSupport
.
というものがあった。WebMvcConfigurationSupport
を用いる必要がないのであれば使わなくて良い…のだと解釈した。
@Configuration
と public class WebConfig implements WebMvcConfigurer
であるクラスを用いることなく、もともとの Converter に対して @Component
を加えるだけで十分動作した。
値をもつ Enum に対する工夫について
Enum が
public enum Modes {
ALPHA, BETA;
}
ではなく
public enum Modes {
HIGH("高"), MIDDLE("中"), LOW("低");
public final String label;
private Priority(String label) {
this.label = label;
}
}
のように値をもつ(正しい表現ではないかもしれない)場合において若干工夫が必要だったので書き残しておく。
元の例では:
public class StringToEnumConverter implements Converter<String, Modes> {
@Override
public Modes convert(String source) {
return Modes.valueOf(source.toUpperCase());
}
}
のようにしていた。
ここでは、Priority を以下のように定義する:
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public enum Priority {
HIGH("高"), MIDDLE("中"), LOW("低");
public static final Map<String, Priority> PRIORITY_LABEL_MAP = Stream.of(Priority.values()).collect(Collectors.toMap(t -> t.label, t -> t));
public final String label;
private Priority(String label) {
this.label = label;
}
public static Optional<Priority> findByLabel(String label) {
return Optional.ofNullable(PRIORITY_LABEL_MAP.get(label));
}
}
Priority は label を持つ。URL では、「高」や「中」という値を query string として受け取る。つまり、Controller は、「高」や「中」の形で URL に現れる Query Parameter を RequestParam として受け取りたいため、Converter はそれを考慮する必要がある。
例えば、以下のようにしてあげると良い。
import java.util.Optional;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import com.example.demo.enums.Priority;
@Component
public class LabelToPriorityConverter implements Converter<String, Optional<Priority>> {
@Override
public Optional<Priority> convert(String label) {
return Priority.findByLabel(label);
}
}
つまり、org.springframework.core.convert.converter.Converter
を implement したクラスが、@org.springframework.stereotype.Component
アノテーションされていれば良い。
Controller は以下のようになっていれば良い(一部抜粋)
@GetMapping
public String getWithEnum(
@RequestParam(value = "priority") Optional<Priority> priority) {
...
}
動作するソースコードを
https://github.com/takotakot/spring-test/blob/enum_param
に置いておくことにした。
Priority.java
LabelToPriorityConverter.java
EnumController.java
サンプルのテストも EnumControllerTest.java に置いてある。
良くコード素片が動く形でおかれていないため、初心者には分からない…ということが多いので、動作するコード一式にしておいた。
備考
もう少し DRY (Don't Repeat Yourself) の原則に従って、複数の Enum についても変換して受け取るできる方法については、Spring MVCのRestControllerのRequestParamで任意のEnumをコードなどの別の値で受け取る方法が良さそうである。
参考
- Using Enums as Request Parameters in Spring https://www.baeldung.com/spring-enum-request-param
- Spring's @RequestParam with Enum の回答 https://stackoverflow.com/questions/39774427/springs-requestparam-with-enum/53266048#53266048
- https://github.com/spring-projects/spring-boot/issues/2116#issuecomment-66622846
- Spring MVCのRestControllerのRequestParamで任意のEnumをコードなどの別の値で受け取る方法 https://qiita.com/yushi_koga/items/ff3338c34ce59c20bd5f
ディスカッション
コメント一覧
まだ、コメントがありません