Использование настроенного ObjectWriter с Джерси - PullRequest
4 голосов
/ 11 марта 2019

Я занимаюсь разработкой веб-сервиса REST.Джерси как поставщик jax-rs и Джексон для сериализации / десериализации.Я также разрабатываю клиент на основе Retrofit2.

Моя иерархия классов обеспечивается сторонней библиотекой, и все классы происходят от корневого базового класса BaseObject.Некоторые из этих классов имеют нежелательные геттеры, например isEmpty, которые я хочу игнорировать при сериализации (обратите внимание, что важно, чтобы они вообще не сериализовались и использования FAIL_ON_UNKNOWN_PROPERTIES для десериализации в моем случае недостаточно).

Я использовал Джексона @JsonFilter на BaseClass с помощью Mixins.Чтобы применить фильтр, насколько я знаю, нужно использовать следующее:

new ObjectMapper().writer(filterProvider).writeValueAsString...

Здесь все в порядке: нежелательное свойство успешно отфильтровано из созданного json.

Теперь мне нужно настроить Jersey и Retrofit2 для использования моего настроенного сериализатора / десериализатора json.

Для Джерси сериализация / десериализация может быть настроена с использованием класса Provider, который реализует ContextResolver<ObjectMapper> и возвращает настроенный ObjectMapperв методе getContext(Class<?> type).

Аналогично в Retrofit2, используя Retrofit.Builder().addConverterFactory(JacksonConverterFactory.create(objectMapper)), можно настроить сериализацию / десериализацию.

ПРОБЛЕМА ЭТО new ObjectMapper().writer(filterProvider) имеетвведите ObjectWriter, а не типа ObjectMapper.Как я могу сказать Джерси и Retrofit2 использовать мой настроенный ObjectWriter, который использует мои фильтры?

1 Ответ

1 голос
/ 13 марта 2019

Начиная с версии 2.6 у Джексона есть метод setFilterProvider для ObjectMapper.Я не пробовал, но в документации есть описание для этого: https://fasterxml.github.io/jackson-databind/javadoc/2.6/com/fasterxml/jackson/databind/ObjectMapper.html#setFilterProvider-com.fasterxml.jackson.databind.ser.FilterProvider-. Вы можете попробовать, я думаю, потому что описание подходит для вашего случая.

Я создал тестовый сервис с Джерси 2.7 и Джексоном 2.9.5.он работает нормально, но вы должны знать некоторые приемы, чтобы запустить его.

В pom.xml добавьте Джерси и Джексона:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jersey.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>${jackson.version}</version>
    </dependency>
</dependencies>
<properties>
    <jersey.version>2.7</jersey.version>
    <jackson.version>2.9.5</jackson.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Вы должныопределите эту зависимость:

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
    </dependency>

это обязательно.

В файле web.xml необходимо сделать ссылку на конфигурацию вашего сервиса:

<web-app version="2.5"
     xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>org.glassfish.jersey.server.ResourceConfig</param-name>
        <param-value>com.home.MyApplication</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

MyApplication.java:

package com.home;

import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;

import javax.ws.rs.ApplicationPath;

@ApplicationPath("/webapi")
public class MyApplication extends ResourceConfig {

    public MyApplication() {

        register(ObjectMapperProvider.class);
        register(JacksonFeature.class);
        register(MyResource.class);

    }
}

С помощью пользовательского ObjectMapperProvider необходимо зарегистрировать класс JacksonFeature.class, поскольку без него Джерси не использует пользовательскийObjectMapperProvider.

ObjectMapperProvider.java:

package com.home;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper>{

    final ObjectMapper defaultObjectMapper;

    public ObjectMapperProvider() {
        defaultObjectMapper = createDefaultMapper();
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {return defaultObjectMapper;}

    public static ObjectMapper createDefaultMapper() {

        final ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.setFilters(new SimpleFilterProvider().addFilter("dataFilter", SimpleBeanPropertyFilter.serializeAllExcept("region", "city")));
        return mapper;

    }
}

Чтобы определить фильтр, используйте методы setFilters.Этот метод не рекомендуется, но библиотека Джерси, которая называется 'jersey-hk2', не знает новый метод 'setFilterProvider' и выдает исключение.При старом методе все работает нормально.

Бизнес-объект с @JsonFilter:

@JsonFilter("dataFilter")
public class SimpleData {

    @JsonProperty("name")
    String firstName;

    @JsonProperty("secondName")
    String lastName;

    @JsonProperty("country")
    String country;

    @JsonProperty("region")
    String region;

    @JsonProperty("city")
    String city;

    @JsonProperty("genre")
    String genre;

    public SimpleData() {

        this.firstName = "Bryan";
        this.lastName = "Adams";

        this.country = "Canada";
        this.region = "Ontario";
        this.city = "Kingston";
        this.genre = "Rock";

    }

    public String getFirstName() {    return firstName;       }
    public void setFirstName(String firstName) {  this.firstName = firstName;  }
    public String getLastName() {   return lastName;    }
    public void setLastName(String lastName) {  this.lastName = lastName;       }
    public String getCountry() {    return country;    }
    public void setCountry(String country) {  this.country = country;      }
    public String getRegion() {   return region;     }
    public void setRegion(String region) {   this.region = region;       }
    public String getCity() {  return city;     }
    public void setCity(String city) {   this.city = city;     }
    public String getGenre() {   return genre;      }
    public void setGenre(String genre) {    this.genre = genre;     }
}

MyResource.java:

@Path("myresource")
public class MyResource {


    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public SimpleData getIt() {

        return new SimpleData();

    }
}

Отфильтрованный результат:

enter image description here

...