Джерси, игнорируя пользовательский объектMapper - PullRequest
1 голос
/ 05 мая 2019

Я использую Джексон 2.7.5 с Джерси 2.25.1. Я пытаюсь исправить существующий производственный код, который в настоящее время дает сбой с помощью «UnrecognizedPropertyException: Unrecognized field», когда он получает неожиданное поле во входных данных JSON.

Исследуя это, я обнаружил несколько старых постов (5+ лет), в которых предлагались различные исправления, которые сильно отличались от моего текущего кода. Я не обращал на них особого внимания, потому что они были для старых версий Джексона / Джерси. И более свежие предложения, включая собственную документацию Джерси (https://jersey.github.io/documentation/latest/media.html#json.jackson),, очень похожи на то, что у меня уже есть. На самом деле, на мой взгляд, мой существующий код уже соответствует текущей практике. Однако, Джерси кажется, игнорирует мой пользовательский параметр ObjectMapper ...

DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false

Я почти уверен, что настройка должна исправить ошибку, но Джерси, кажется, использует ObjectMapper по умолчанию вместо моих пользовательских настроек.

Во-первых, вот информация о зависимостях, которая, как мне кажется, соответствует тому, что показано в документации на Джерси (https://jersey.github.io/documentation/latest/media.html#json.jackson).

<dependency>
  <groupId>org.glassfish.jersey.media</groupId>
  <artifactId>jersey-media-json-jackson</artifactId>
  <version>${jersey.version}</version>
</dependency>

Вот вызов, который возвращает ошибку:

// this will throw an exception if it can't convert the string to the class
PropSearchResponse propResponse = null;
try {
  propResponse = getResponse.readEntity(PropSearchResponse.class);
} catch(final ProcessingException e) {
  throw new ProcessResultException(Code.FAILED, "failed to map from prop response", e);
}

Вот оригинальный код для моего пользовательского ObjectMapper:

@Provider()
@Produces(value = MediaType.APPLICATION_JSON)
public class OutMapperProvider implements ContextResolver<ObjectMapper> {
  private final ObjectMapper mapper;

  public OutMapperProvider() {
    mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
    mapper.setSerializationInclusion(Include.NON_NULL);
    mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"));
  }

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

Вот пример из документации на Джерси:

@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> {

    final ObjectMapper defaultObjectMapper;

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

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

    private static ObjectMapper createDefaultMapper() {
        final ObjectMapper result = new ObjectMapper();
        result.configure(Feature.INDENT_OUTPUT, true);

        return result;
    }
}

Я попробовал пример с Джерси (конечно, изменив имена, чтобы соответствовать моим), а также несколько других примеров, которые я нашел в Интернете. Пример Джерси выполняет настройку после @Override. Большинство других примеров делают это до @Override, но все они в значительной степени похожи друг на друга и на мой существующий код. Но, похоже, это не имеет значения. Независимо от того, что я пробовал, пользовательская конфигурация игнорируется, и Джерси вызывает ObjectMapper по умолчанию, который завершается ошибкой в ​​неожиданных полях JSON.

Отказ от ответственности: Это мой первый опыт с Джерси и Джексоном. У меня пока нет хорошего понимания основного механизма. Я просто пытаюсь следовать шаблонам примеров.

Обновление: Я считаю, что приведенный выше код в основном правильный. Но комментарий Павла ниже говорит, что мне нужно зарегистрировать пользовательский ObjectMapper. Я попытался воспроизвести несколько примеров, которые я нашел в Интернете (например, пример 4.2 на https://docs.huihoo.com/jersey/2.13/deployment.html#environmenmt.appmodel,), но безуспешно. Для моей текущей попытки я попытался добавить новый класс MyApplication в существующий пакет конфигурации (com.dmx.repl.config), используя ResourceConfig из Джерси. Код ниже. Но все же, это не работает.

Редактировать: игнорировать этот код, он не работал. Смотрите решение ниже.

package com.dmx.repl.config;

import org.glassfish.jersey.server.ResourceConfig;
import com.dmx.repl.commons.OutMapperProvider;


/**
 *
 * @author Greg
 * @version 1.0
 */

// Attempt to register custom ObjectMapper
public class MyApplication extends ResourceConfig {
  public MyApplication() {
    // I've tried both of these.
    //register(OutMapperProvider.class);
    packages("com.dmx.repl.commons");
  }
}

1 Ответ

1 голос
/ 07 мая 2019

Сейчас работает. Джерси теперь распознает пользовательский ObjectMapper, который настроен на игнорирование неизвестных полей JSON с помощью "FAIL_ON_UNKNOWN_PROPERTIES, false".

Код ObjectMapper выше верен. Проблема (как предложил Пол в комментариях) состояла в том, что клиент не зарегистрировал пользовательский объектный макет. Это было исправлено очень просто, добавив следующую строку в метод настройки клиента, следуя настройке клиента с помощью ClientBuilder.

this.client.register(OutMapperProvider.class);
...