Столкнулся с проблемой обработки ошибок, когда для перечислений используется форма JsonObject. Я использую такие перечисления в DTO запроса REST и хочу уведомить пользователя, когда он / она использовал какое-то несуществующее перечисление и какие перечисления доступны для него.
Так что, когда Enum формы JsonObject, вызов REST просто вернет вам 500 Internal Server Error без какого-либо четкого сообщения о том, что на самом деле не так.
Когда enum без формы JsonObject, вызов REST вернет 400 Bad Request с сообщением:
"Cannot deserialize value of type `com.some.learn.model.SomeStatus` from String \"gdgd\": value not one of declared Enum instance names: [ENUM1, ENUM2, ENUM3]"
Аналогичный ответ я ожидаю увидеть, когда захочу использовать enum с формой JsonObject. Как этого добиться?
Мое перечисление:
@Getter
@RequiredArgsConstructor
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum SomeEnum {
ENUM_1(CONTEXT_1, FEATURE_1, EDIT),
ENUM_2(CONTEXT_1, FEATURE_1, VIEW),
ENUM_3(CONTEXT_2, FEATURE_2, EDIT);
private final SomeContext context;
private final SomeFeature feature;
private final SomeType type;
@JsonCreator
public static SomeEnum fromJson(@JsonProperty("name") String name) {
return valueOf(name);
}
}
DTO:
@Data
public class SomeDto {
...
@NotEmpty
@UniqueElements
private List<SomeEnum> someEnums;
}
Также @Validated пружинная аннотация, используемая в слое контроллера для метода, который ожидает выше DTO.
При передаче несуществующего перечисления появляется следующее исключение в журналах:
org.springframework.core.codec.CodecException: Type definition error: [simple type, class com.some.learn.model.SomeEnum]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.some.learn.model.SomeEnum`, problem: No enum constant com.some.learn.model.SomeEnum.balbla
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.some.learn.model.SomeDto["someEnums"]->java.util.ArrayList[0])
at org.springframework.http.codec.json.AbstractJackson2Decoder.lambda$decodeInternal$1(AbstractJackson2Decoder.java:130)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:350)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.tryEmit(FluxFlatMap.java:501)
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onNext(FluxFlatMap.java:943)
at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onNext(ScopePassingSpanSubscriber.java:97)
at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:243)
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:201)
at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.request(ScopePassingSpanSubscriber.java:80)
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onSubscribe(FluxFlatMap.java:933)
at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onSubscribe(ScopePassingSpanSubscriber.java:72)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63)
at reactor.core.publisher.FluxLiftFuseable.subscribe(FluxLiftFuseable.java:70)
at reactor.core.publisher.Flux.subscribe(Flux.java:7793)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:389)
at reactor.core.publisher.FluxMapSignal$FluxMapSignalSubscriber.onNext(FluxMapSignal.java:147)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114)
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:205)
at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:321)
at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:318)
at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:450)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:141)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:345)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:337)
at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:191)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:345)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:337)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:345)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:337)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:345)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:677)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:612)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:529)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:491)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.some.learn.model.SomeEnum`, problem: No enum constant com.some.learn.model.SomeEnum.balbla
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.some.learn.model.SomeDto["someEnums"]->java.util.ArrayList[0])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1608)
at com.fasterxml.jackson.databind.DeserializationContext.handleInstantiationProblem(DeserializationContext.java:1073)
at com.fasterxml.jackson.databind.deser.std.FactoryBasedEnumDeserializer.deserialize(FactoryBasedEnumDeserializer.java:146)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:286)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:369)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:1574)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:965)
at org.springframework.http.codec.json.AbstractJackson2Decoder.lambda$decodeInternal$1(AbstractJackson2Decoder.java:120)
... 48 common frames omitted
Caused by: java.lang.IllegalArgumentException: No enum constant com.some.learn.model.SomeEnum.balbla
at java.base/java.lang.Enum.valueOf(Enum.java:240)
at com.some.learn.model.SomeEnum.valueOf(SomeEnum.java:14)
at com.some.learn.model.SomeEnum.fromJson(SomeEnum.java:117)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.fasterxml.jackson.databind.introspect.AnnotatedMethod.callOnWith(AnnotatedMethod.java:122)
at com.fasterxml.jackson.databind.deser.std.FactoryBasedEnumDeserializer.deserialize(FactoryBasedEnumDeserializer.java:138)
... 57 common frames omitted