OffsetDateTime, приводящий к "Не найден источник внедрения для параметра типа public javax.ws.rs.core.response" в методе GET
У меня есть следующее 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
Модельный класс. У меня есть несколько других функций в этом классе, но всякий раз, когда я покидаю 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 ответ
Все остальные подобные вопросы, которые я нашел, были связаны с данными MultiPart и загрузкой файлов
Это связано. Ошибка является общей ошибкой, возникающей, когда Джерси не может проверить модель ресурса. Частью модели ресурса являются параметры метода. В Джерси есть система, позволяющая узнать, какие параметры он сможет обработать, а какие - нет. В вашем случае он не знает, как обрабатывать OffsetDateTime
,
Существует набор правил, которым вы должны следовать, чтобы иметь возможность использовать неосновные типы как @QueryParam
s:
- Будь примитивным типом
- Иметь конструктор, который принимает один аргумент String
- Иметь статический метод с именем
valueOf
или жеfromString
который принимает один аргумент String (см., например,Integer.valueOf(String)
) - Иметь зарегистрированную реализацию
ParamConverterProvider
SPI расширения JAX-RS, который возвращаетParamConverter
экземпляр, способный к преобразованию "из строки" для типа. - Быть
List<T>
,Set<T>
или жеSortedSet<T>
, гдеT
удовлетворяет 2, 3 или 4 выше. Полученная коллекция доступна только для чтения.
Так что в этом случае OffsetDateTime
спускаясь по списку; это не примитив; у него нет конструктора String; это не имеет статического 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;
}
}
В основном, Джерси передаст вам значение String параметра запроса, и ваша задача - создать его и вернуть.
Тогда просто зарегистрируйте OffsetDateTimeProvider
с приложением. Если вы используете сканирование пакетов, оно должно быть взято и зарегистрировано автоматически с @Provider
аннотаций.
Я не использую Swagger, поэтому я не знаю, предоставляют ли они уже что-то подобное, уже реализованное, но кажется странным, что они сгенерируют это для вас, и у них не будет способа заставить это работать. Я знаю, что у Jersey 3 будет поддержка Java 8 из коробки, но кто знает, когда, черт возьми, это будет выпущено.