面对将JsonObject形状用于枚举时的错误处理问题。我在REST请求的DTO中使用了此类枚举,并希望在用户使用一些不存在的枚举以及可供他使用的枚举时通知用户。
因此,当JsonObject形状的Enum枚举时,REST调用将只向您返回500 Internal Server Error,而没有任何明确的消息实际上是什么错误。
当枚举不具有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]"
类似的响应,我希望在要使用具有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 spring注释,用于期望高于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