OffsetDateTime在GET方法中产生“没有找到类型为public javax.ws.rs.core.response的参数的注入源”

我有以下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类在参数(即param3param4 )中就会出现问题,但我一直无法找到原因。 此外,Swagger Codegen选择了OffsetDateTime,我不愿意改变它,看看每当我重新生成源时我将如何更改每个派生文件。

有没有人在使用REST服务和OffsetDateTime之前遇到过这个问题?

我发现的所有其他类似问题都与MultiPart Data和文件上传有关

这是相关的。 该错误是Jersey无法validation资源模型时出现的一般错误。 资源模型的一部分是方法参数。 泽西岛有一个系统,用于了解它将能够处理哪些参数以及哪些参数不会处理。 在您的情况下,它不知道如何处理OffsetDateTime

为了能够将非基本类型用作@QueryParam ,您需要遵循一套规则:

  1. 是一种原始类型
  2. 有一个接受单个String参数的构造函数
  3. 有一个名为valueOffromString的静态方法接受单个String参数(例如,参见Integer.valueOf(String)
  4. 有一个ParamConverterProvider JAX-RS扩展SPI的注册实现,它返回一个ParamConverter实例,该实例能够为该类型进行“from string”转换。
  5. Be ListSetSortedSet ,其中T满足上面的2,3或4。 生成的集合是只读的。

所以在这种OffsetDateTime情况下,沿着列表向下; 它不是原始的; 它没有String构造函数; 它没有静态valueOffromString

所以我们基本上剩下的选择是为它实现ParamConverter/ParamConverterProvider 。 基本设置看起来像

 @Provider public class OffsetDateTimeProvider implements ParamConverterProvider { @Override public  ParamConverter getConverter(Class clazz, Type type, Annotation[] annotations) { if (clazz.getName().equals(OffsetDateTime.class.getName())) { return new ParamConverter() { @SuppressWarnings("unchecked") @Override public T fromString(String value) { OffsetDateTime time = ... return (T) time; } @Override public String toString(T time) { return ...; } }; } return null; } } 

基本上,Jersey会向您传递查询参数的String值,并且创建它并返回它是您的工作。

然后只需在应用程序中注册OffsetDateTimeProvider 。 如果您正在使用包扫描,则应从@Provider注释中自动选取并注册。

我不使用Swagger,所以我不知道他们是否已经提供了已经实现的这样的东西,但是它们会为你生成这个并且没有办法让它工作似乎很奇怪。 我知道Jersey 3将支持Java 8,但谁知道什么时候会发布。