Притвориться, что параметр не кодируется

Я рефакторинг устаревшей кодовой базы для использования Feign, и у меня есть некоторые проблемы:

  1. Ни один оператор журнала Feign не выводится на консоль.

    • Despite instantiating with a logger and full log level
  2. Feign не кодирует мой параметр reservationSearch

    • Feign just POST the toString of the Object

Определение притворства:

public interface EPCReservationClient {
    @RequestLine("POST v1/searchReservations")
    @Headers({"clientId: {clientId}", "Content-Type: application/json", 
              "Authentication: {authentication}"})
    @Body("{reservationSearch}")
    ReservationSearchResponse reservationSearch(
        @Param("authentication") String authentication, //apiToken
        @Param("clientId") String clientId,
        @Param("reservationSearch") 
        ReservationSearch<ReservationSearchParameters> reservationSearch);
}

Создание экземпляра

Feign.builder()
    .logger(new Logger.JavaLogger())
    .decoder(new JacksonDecoder())
    .encoder(new JacksonEncoder(new ObjectMapper().findAndRegisterModules()))
    .logLevel(Logger.Level.FULL)
    .target(EPCReservationClient.class, restUrl);

Тип параметра (не убивайте меня, не мой код):

public class ReservationSearch<T> {

    @JsonProperty("hotelID")
    private final int hotelID;
    private final String languageId;
    @JsonProperty("reservationSearchParameters")
    private final T parameters;
    @JsonProperty("reservationID")
    private final List<Long> reservationID;

    public ReservationSearch(int hotelID, T parameters, final List<Long> reservationID) {
        this.hotelID = hotelID;
        this.languageId = "1033";
        this.parameters = parameters;
        this.reservationID = Optional.ofNullable(reservationID)
                                     .orElseGet(Collections::emptyList);
    }

    public static ReservationSearch<ReservationSearchParameters> forLastName(
        int maxRecords, int hotelId, String lastName) {
        return new ReservationSearch<>(hotelId, new ReservationSearchParameters(maxRecords, lastName, null), null);
    }

    public static ReservationSearch<ReservationSearchParameters> forConfirmationNumber(
        int maxRecords, int hotelId, String number) {
        return new ReservationSearch<>(hotelId, new ReservationSearchParameters(maxRecords, null, number), null);
    }

    public static ReservationSearch<ReservationSearchParameters> forReservationId(
            final int maxRecords,
            final int hotelId,
            final String reservationNumber) {
        ReservationSearch<ReservationSearchParameters> reservationSearchParametersReservationSearch = new ReservationSearch<>(
                hotelId,
                new ReservationSearchParameters(
                        maxRecords,
                        null,
                        null),
                Collections.singletonList(Long.valueOf(reservationNumber)));
        return reservationSearchParametersReservationSearch;
    }

    public int getHotelID() {
        return hotelID;
    }

    public String getLanguageId() {
        return languageId;
    }

    public T getParameters() {
        return parameters;
    }

    public List<Long> getReservationID() {
        return reservationID;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        final ReservationSearch that = (ReservationSearch) o;

        return new EqualsBuilder()
            .append(hotelID, that.hotelID)
            .append(languageId, that.languageId)
            .append(parameters, that.parameters)
            .append(reservationID, that.reservationID)
            .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37)
            .append(hotelID)
            .append(languageId)
            .append(parameters)
            .append(reservationID)
            .toHashCode();
    }

}

Параметры поиска бронирования:

public class ReservationSearchParameters {
    private final String travelerLastName;
    private final String confirmationNumber;
    private final int maxRecordsLimit;

    public ReservationSearchParameters(int maxRecordsLimit, String travelerLastName, String confirmationNumber) {
        this.maxRecordsLimit = maxRecordsLimit;
        this.travelerLastName = travelerLastName;
        this.confirmationNumber = confirmationNumber;
    }

    public String getTravelerLastName() { return travelerLastName; }

    public String getConfirmationNumber() { return confirmationNumber; }

    public int getMaxRecordsLimit() { return maxRecordsLimit; }

}

person fred    schedule 06.10.2017    source источник
comment
Это параметр, а не тело запроса. Вам нужно будет расширить его самостоятельно, если вы хотите что-то большее, чем toString().   -  person chrylis -cautiouslyoptimistic-    schedule 06.10.2017
comment
@chrylis Я думал, что, учитывая, что я использую JacksonEncoder, он будет закодирован за кулисами. Нет ли способа сделать это автоматически без использования расширителя?   -  person fred    schedule 06.10.2017
comment
Хорошо, как именно для параметра запроса? Преобразовать в JSON и URL-кодировать это? Как-то странно. Распаковать поля и обращаться с ними как с плоской картой? Возможные конфликты, неочевидные. Это не проблема для тела, но для параметра разумного значения по умолчанию не существует. Вам придется объяснить это Фейну самому.   -  person chrylis -cautiouslyoptimistic-    schedule 06.10.2017
comment
@chrylis Я думаю, что я действительно хочу сделать, это удалить аннотации @Body({reservationSearch}) и @Param(reservationSearch) из приведенного выше кода. Это должно запустить JacksonEncoder.   -  person fred    schedule 06.10.2017
comment
Замечу, что с точки зрения API-дизайна необычно отправлять параметры поиска как нечто помимо параметров запроса. Это, конечно, не запрещено, но нетипично.   -  person chrylis -cautiouslyoptimistic-    schedule 06.10.2017
comment
@chrylis Согласен, к сожалению, я не контролирую целевой API, и он предназначен для приема объекта reservationSearch в качестве тела POST ... В любом случае, благодаря вам я смог понять, что я делаю неправильно, ура.   -  person fred    schedule 06.10.2017


Ответы (1)


Параметры заголовка (@Headers и @HeaderMap) и шаблона тела (@Body) всегда считаются предварительно закодированными. Только параметры запроса (@QueryMap и @Param, которые ссылаются на параметр запроса) будут закодированы в URL.

Если вы хотите, чтобы ваш объект body был закодирован с помощью Encoder, не указывайте шаблон @Body и не аннотируйте параметр body с помощью @Param (он предназначен только для использования в параметрах шаблона). Затем неаннотированный параметр body будет передан в Encoder, указанный в вашей строке Feign.builder().encoder(new FooEncoder()).

person Shadow Man    schedule 05.04.2018