Результат OffsetDateTime «Источник инъекции не найден для параметра типа public javax.ws.rs.core.response» в методе GET

#java #rest #jax-rs #swagger

#java #rest #jax-rs #развязность

Вопрос:

У меня есть следующий GET метод REST:

 import java.time.OffsetDateTime;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import com.product.rest.api.TransactionsApi;
import com.product.rest.model.Transaction;

@Path("/transactions")

@Api(description = "the transactions API")
@Consumes({ "application/json" })
@Produces({ "application/json" })
public class TransactionsApiImpl extends TransactionsApi {

    @GET

    @Consumes({ "application/json" })
    @Produces({ "application/json" })
    @ApiOperation(value = "", notes = "Get all transactions", response =     Transaction.class, responseContainer = "List", tags = {})
    @ApiResponses(
        value = { @ApiResponse(code = 200, message = "OK", response =     Transaction.class, responseContainer = "List"),
            @ApiResponse(code = 400, message = "Bad Request", response =     Transaction.class, responseContainer = "List"),
            @ApiResponse(code = 404, message = "Not Found", response =     Transaction.class, responseContainer = "List"),
            @ApiResponse(code = 500, message = "Internal Server Error",     response = Transaction.class, responseContainer = "List") })
    @Override
    public Response transactionsGet(
        @HeaderParam("tok") String tok,
        @QueryParam("param1") Integer param1,
        @QueryParam("param2") String param2,
        @QueryParam("param3") OffsetDateTime param3,
        @QueryParam("param4") OffsetDateTime param4,
        @QueryParam("param5") Integer param5,
        @QueryParam("param6") Integer param6,
        @QueryParam("param7") String param7) {
        return Response.ok().entity("Success!").build();
    }
  

Это TransactionsApi сгенерированная реализация с использованием Swagger Codegen, как Transaction и класс model . У меня есть несколько других функций в этом классе, но всякий раз, когда я оставляю GET /transactions функцию без комментариев, я получаю следующую ошибку:

 WARN [Thread-1] (ContextHandler.java:2175) - unavailable
org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.

[[FATAL] No injection source found for a parameter of type public javax.ws.rs.core.Response     
com.product.rest.impl.v1.TransactionsApiImpl.transactionsGet(java.lang.String,java.lang.Integer,java.lang.String,java.time.OffsetDateTime,java.time.OffsetDateTime,java.lang.Integer,java.lang.Integer,java.lang.String) at index 3.; source='ResourceMethod{httpMethod=GET, consumedTypes=[application/json], producedTypes=[application/json], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class com.product.rest.impl.v1.TransactionsApiImpl, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor@7df78e88]}, definitionMethod=public javax.ws.rs.core.Response
  

Все другие подобные вопросы, которые я нашел, были связаны с MultiPart Data загрузкой и загрузкой файлов, тогда как я делаю простой GET запрос. Другие функции, которые также используют javax.ws.rs.code.Response класс, не имеют этой проблемы, и сервер запускается нормально.

Я заметил, что проблема возникает всякий OffsetDateTime раз, когда класс находится в параметрах (т. Е. param3 И param4 ), Но я не смог выяснить, почему. Более того, OffsetDateTime был выбран Swagger Codegen, и я неохотно его меняю, видя, как мне придется впоследствии изменять каждый производный файл всякий раз, когда я восстанавливаю свои исходники.

У кого-нибудь раньше была эта проблема со службами REST и OffsetDateTime ?

Ответ №1:

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

Это связано. Ошибка — это общая ошибка, которую вы получаете, когда Джерси не может проверить модель ресурсов. Частью модели ресурсов являются параметры метода. В Джерси есть система, позволяющая узнать, какие параметры он сможет обрабатывать, а какие нет. В вашем случае он не знает, как обработать OffsetDateTime .

Существует набор правил, которым вам необходимо следовать, чтобы иметь возможность использовать неосновные типы как @QueryParam s (и все другие @XxxParams , такие как @PathParam и @FormParam и т.д.):

  1. Быть примитивным типом
  2. Есть конструктор, который принимает один String аргумент
  3. Есть статический метод с именем valueOf или fromString , который принимает один строковый аргумент (см., Например, Integer.valueOf(String) )
  4. Есть зарегистрированная реализация ParamConverterProvider SPI расширения JAX-RS, которая возвращает ParamConverter экземпляр, способный к преобразованию «из строки» для типа.
  5. Быть List<T> , Set<T> или SortedSet<T> , где T удовлетворяет 2, 3 или 4 выше. Результирующая коллекция доступна только для чтения.

Итак, в этом случае OffsetDateTime , переходя по списку; это не примитив; у него нет строкового конструктора; у него нет статического valueOf или fromString

Таким образом, в принципе, единственный оставшийся вариант — реализовать ParamConverter/ParamConverterProvider для него. Базовая настройка выглядит следующим образом

 @Provider
public class OffsetDateTimeProvider implements ParamConverterProvider {

    @Override
    public <T> ParamConverter<T> getConverter(Class<T> clazz, Type type, Annotation[] annotations) {
        if (clazz.getName().equals(OffsetDateTime.class.getName())) {

            return new ParamConverter<T>() {

                @SuppressWarnings("unchecked")
                @Override
                public T fromString(String value) {
                    OffsetDateTime time = ...
                    return (T) time;
                }

                @Override
                public String toString(T time) {
                    return ...;
                }
            };
        }
        return null;
    }
}
  

Jersey передаст вам строковое значение параметра запроса, и ваша задача — создать его и вернуть.

Затем просто зарегистрируйте OffsetDateTimeProvider его в приложении. Если вы используете сканирование пакетов, он должен быть выбран и зарегистрирован автоматически из @Provider аннотации.

Я не использую Swagger, поэтому я не знаю, предоставляют ли они что-то подобное уже реализованному, но кажется странным, что они сгенерируют это для вас, и у них нет способа заставить это работать. Я знаю, что Джерси 3 будет иметь поддержку Java 8 из коробки, но кто знает, когда, черт возьми, это будет выпущено.

Комментарии:

1. Примечание: вопрос и ответ относятся к Джерси 2 (JAX-RS 2). ParamConverter и ParamConverterProvider недоступны в Джерси 1, если по какой-либо причине вы используете Джерси 1 и не можете обновиться.