我有以下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
)就会出现问题,但我一直无法找到原因。此外,Swagger Codegen选择了OffsetDateTime
,我不愿意改变它,看看每当我重新生成我的源时我将如何更改每个派生文件。
有没有人在使用REST服务和OffsetDateTime
之前遇到此问题?
答案 0 :(得分:10)
我发现的所有其他类似问题都与MultiPart数据和文件上传有关
它有关系。当Jersey无法验证资源模型时,错误是您遇到的一般错误。资源模型的一部分是方法参数。泽西岛有一个系统,可以知道它将能够处理哪些参数以及它赢得了哪些参数。在您的情况下,它不知道如何处理OffsetDateTime
。
您需要遵循一系列规则才能将非基本类型用作@QueryParam
s(以及所有其他@XxxParams
,例如@PathParam
和{{1等等。):
@FormParam
参数的构造函数String
或valueOf
的静态方法接受单个String参数(例如,参见fromString
)Integer.valueOf(String)
JAX-RS扩展SPI的注册实现,该实现返回一个ParamConverterProvider
实例,该实例能够从字符串""转换类型。ParamConverter
,List<T>
或Set<T>
,其中SortedSet<T>
满足上述2,3或4。生成的集合是只读的。所以在这个T
的情况下,在列表中;它不是原始的;它没有String构造函数;它没有静态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;
}
}
即可。如果您正在使用包裹扫描,则应从OffsetDateTimeProvider
注释中自动提取并注册。
我没有使用Swagger,所以我不知道他们是否已经提供了已经实现过的这样的东西,但是他们会为你生成这个并且没有办法制作它似乎很奇怪工作。我知道泽西3队将获得Java 8支持,但谁知道什么时候会被释放。