Правильная обработка ошибок для перечисления формы JsonObject - PullRequest
0 голосов
/ 05 июня 2019

Столкнулся с проблемой обработки ошибок, когда для перечислений используется форма 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...