更新: 写完这一切几分钟后,我找到了第 12 章。Jersey 2.13 规范中的声明性超链接。它仍然“处于开发和实验阶段”,但看起来它更优雅地解决了这个问题。原帖中的所有代码都可以用这个代替...
public class Pie {
private String name;
Pie(String name) {
this.name = name;
}
@JsonIgnore
public String getName() {
return name;
}
@InjectLink(value="pies/{name}", style=Style.ABSOLUTE)
public URI url;
}
如果您需要向 Jackson 序列化程序发送任意数据,那么下面的解决方案仍然有效。
原创我遇到了同样的问题。具体来说,我希望我的资源只包含它们的 id(它们的 URI 末尾的东西),并找到一种方法来仅在 Jackson 生成 JSON 时使用 UriInfo 生成完整的 URI。我想避免解决方案,即我必须为每个请求在我的资源上创建新的覆盖对象,或者在序列化之前将 UriInfo 插入每个资源。
事实证明,从 Jackson 2.3 开始,有一种非常好的方法可以做到这一点。 Jackson 支持一个名为 ObjectWriterInjector 的类。使用它的静态 set 方法,您可以为每个请求提供一次您自己的 ObjectWriterModifier 实例。该实例可以在 UriInfo 可用的 Jersey 资源方法中创建和设置。在 Jackson 写出 JSON 之前,它会调用您的 ObjectWriterModifier,让您有机会调整它将使用的 ObjectWriter。在这种情况下,您可以使用 withAttribute 方法将 UriInfo 附加到 ObjectWriter。
那么 ObjectWriter 上的属性有什么用呢?事实证明,这些属性可通过 JsonSerializer 实现的 serialize 方法中的 SerializerProvider 参数获得。就我而言,我只想修改一个字段,所以我在 getter 上使用了 @JsonSerialize。然后在 serialize 方法中调用 SerializerProvider 参数的 getAttribute 方法来检索 UriInfo,然后使用它来构造完整的 URI。
这种方法应该适用于您希望将信息下推到 Jackson 序列化程序的任何情况。
简单的泽西资源...
@Path("/pies")
public class Pies {
static List<Pie> pies;
static
{
pies = new ArrayList<Pie>();
pies.add(new Pie("apple"));
pies.add(new Pie("pumpkin"));
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Pie> getPies(@Context UriInfo uriInfo) {
// This is the good stuff!!!!
ObjectWriterInjector.set(new ObjectWriterPlusUriInfo(uriInfo));
// Notice I don't have to anything to the objects in the Pies list
return pies;
}
}
调整 ObjectWriter 的类...
class ObjectWriterPlusUriInfo extends ObjectWriterModifier {
private UriInfo uriInfo;
ObjectWriterPlusUriInfo(UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
@Override
public ObjectWriter modify(EndpointConfigBase<?> endpoint,
MultivaluedMap<String, Object> responseHeaders, Object value,
ObjectWriter ow, JsonGenerator gen) throws IOException {
// Adding the UriInfo attribute
return ow.withAttribute("JerseyUriInfo", uriInfo);
}
}
带有 Jackson 注释的 Pie 类...
public class Pie {
private String name;
Pie(String name) {
this.name = name;
}
@JsonProperty(value="url")
@JsonSerialize(using=JacksonIdToUrlSerializer.class)
public String getName() {
return name;
}
}
序列化器...
public class JacksonIdToUrlSerializer extends JsonSerializer<String>{
@Override
public void serialize(String value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
UriInfo uriInfo = (UriInfo)provider.getAttribute("JerseyUriInfo");
jgen.writeString(uriInfo.getRequestUriBuilder().path(value).build().toString());
}
}
...的 GET
http://localhost:8080/service/api/pies...
生产...
[
{
url: "http://localhost:8080/service/api/pies/apple"
},
{
url: "http://localhost:8080/service/api/pies/pumpkin"
}
]
...的 GET
http://127.0.0.1:8080/service/api/pies...
生产...
[
{
url: "http://127.0.0.1:8080/service/api/pies/apple"
},
{
url: "http://127.0.0.1:8080/service/api/pies/pumpkin"
}
]
请注意,ObjectWriterInjector 在内部使用线程局部变量,因此使用更通用的方法根据每个请求向下传递数据似乎同样有效。