Вот такая ситуация.

У меня большая кодовая база с использованием Jersey 2.17, Jackson 2.6.3 и Spring 4.2.0.

У меня довольно много моделей с небольшим набором свойств, представленных с помощью @JsonProperty. Остальные по умолчанию исключены.

Есть много методов ресурсов Джерси, которые не используют аннотацию JsonView.

Внесите меня. Мне нужно написать несколько новых внутренних конечных точек API, которые открывают другое подмножество внутренних / конфиденциальных свойств модели. Я аннотировал эти "частные" свойства с помощью @JsonProperty и @JsonView(SuperSecretAndInternal.class).

Исходные общедоступные свойства Я добавил аннотацию @JsonView(PublicForEveryone.class).

Проблема в том, что существует множество обработчиков методов ресурсов, которые не используют JsonView. В результате отображаются все свойства (как PublicForEveryone, так и SuperSecretAndIntenal).


Редактировать. Добавление кода примера.

// POJO - before
@JsonAutoDetect(getterVisibility = NONE, isGetterVisibility = NONE, fieldVisibility = NONE)
class Person {

    @JsonProperty
    String name;
    @JsonProperty
    String age;

    Date createdDate;
    String socialSecurityNumber;

    // getters/setters not shown
}

Это использовалось в обработчике метода Джерси в PublicAPIResource.

@GET
@Path("/people")
public Person getUser(@PathParam("name") String name)
{
// get user by name, return user
}

И в результате получаем json:

{ name: "Jane", age: 20 }

Теперь я пришел и хочу предоставить уязвимые поля POJO в альтернативном частном / внутреннем API. Итак, я модифицирую POJO следующим образом:

// POJO - after
@JsonAutoDetect(getterVisibility = NONE, isGetterVisibility = NONE, fieldVisibility = NONE)
class Person {

    @JsonProperty
    @JsonView(PublicForEveryone.class)
    String name;

    @JsonProperty
    @JsonView(PublicForEveryone.class)
    String age;

    @JsonProperty
    @JsonView(SuperSecretAndInternal.class)
    Date createdDate;

    @JsonProperty
    @JsonView(SuperSecretAndInternal.class)
    String socialSecurityNumber;

    // getters/setters not shown
}

При создании просмотров:

public class Views
{

    public static class PublicForEveryone
    {}
    public static class SuperSecretAndInternal extends PublicForEveryone
    {}
}

И я создаю новый обработчик ресурсов Джерси в PrivateAPIResource

@GET
@Path("/internal/secret/people")
@JsonView( SuperSecretAndInternal.class )
public Person getUser(@PathParam("name") String name)
{
// get user by name, return user
}

Который возвращает json:

{ name: "Jane", age: 20, createdDate: xxx, socialSecuritynumber: 123  }

Но исходный PublicAPIResource теперь возвращает весь POJO Person, потому что у него нет аннотации @JsonView. В этом простом примере я мог бы просто добавить аннотацию и все готово, но в моей реальной кодовой базе есть много ресурсов, не говоря уже о случаях, когда People POJO является вложенным полем в других моделях.


Вопрос: Есть ли способ указать по умолчанию JsonView для POJO / модели? Намерение таково, что если обработчик метода ресурса jersey НЕ указывает @JsonView, то будет использоваться значение по умолчанию, вместо того, чтобы просто отображать каждое аннотированное свойство @JsonProperty.

Если нет, знает ли кто-нибудь другой способ добиться этого без изменения всех моих обработчиков методов ресурсов (потому что я не могу)?

Могу ли я предоставить сериализатор по умолчанию для POJO, который сериализирует его с представлением "по умолчанию", но каким-то образом позволяет явным представлениям проходить через него?

0
Casey 29 Фев 2016 в 07:34

1 ответ

Лучший ответ

Вы можете настроить включение / исключение по умолчанию, но я думаю, что это не решит вашу проблему. Вы проверяли JsonFilter http://wiki.fasterxml.com/JacksonFeatureJsonFilter, у него есть функция для определения фильтра по умолчанию который может быть применен ко всем pojos / моделям.

Пример pojo:

class Person{
    String name;
    String age;
    Date createdDate;
}
class User{
    String username;
    String password;
    Date createdDate;
}

CustomAnnotationInspector:

public class CustomIntrospector extends JacksonAnnotationIntrospector
{
  @Override
  public Object findFilterId(AnnotatedClass ac) {
    // Let's default to current behavior if annotation is found:
    Object id = super.findFilterId(ac);
    // but use simple class name if not
    if (id == null) {
       id = "DEFAULT_FILTER";
    }
    return id;
}

Подключите его к ObejctMapper:

ObjectMapper mapper = new ObjectMapper();

// create filter with id "DEFAULT_FILTER" and configure it to exclude 'createdDate' property.
FilterProvider filters = new SimpleFilterProvider().addFilter("DEFAULT_FILTER",
SimpleBeanPropertyFilter.serializeAllExcept("createdDate"));

JacksonAnnotationIntrospector jai = new CustomIntrospector ();

// plug the custom annotation that will use "DEFAULT_FILTER" if the pojo doesn't have @JsonFilter annotation.
String jsonPerson = mapper.setAnnotationIntrospector(jai).writer(filters).writeValueAsString(new Person());
String jsonUser = mapper.setAnnotationIntrospector(jai).writer(filters).writeValueAsString(new User());
0
KSTN 29 Фев 2016 в 09:29
Спасибо за ответ. Идея фильтра хороша, однако фильтры будут переопределять @ JsonView. Итак, чтобы полностью реализовать это, мне нужно отбросить все представления и реализовать поведение, подобное представлению, в JsonFilter. Это не идеально, поскольку вводит кучу нового кода отдельно от POJO.
 – 
Casey
29 Фев 2016 в 19:42