委托自定义 Jackson 解串器

问题描述

情况如下:我设法让 Jackson 反序列化以下泛型 ResponseWrapper<T>

static final class ResponseWrapper<T> {
    
    private ResponseData <T> response;
    
    protected static final class ResponseData<T> {
    
        private int    status;
        private T      data;
    
    }
    
}

使用以下 ParameterizedTypeReference

public static <T> ParameterizedTypeReference <ResponseWrapper<T>> typeReferenceOf ( Class<T> tClass ) {
    return ParameterizedTypeReference.forType( ParameterizedTypeImpl.make( ResponseWrapper.class,new Type[]{ tClass },null ) );
}

问题:我需要处理 T 的反序列化将失败的情况,因为 data 的值不是一个对象而是一个 {{1} } 反而。我需要捕获异常并将此值分配给 String 中的另一个属性,例如 ResponseData。我的看法是用 String errorMessage 注释 response 属性,但我不知道如何正确实现 @JsonDeserialize( using = ResponseDeserializer.class ) 以便它将反序列化委托给 Jackson 的实现,我只是捕获发生时异常。

有关更多上下文,我使用 JsonDeserializer 作为 HTTP 客户端,并使用发生反序列化的交换 WebClient 处理响应。

解决方法

为了获得泛型类型,我让 ResponseDeserializer 实现 ContextualDeserializer

@Override
public JsonDeserializer<?> createContextual ( DeserializationContext context,BeanProperty property ) throws JsonMappingException {

   JavaType wrapperType = property.getType();
   JavaType valueType = wrapperType.containedType(0);
   return new ResponseDeserializer<>( valueType );

}

这使我能够使用特定的 JavaType 创建反序列化器的具体实例。以下是完整的解决方案:

private static final class ResponseDeserializer<T> extends JsonObjectDeserializer<ResponseWrapper.ResponseData<T>> implements ContextualDeserializer  {
   
   private final JavaType javaType;

   public ResponseDeserializer ( ) {
       this.javaType = null;
   }
   
   public ResponseDeserializer ( JavaType javaType ) {
       this.javaType = javaType;
   }
   
   @Override
   public JsonDeserializer<?> createContextual ( DeserializationContext context,BeanProperty property ) throws JsonMappingException {

       JavaType wrapperType = property.getType();
       JavaType valueType = wrapperType.containedType(0);
       return new ResponseDeserializer<>( valueType );
       
   }

   @Override
   protected ResponseWrapper.ResponseData<T> deserializeObject ( JsonParser jsonParser,DeserializationContext context,ObjectCodec codec,JsonNode tree ) throws IOException {
       
       int status = tree.get( "status" ).asInt();
       JsonNode dataNode = tree.get( "data" );
       
       try {

           final T data; {
               
               if ( dataNode == null ) {
                   data = null;
               } else {
                   JsonParser dataParser = dataNode.traverse();
                   JsonToken token = dataParser.nextToken(); // handle?
                   data = context.readValue( dataParser,javaType );
               }
               
           };
           
           return new ResponseWrapper.ResponseData<T>( status,data );
           
       } catch ( InvalidDefinitionException e ) {
           
           String errorMessage = dataNode.asText();
           return new ResponseWrapper.ResponseData<T>( status,errorMessage );
           
       }

   }
   
}