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

use*_*710 10 java rest jax-rs swagger

我有以下GETREST方法:

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();
    }
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

我发现的所有其他类似问题都MultiPart Data与文件上传有关,而我正在提出一个简单的GET请求.其他也使用javax.ws.rs.code.Response该类的函数没有此问题,服务器正常启动.

我注意到只要OffsetDateTime类在参数(即param3param4)中就会出现问题,但我一直无法找到原因.此外,OffsetDateTime由Swagger Codegen选择,我不愿意改变它,看看每当我重新生成我的源时我将如何更改每个派生文件.

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

Pau*_*tha 15

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

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

您需要遵循一组规则才能将非基本类型用作@QueryParams(以及所有其他类型,@XxxParams例如@PathParam@FormParam等):

  1. 是一种原始类型
  2. 有一个接受单个String参数的构造函数
  3. 有一个名为valueOffromString接受单个String参数的静态方法(例如,参见Integer.valueOf(String))
  4. 有一个ParamConverterProviderJAX-RS扩展SPI 的注册实现,它返回一个ParamConverter能够为该类型进行"from string"转换的实例.
  5. List<T>,Set<T>或者SortedSet<T>,T满足2,3或4以上.生成的集合是只读的.

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

所以基本上,剩下的唯一选择是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Jersey会传递查询参数的String值,创建它并返回它是你的工作.

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

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