【问题标题】:Applying different Jackson filter for different Jersey REST service calls为不同的 Jersey REST 服务调用应用不同的 Jackson 过滤器
【发布时间】:2012-06-06 11:29:25
【问题描述】:

我正在使用 Jersey 来实现 JAX-RS REST 样式的服务以及用于 JSON 映射的 Jackson 2.0.2。其中一个 REST 服务返回一个List<EntityA>(我们称之为indexA),其中EntityA 包含另一个List<EntityB>,而另一个服务只返回一个List<EntityB>(我们称之为indexB):

@Entity
@JsonAutoDetect
public class EntityA {
  @Id
  private String id;

  @OneToMany
  private List<EntityB> b;

  ...
}

@Entity
@JsonAutoDetect
@JsonFilter("bFilter")
public class EntityB {
  @Id
  private String id;

  private String some;
  private String other;
  private String attributes;

  ...
}

@Path("/a")
public class AResource {

  @GET
  @Path("/")
  public List<EntityA> indexA() {
    ...
  }
}

@Path("/b")
public class BResource {

  @GET
  @Path("/")
  public List<EntityB> indexB() {
    ...
  }
}

我想要实现的是对indexA 调用应用杰克逊过滤器,这样子EntityB 元素的所有属性都不会被序列化。 OTOH,indexB 应该完整地返回 EntityB

我知道ContextResolver&lt;ObjectMapper&gt; 的存在,我已经将其用于其他目的。不幸的是,对于ContextResolver,似乎不可能区分这两种服务调用,因为提供给ContextResolver.getContext(Class)Class 在这两种情况下都是ArrayList(并且由于类型擦除,我无法弄清楚泛型类型参数)。

根据被映射的实体类型,有没有更适合配置ObjectMapper/FilterProvider 的钩子?

我可以使用How to return a partial JSON response using Java? 中提出的方法:手动映射到String,但这会扼杀基于声明性注释的方法的整体美感,所以我想避免这种情况。

【问题讨论】:

    标签: java jersey jax-rs jackson


    【解决方案1】:

    我也遇到了同样的情况,经过大量研究,我想通了,解决方案是使用 @JsonView 和 Spring,它可以将 ObjectMapper 注入 JSON Writer 而不会破坏泽西岛的美丽。

    我正在研究一组 REST API,我想获取 SystemObject 的实例列表以及 SystemObject 的特定实例的详细信息,就像你一样,我只想要非常有限的每个属性的数量列表中的实例和细节中的一些附加属性,我只是为它们定义视图,并在SystemObject 类中添加注释。但默认情况下,所有没有 @JsonView 注释的属性都会输出到 JSON,但是有一个配置 item(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION) 可以用来排除它们。

    问题是我必须将其设置为 true 以满足我的需要。但是我无法更改将对象转换为 JSON 的魔术的 ObjectMapper,通过阅读下面的 3 篇文章,我知道我能做的唯一方法是将修改后的 ObjectMapper 注入泽西岛。 现在我得到了我想要的。

    这就像您针对一个数据库表创建多个视图。

    这 3 个链接将以不同的方式帮助您:

    How to create a ObjectMapperProvider which can be used by Spring to inject

    Jersey, Jackson, Spring and JSON

    Jersey + Spring integration example

    REST 资源:

    package com.john.rest.resource;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.HeaderParam;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.WebApplicationException;
    import javax.ws.rs.core.Context;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Request;
    import javax.ws.rs.core.UriInfo;
    
    import org.codehaus.jackson.map.annotate.JsonView;
    import org.springframework.stereotype.Component;
    
    import com.midtronics.esp.common.EspException;
    import com.midtronics.esp.common.SystemObject;
    import com.midtronics.esp.mobile.model.SystemObjectView;
    import com.midtronics.esp.model.accesscontrol.AccessControlBean;
    import com.midtronics.esp.model.site.SiteBean;
    
    @Component
    @Path("/hierarchy")
    public class Hierarchy {
    
        // Allows to insert contextual objects into the class, 
        // e.g. ServletContext, Request, Response, UriInfo
        @Context
        UriInfo uriInfo;
    
        @Context
        Request request;
    
        // Return the list of sites
        @GET
        @Path("sites")
        @Produces(MediaType.APPLICATION_JSON)
        @JsonView({SystemObjectView.ObjectList.class})
        public List<SystemObject> listSite(
                @HeaderParam("userId") String userId, 
                @HeaderParam("password") String password) {
            ArrayList<SystemObject> sites= new ArrayList<SystemObject>();
    
            try{
                if(!AccessControlBean.CheckUser(userId, password)){
                    throw new WebApplicationException(401);
                }
                SystemObject.GetSiteListByPage(sites, 2, 3);
    
                return sites;
            } catch(EspException e){
                throw new WebApplicationException(401);
            } catch (Exception e) {
                throw new WebApplicationException(500);
            }
        }
    
        // Return the number of sites
        @GET
        @Path("sites/total")
        @Produces(MediaType.TEXT_PLAIN)
        public String getSiteNumber(@HeaderParam("userId") String userId, 
                @HeaderParam("password") String password) {
            try{
                return Integer.toString(SiteBean.GetSiteTotal()); 
            } catch(EspException e){
                throw new WebApplicationException(401);
            } catch (Exception e) {
                throw new WebApplicationException(500);
            }
        }
    
    }
    

    REST 模型:

    package com.john.rest.model;
    
    import java.io.Serializable;
    import java.util.ArrayList;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    import org.codehaus.jackson.annotate.JsonIgnore;
    import org.codehaus.jackson.annotate.JsonProperty;
    import org.codehaus.jackson.map.annotate.JsonView;
    
    import com.midtronics.esp.mobile.model.SystemObjectView;
    import com.midtronics.esp.model.common.ICommonDAO;
    
    @XmlRootElement
    public class SystemObject implements Serializable
    {
        private static final long serialVersionUID = 3989499187492868996L;
    
        @JsonProperty("id")
        @JsonView({SystemObjectView.ObjectList.class, SystemObjectView.ObjectDetail.class})
        protected String objectID = "";
    
        @JsonProperty("parentId")
        protected String parentID = "";
    
        @JsonProperty("name")
        @JsonView({SystemObjectView.ObjectList.class, SystemObjectView.ObjectDetail.class})
        protected String objectName = "";
    
        //getters...
        //setters...
    
    }
    

    REST 模型视图:

    package com.john.rest.model;
    
    public class SystemObjectView {
        public static class ObjectList { };
    
        public static class ObjectDetail extends ObjectList { }
    }
    

    【讨论】:

    • 如果我能投票 20 次,我会的。在我读到这篇文章之前,我不知道你可以将 JsonView 应用于 Jersey 资源方法来选择要序列化的视图。如果文档中对此进行了描述,我完全错过了它。顺便说一句——在没有 Spring 的情况下工作(我正在使用 Felix)。非常感谢!
    • 我不认为您在文档中错过了这一点。我一直在寻找一种好方法来做到这一点,直到我看到这篇文章才找到。
    • 感谢报告,项目 README 现在包括适用于 JAX-RS 端点的注释的简要描述——github.com/FasterXML/jackson-jaxrs-providers——希望其他容器(Spring、Restlet)也有/添加类似的东西.
    猜你喜欢
    • 2010-11-29
    • 2012-04-05
    • 1970-01-01
    • 1970-01-01
    • 2016-03-12
    • 1970-01-01
    • 1970-01-01
    • 2017-11-11
    • 2020-02-27
    相关资源
    最近更新 更多