GET 方法中产生 "No injection source found for a parameter of type public javax.ws.rs.core.response" 的 OffsetDateTime
OffsetDateTime yielding "No injection source found for a parameter of type public javax.ws.rs.core.response" in GET method
我有以下 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
模型 class 也是如此。我在这个 class 中还有其他几个函数,但是每当我不注释 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
class 的函数没有这个问题,服务器正常启动。
我注意到只要 OffsetDateTime
class 在参数中(即 param3
和 param4
)就会出现问题,但我一直找不到出为什么。此外,OffsetDateTime
是由 Swagger Codegen 选择的,我不愿意更改它,因为我看到每当我重新生成我的源时我将不得不更改每个派生文件。
有没有人在使用 REST 服务和 OffsetDateTime
之前遇到过这个问题?
All other similar questions I have found had to do with MultiPart Data and file uploading
有关系。该错误是 Jersey 无法验证资源模型时出现的一般错误。资源模型的一部分是方法参数。 Jersey 有一个系统可以知道哪些参数可以处理,哪些不能处理。在您的情况下,它不知道如何处理 OffsetDateTime
.
为了能够将非基本类型用作 @QueryParam
(以及所有其他 @XxxParams
,例如 @PathParam
和 @FormParam
, 等等):
- 成为原始类型
- 有一个接受单个
String
参数的构造函数
- 有一个名为
valueOf
或 fromString
的静态方法,它接受一个字符串参数(例如,参见 Integer.valueOf(String)
)
- 有一个
ParamConverterProvider
JAX-RS 扩展 SPI 的注册实现,return 是一个 ParamConverter
实例,能够对类型进行 "from string" 转换。
- 为
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;
}
}
Jersey 会将查询参数的字符串值传递给您,您的工作就是创建它并 return 它。
然后只需在应用程序中注册 OffsetDateTimeProvider
。如果您使用包裹扫描,它应该从 @Provider
注释中自动提取和注册。
我不使用 Swagger,所以我不知道他们是否已经提供了已经实现的类似功能,但他们会为您生成它,但没有办法让它工作,这似乎很奇怪。我知道 Jersey 3 将有 Java 8 个开箱即用的支持,但谁知道什么时候会发布。
我有以下 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
模型 class 也是如此。我在这个 class 中还有其他几个函数,但是每当我不注释 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
class 的函数没有这个问题,服务器正常启动。
我注意到只要 OffsetDateTime
class 在参数中(即 param3
和 param4
)就会出现问题,但我一直找不到出为什么。此外,OffsetDateTime
是由 Swagger Codegen 选择的,我不愿意更改它,因为我看到每当我重新生成我的源时我将不得不更改每个派生文件。
有没有人在使用 REST 服务和 OffsetDateTime
之前遇到过这个问题?
All other similar questions I have found had to do with MultiPart Data and file uploading
有关系。该错误是 Jersey 无法验证资源模型时出现的一般错误。资源模型的一部分是方法参数。 Jersey 有一个系统可以知道哪些参数可以处理,哪些不能处理。在您的情况下,它不知道如何处理 OffsetDateTime
.
为了能够将非基本类型用作 @QueryParam
(以及所有其他 @XxxParams
,例如 @PathParam
和 @FormParam
, 等等):
- 成为原始类型
- 有一个接受单个
String
参数的构造函数 - 有一个名为
valueOf
或fromString
的静态方法,它接受一个字符串参数(例如,参见Integer.valueOf(String)
) - 有一个
ParamConverterProvider
JAX-RS 扩展 SPI 的注册实现,return 是一个ParamConverter
实例,能够对类型进行 "from string" 转换。 - 为
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;
}
}
Jersey 会将查询参数的字符串值传递给您,您的工作就是创建它并 return 它。
然后只需在应用程序中注册 OffsetDateTimeProvider
。如果您使用包裹扫描,它应该从 @Provider
注释中自动提取和注册。
我不使用 Swagger,所以我不知道他们是否已经提供了已经实现的类似功能,但他们会为您生成它,但没有办法让它工作,这似乎很奇怪。我知道 Jersey 3 将有 Java 8 个开箱即用的支持,但谁知道什么时候会发布。