После Spring / Jackson-databind незначительное обновление HttpMessageConverter больше не работает - PullRequest
6 голосов
/ 01 февраля 2020

Мне пришлось обновить несколько пакетов для прохождения проверки безопасности белого источника, и теперь, когда обновлены зависимости, пользовательский HttpMessageConverter, который перехватывал и формировал ответ ранее, больше не работает. Соответствующие обновления зависимостей показаны ниже.

Tomcat-embed-core 8.5.50 -> 9.0.30

Контракт Spring Cloud, выпуск 2.0.1.RELEASE-> 2.0.6.RELEASE

Версия загрузки Spring 2.0.4.RELEASE -> 2.0.6.RELEASE

Jackson-databind 2.9.6 -> 2.10.0.pr1

Jackson-core: 2.10.1 -> 2.10.0. pr1

Вот пользовательский HttpMessageConverter, который работал ранее:

    private class JsonApiHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
    JsonApiHttpMessageConverter() {
        super(MediaType.valueOf(ResponseType.MEDIA_TYPE_JSON_API));
    }

    @Override
    protected boolean supports(final Class<?> clazz) {
        return clazz == HttpErrorResponse.class;
    }

    @Override
    protected Object readInternal(final Class<?> clazz, final HttpInputMessage inputMessage)
        throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override
    protected void writeInternal(final Object o, final HttpOutputMessage outputMessage)
        throws IOException, HttpMessageNotWritableException {
        try (OutputStreamWriter outputStream =
            new OutputStreamWriter(outputMessage.getBody(), Charset.defaultCharset())) {
            JsonAPIDocument document;
            if (o instanceof HttpErrorResponse) {
                // Build Error Document
                final HttpErrorResponse errorResponse = (HttpErrorResponse) o;
                final JsonApiErrorDTO errorDTO = new JsonApiErrorDTO(Integer.toString(errorResponse.getStatus()),
                    Integer.toString(errorResponse.getCode()), errorResponse.getMessage());
                document = new JsonAPIDocument();
                document.addError(errorDTO);
            } else { // Build JSON API Response Document
                final JsonApiDocumentBuilder documentBuilder = new JsonApiDocumentBuilder();
                documentBuilder.data(o);
                document = documentBuilder.build();
            }
            outputStream.write(new Gson().toJson(document));
            outputStream.flush();
        } catch (final InvalidJsonApiObjectException ijaoe) {
            LOG.error("Error in converting Object to JsonAPIDocument", ijaoe);
            throw new ServiceException(ijaoe);
        }
    }
}

он определен в классе, который регистрирует конвертеры сообщений, как показано ниже

@Configuration
public class ServiceConfiguration implements WebMvcConfigurer {

...

    @Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
    converters.add(new JsonApiHttpMessageConverter());
    converters.add(new ByteArrayHttpMessageConverter());
    converters.add(new StringHttpMessageConverter());
    converters.add(new ResourceHttpMessageConverter());
    converters.add(new SourceHttpMessageConverter<>());
    converters.add(new AllEncompassingFormHttpMessageConverter());
    converters.add(new MappingJackson2HttpMessageConverter());
    converters.add(new MappingJackson2CborHttpMessageConverter());
    converters.add(new Jaxb2RootElementHttpMessageConverter());
}

@Override
public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
    configurer.defaultContentType(MediaType.valueOf(ResponseType.MEDIA_TYPE_JSON_API));
}

}

Это код ответа об ошибке:

@XmlRootElement(name = "error")
@XmlAccessorType(XmlAccessType.FIELD)
@JsonApiType(type = "error")
public class HttpErrorResponse implements Serializable {
    private static final long serialVersionUID = 1321088631120274988L;

    @XmlTransient
    private int status;

    @XmlElement(name = "code", required = true)
    private int code;

    @XmlElement(name = "message", required = true)
    @JsonApiAttribute(name = "detail")
    private String message;

    @JsonApiIgnore
    @XmlElement(name = "uuid", required = true)
    private String uuid;

    public HttpErrorResponse() {
        this.uuid = UUID.randomUUID().toString();
    }

    public HttpErrorResponse(final int status, final int code, final String message) {
        this();
        this.status = status;
        this.code = code;
        this.message = message;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(final int status) {
        this.status = status;
    }

    public int getCode() {
        return code;
    }

    public void setCode(final int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(final String message) {
        this.message = message;
    }

    public String getUuid() {
        return uuid;
    }

    public void setUuid(final String uuid) {
        this.uuid = uuid;
    }

}

и объект, по-видимому, является возвращаемым, но конвертер сообщений не преобразует его. Старый формат ответа с работающим конвертером:

"{\"included\":[],\"errors\":[{\"status\":\"400\",\"code\":\"990002\",\"detail\":\"Invalid subscription id: XYZ\"}]}",

, а текущий ответ:

"responseBody": "{\"status\":400,\"code\":990002,\"message\":\"Invalid subscription id: XYZ\",\"uuid\":\"018fe1e3-3936-4c53-8612-61ef778fd811\"}",

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

@JsonPropertyOrder({ "data", "included", "errors" })
@JsonInclude(JsonInclude.Include.NON_NULL)
public class JsonAPIDocument extends AbstractJsonAPIDocument {

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private IJsonAPIDTO data;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    public IJsonAPIDTO getData() {
        return data;
    }

    public void setData(IJsonAPIDTO data) {
        this.data = data;
    }
}

Вот заголовки ответа:

"responseHeaders": {
    "X-Origin-Ref": "microservice",
    "X-Transaction-Ref": "b2e3d807-0d6f-40e7-90ad-43d5ecb455c2",
    "Content-Type": "application/vnd.api+json"
}

и ResponseType.MEDIA_TYPE_JSON_API равен

public static final String MEDIA_TYPE_JSON_API = "application/vnd.api+json"

В качестве отчаянной попытки я изменил метод поддержки класса JsonApiHttpMessageConverter, чтобы он всегда возвращал значение true, и преобразователь все еще не получает ответ

...