返回

在Jackson序列化/反序列化中如何优雅地获取请求上下文?

java

在Jackson序列化/反序列化中优雅地获取请求上下文

问题陈述

使用Jersey和Jackson框架而不依赖Spring时,在反序列化程序中访问ContainerRequestContext或HttpHeaders会遇到困难。

ImprovedLocalThread的局限性

我们尝试使用ImprovedLocalThread来解决此问题,但它并不是一个稳定的解决方案。

InjectableValues的解决方案

Jackson提供了InjectableValues对象,允许我们向反序列化程序注入自定义对象,包括ContainerRequestContext。

实施步骤

1. 创建InjectableValues提供程序:

public class MyInjectableValuesProvider implements InjectableValues.Provider {

    private final ContainerRequestContext requestContext;

    public MyInjectableValuesProvider(ContainerRequestContext requestContext) {
        this.requestContext = requestContext;
    }

    @Override
    public InjectableValues findInjectableValues(Object valueToInject, DeserializationContext context, BeanProperty property,
                                               TypeDeserializer typeDeserializer, TypeSerializer typeSerializer) {
        return new SimpleInjectableValues(requestContext);
    }
}

2. 创建自定义反序列化程序:

public class MyDeserializer<T> extends StdDeserializer<T> {

    @Inject
    private ContainerRequestContext requestContext;

    public MyDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public T deserialize(JsonParser pJsonParser, DeserializationContext pDeserializationContext)
            throws IOException {

        // Use the requestContext here.

        return null;
    }
}

3. 注册InjectableValues提供程序和自定义反序列化程序:

@Context
private ContainerRequestContext requestContext;

@POST
@Path("/my-resource")
@Consumes(MediaType.APPLICATION_JSON)
public Response myResource(@Context HttpServletRequest httpServletRequest) {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setInjectableValues(new MyInjectableValuesProvider(requestContext));
    mapper.registerModule(new SimpleModule().addDeserializer(MyClass.class, new MyDeserializer(MyClass.class)));
    
    ...
}

优点

使用InjectableValues比ImprovedLocalThread更稳定、更线程安全。

常见问题解答

1. 为什么使用InjectableValues而不是反序列化上下文?

反序列化上下文不保证在所有情况下都能提供访问,而InjectableValues提供了一种更可靠的方法。

2. 自定义反序列化程序是否比通用反序列化程序更慢?

性能差异可以忽略不计,并且使用InjectableValues带来的好处远远超过了潜在的开销。

3. InjectableValues是否与所有Jackson版本兼容?

InjectableValues自Jackson 1.9起可用,适用于所有后续版本。

4. 是否可以向InjectableValues注入其他对象?

是的,InjectableValues允许注入任何类型的对象,不限于ContainerRequestContext。

5. 在处理大型JSON响应时,使用InjectableValues是否会影响性能?

不会,InjectableValues的开销很低,对性能影响可以忽略不计。

结论

通过使用InjectableValues,我们可以向Jackson反序列化程序注入ContainerRequestContext,从而在反序列化期间访问ContainerRequestContext。这是一种比ImprovedLocalThread更稳定、更线程安全的解决方案,为使用Jersey/Jackson框架提供了更大的灵活性。