如何使用Java返回部分JSON响应?

我正在构build一个RESTful API,并希望为开发人员提供选项,以便select在JSON响应中返回哪些字段。 这篇博客文章展示了几个API(Google,Facebook,LinkedIn)允许开发者自定义响应的例子。 这被称为部分响应。

一个例子可能是这样的:

/users/123?fields=userId,fullname,title 

在上面的例子中,API应该返回用户“123”的userId,fullName和title字段。

我正在寻找如何在我的RESTful Web服务中实现这个想法。 我目前正在使用CXF(编辑:和jackson),但愿意尝试另一个JAX-RS实现。

这是我目前所拥有的。 它返回一个完整的用户对象。 我怎样才能返回API调用者想要在运行时基于“字段”paramaeter的字段? 我不想让其他领域为空。 我只是不想退还它们。

 @GET @Path("/{userId}") @Produces("application/json") public User getUser(@PathParam("userId") Long userId, @DefaultValue("userId,fullname,title") @QueryParam("fields") String fields) { User user = userService.findOne(userId); StringTokenizer st = new StringTokenizer(fields, ","); while (st.hasMoreTokens()) { // here's where i would like to select only the fields i want to return } return user; } 

更新:

我跟随unludo的链接,然后链接到这个: http ://wiki.fasterxml.com/JacksonFeatureJsonFilter

有了这个信息,我添加了@JsonFilter("myFilter")到我的领域类。 然后我修改了我的RESTful服务方法来返回String而不是User,如下所示:

 @GET @Path("/{userId}") @Produces("application/json") public String getUser(@PathParam("userId") Long userId, @DefaultValue("userId,fullname,title") @QueryParam("fields") String fields) { User user = userService.findOne(userId); StringTokenizer st = new StringTokenizer(fields, ","); Set<String> filterProperties = new HashSet<String>(); while (st.hasMoreTokens()) { filterProperties.add(st.nextToken()); } ObjectMapper mapper = new ObjectMapper(); FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", SimpleBeanPropertyFilter.filterOutAllExcept(filterProperties)); try { String json = mapper.filteredWriter(filters).writeValueAsString(user); return json; } catch (IOException e) { e.printStackTrace(); return e.getMessage(); } } 

我需要做更多的testing,但迄今为止这么好。

如果你使用Jackson(一个很好的JSON库 – 我相信Java的一种标准),你可以使用@View注释来过滤你想要的结果对象。

我知道你想要一些dynamic的东西,所以这有点复杂。 你会发现你在这里find: http : //www.cowtowncoder.com/blog/archives/2011/02/entry_443.html (看看6.完全dynamic过滤: @JsonFilter )。

我会感兴趣的解决scheme,你会发现。

在资源方法中为每个请求创build一个ObjectMapper实例可能会产生显着的性能开销。 根据jackson的performance,最佳实践对象映射器创build起来非常昂贵。

相反,您可以使用Jackson 2.3 ObjectWriterModifier / ObjectReaderModifierfunction在资源方法内自定义JAX-RS提供程序的Jackson对象编写器 。

下面是一个示例,演示如何注册一个ObjectWriterModifier线程本地对象,该对象改变了应用于资源方法内使用的JAX-RS Jackson提供程序的filter集合。 请注意,我没有针对JAX-RS实现testing代码。

 public class JacksonObjectWriterModifier2 { private static class FilterModifier extends ObjectWriterModifier { private final FilterProvider provider; private FilterModifier(FilterProvider provider) { this.provider = provider; } @Override public ObjectWriter modify(EndpointConfigBase<?> endpoint, MultivaluedMap<String, Object> responseHeaders, Object valueToWrite, ObjectWriter w, JsonGenerator g) throws IOException { return w.with(provider); } } @JsonFilter("filter1") public static class Bean { public final String field1; public final String field2; public Bean(String field1, String field2) { this.field1 = field1; this.field2 = field2; } } public static void main(String[] args) throws IOException { Bean b = new Bean("a", "b"); JacksonJsonProvider provider = new JacksonJsonProvider(); ObjectWriterInjector.set(new FilterModifier(new SimpleFilterProvider().addFilter("filter1", SimpleBeanPropertyFilter.filterOutAllExcept("field1")))); provider.writeTo(b, Bean.class, null, null, MediaType.APPLICATION_JSON_TYPE, null, System.out); } } 

输出:

 {"field1":"a"} 

库泽西岛实体过滤可以这样做:

https://github.com/jersey/jersey/tree/2.22.2/examples/entity-filtering-selectable

https://jersey.java.net/documentation/latest/entity-filtering.html

例如:

我的对象

 public class Address { private String streetAddress; private String region; private PhoneNumber phoneNumber; } 

url

人/ 1234?select=的StreetAddress,区域

返回

 { "streetAddress": "2 square Tyson", "region": "Texas" } 

添加到Maven

 <dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-entity-filtering</artifactId> <version>2.22.2</version> </dependency>