【问题标题】:OffsetDateTime yielding "No injection source found for a parameter of type public javax.ws.rs.core.response" in GET methodOffsetDateTime 在 GET 方法中产生“没有为公共 javax.ws.rs.core.response 类型的参数找到注入源”
【发布时间】:2016-10-04 10:34:33
【问题描述】:

我有以下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)就会出现问题,但我一直无法找出原因。此外,OffsetDateTime 是由 Swagger Codegen 选择的,我不愿意更改它,因为我在重新生成源代码时必须更改每个派生文件。

以前有人在使用 REST 服务和 OffsetDateTime 时遇到过这个问题吗?

【问题讨论】:

    标签: java rest jax-rs swagger


    【解决方案1】:

    我发现的所有其他类似问题都与多部分数据和文件上传有关

    这是相关的。该错误是您在 Jersey 无法验证资源模型时遇到的一般错误。资源模型的一部分是方法参数。 Jersey 有一个系统可以知道哪些参数可以处理,哪些不能处理。在您的情况下,它不知道如何处理OffsetDateTime

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

    1. 成为原始类型
    2. 有一个接受单个 String 参数的构造函数
    3. 有一个名为 valueOffromString 的静态方法,它接受单个字符串参数(例如,请参阅 Integer.valueOf(String)
    4. 有一个ParamConverterProvider JAX-RS 扩展 SPI 的注册实现,它返回一个 ParamConverter 实例,该实例能够对该类型进行“来自字符串”的转换。
    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;
        }
    }
    

    Jersey 会将查询参数的字符串值传递给您,您的工作是创建并返回它。

    然后只需向应用程序注册OffsetDateTimeProvider。如果您使用的是包扫描,则应从 @Provider 注释中自动提取和注册。

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

    【讨论】:

      猜你喜欢
      • 2015-08-19
      • 1970-01-01
      • 2020-05-20
      • 1970-01-01
      相关资源
      最近更新 更多