Подтвердить что ты не робот

Применение другого фильтра Джексона для различных вызовов службы REST Джерси

Я использую Jersey для реализации JAX-RS REST-сервисов наряду с Jackson 2.0.2 для сопоставления JSON. Один из этих 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<ObjectMapper>, которое я уже использую для других целей. К сожалению, для ContextResolver, как представляется, невозможно отличить обе служебные вызовы, поскольку Class, поставляемый в ContextResolver.getContext(Class), равен ArrayList в обоих случаях (и благодаря стиранию типа я не могу определить параметры типового типа).

Есть ли какие-либо крючки, лучше подходящие при настройке ObjectMapper/FilterProvider в зависимости от типа объекта, который отображается?

Я мог бы использовать подход, предложенный в Как вернуть частичный ответ JSON с помощью Java?: Вручную сопоставление с String, но это убивает всю красоту декларативный подход, основанный на аннотациях, поэтому я хотел бы избежать этого.

4b9b3361

Ответ 1

Я был в той же ситуации, после тонких исследований, я понял, решение заключается в использовании @JsonView и Spring, которые могут вставлять ObjectMapper в JSON Writer, не убивая красоту Джерси.

Я работаю над набором API REST, я хочу получить список экземпляров SystemObject, а деталь - конкретный экземпляр SystemObject, так же как вы, я просто хочу очень ограниченное количество свойств каждого экземпляр в списке и некоторые дополнительные свойства в деталях, я просто определяю Views для них и добавляю аннотацию в классе SystemObject. но по умолчанию все свойства без аннотации @JsonView будут выводиться в JSON, но есть конфигурация item(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION), которую я могу использовать, чтобы исключить их.

Проблема в том, что я должен установить ее в соответствии с моей потребностью. но я не могу изменить ObjectMapper, который делает магию, чтобы преобразовать объект в JSON, прочитав 3 статьи ниже, я понял, что единственный способ сделать это - ввести модифицированный ObjectMapper в Jersey. Теперь я получил то, что хочу.

Это похоже на создание нескольких представлений относительно таблицы базы данных.

Эти 3 ссылки помогут вам по-разному:

Как создать ObjectMapperProvider, который может использоваться Spring для ввода

Джерси, Джексон, Spring и JSON

Пример интеграции с Джерси + Spring

Ресурс 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 { }
}