是否有全球基地Uri工厂?

时间:2014-04-01 03:11:13

标签: java java-ee jax-rs wildfly hateoas

我需要到达baseUri,我很喜欢这个

@Context
UriInfo uriInfo;

我的问题是我在一段代码中需要baseUri我无法注入,(实体的子对象)。我可以通过uriInfo或建造者,但这似乎并不理想,因为大多数对象都没有业务知道它。最终目标是我的JSON响应中的HATEOAS URI,但我不需要它是一个特定于JAX-RS的解决方案,我想如果我可以在我的jackson转换器或实体中获取Base URI,我可以创建那里的URIBuilder

2 个答案:

答案 0 :(得分:0)

UriInfo由JAX-RS实现和AFAIK管理,您实际上无法将其注入代码的其他位置(它不是CDI bean)。如果您的目标是实现HATEOAS,您可以编写自己的MessageBodyWriter,它将负责将您的实体对象图解组为JSON响应,并且您可以在其中注入此UriInfo

HTH。

答案 1 :(得分:0)

更新:我写完这一切后的几分钟,我发现了第12章。泽西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序列化程序发送任意数据,则下面的解决方案仍然有效。

ORIGINAL 我遇到了同样的问题。具体来说,我希望我的资源只包含它们的id(URI末尾的东西),并且只有在Jackson生成JSON时才能找到使用UriInfo生成完整URI的方法。我想避免解决方案,我必须在每个请求的资源上创建新的封面对象,或者在序列化之前将UriInfo插入每个资源。

事实证明,从Jackson 2.3开始,有一种非常好的方法可以做到这一点。 Jackson支持一个名为ObjectWriterInjector的类。使用其静态集方法,您可以为每个请求提供一次自己的ObjectWriterModifier实例。可以在您的Jersey资源方法中创建和设置该实例,其中UriInfo可用。在杰克逊写出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);
    }
}

带杰克逊注释的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 of ...

http://localhost:8080/service/api/pies...

...可生产

[
  {
  url: "http://localhost:8080/service/api/pies/apple"
  },
  {
  url: "http://localhost:8080/service/api/pies/pumpkin"
  }
]

GET of ...

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在内部使用Thread Local变量,因此使用该更通用的方法在每个请求的基础上传递数据似乎同样有效。