在Jackson序列化/反序列化中如何优雅地获取请求上下文?
2024-03-27 08:19:28
在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框架提供了更大的灵活性。