【问题标题】:Incorrect parameter type on DateTimeDateTime 上的参数类型不正确
【发布时间】:2017-07-12 15:43:26
【问题描述】:

Intellij 告诉我 updateTime 的参数类型不正确。我不熟悉这个错误和@EnumDateFormat。

    @DELETE
    @Path("groups/{groupId}/samples/{testYear}")
    @Produces(MediaType.APPLICATION_JSON)
    @RolesAllowed({Profile.MP_USER_ROLE})
    public Response deleteGroupSamples (@PathParam("groupId") Long groupId, @PathParam("testYear") Long testYear, @QueryParam("updateTime") @EnumDateFormat( FormatEnum.WITH_HHMMSS ) DateTime updateTime, TreatmentGroupTest sample) throws ValidationException{
        manager.deleteGroupSample( this.getUser(), sample.getTestSampleId(), updateTime );
        ResponseBuilder builder=null;
        builder = Response.ok(  );
        return builder.build();
    }

错误还提示:

检查@PathParam、@QueryParam等参数的类型。注解的参数、字段或属性的类型必须是

  1. 成为原始类型

  2. 有一个接受单个字符串参数的构造函数

  3. 有一个名为 valueOf 或 formString 的静态方法,它接受单个 String 参数(例如,参见 Integer.valueOf(String))

  4. 有一个 ParamConverterProvider JAX-RS 扩展 SPI 的注册实现,它返回一个 ParamConverter 实例,该实例能够进行该类型的“表单字符串”转换

  5. 是 List、Set 或 SortedSet,其中 T 满足上述 2、3 或 4。生成的集合是只读的

【问题讨论】:

  • 好吧,数字 1 和 5 不适用于 DateTime,因此请检查其余部分。我认为没有 valueOf 方法或带有字符串的构造函数,所以留下数字 4
  • @cricket_007 不知道这是什么意思,但感谢您的建议!
  • 您引用的“建议”。阅读它们?你知道“原始”是什么意思或valueOf 指的是什么吗?基本上,问题在于DateTime 可以是任何格式,而JAX-RS 无法为您处理。将纯字符串发送到必须与预期日期格式匹配的端点(hh:mm:ss) 对您来说更有意义
  • 是的,我读过它们并且知道原始和 valueOf 是什么意思哈哈。错误建议 4 是我完全迷失的那个。但是你的解释更通俗易懂,所以我理解。

标签: java datetime jax-rs


【解决方案1】:

我想这是一个老问题,但是对于LocalDate,您必须注册一个ParamConverterProvider 的实现,它返回一个ParamConverter 实例,该实例能够从String 创建一个LocalDate。

如果您查看ParamConverter 的javadoc,您会看到有两种方法:E fromString(String value) 和String toString(E value)。 此外,如果您查看ParamConverterProvider 的文档,您会注意到它具有以下方法:<T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation annotations[])。

基本上,您必须创建一个ParamConverter<LocalDate> 的实现,它可以从String 创建一个LocalDate,然后从注册的ParamConverterProvider 返回该实现的一个实例。

这是一个例子:

package com.example;

import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.Provider;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Optional;

/**
 * The {@link ParamConverterProvider} for {@link java.time} package classes
 * (i.e {@link LocalDate}, {@link LocalTime} and {@link LocalDateTime}).
 */
@Provider
public class Java8TimeParamConverterProvider implements ParamConverterProvider {

    /**
     * Contains a {@link DateTimeFormatter} whose pattern is "yyyy-MM-dd".
     */
    public static final DateTimeFormatter CLASSIC_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");


    @Override
    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
        if (rawType == LocalDate.class) {
            //noinspection unchecked
            return (ParamConverter<T>) new Java8LocalDateClassicFormatParamConverter();
        }
        if (rawType == LocalTime.class) {
            return null; // TODO: implement
        }
        if (rawType == LocalDateTime.class) {
            return null; // TODO: implement
        }
        return null;
    }

    /**
     * The {@link ParamConverter} for {@link LocalDate} using the {@link Formatters#CLASSIC_DATE_FORMATTER}.
     */
    private static class Java8LocalDateClassicFormatParamConverter implements ParamConverter<LocalDate> {

        @Override
        public LocalDate fromString(String value) {
            return Optional.ofNullable(value)
                    .map(Formatters.CLASSIC_DATE_FORMATTER::parse)
                    .map(LocalDate::from)
                    .orElse(null);
        }

        @Override
        public String toString(LocalDate value) {
            return Formatters.CLASSIC_DATE_FORMATTER.format(value);
        }
    }
}

您必须注册此提供程序。在您的 ResourceConfig 中,您必须包含以下内容:

public class AppConfig extends ResourceConfig {

    public AppConfig() {
        register(Java8TimeParamConverterProvider.class);
    }
}

或者,如果您正在扫描包裹:

public class AppConfig extends ResourceConfig {

    public AppConfig() {
        packages("com.example");
    }
}

(这就是@Providerannotation 包含在Java8TimeParamConverterProviderclass 定义中的原因)。请注意,如果您使用的是 spring boot,这将不起作用,因为此时 spring boot 插件创建的最终 jar 存在问题。

注册您的提供商的另一种方法是通过web.xml。在这种情况下,您必须包括以下内容:

<servlet>
    <servlet-name>jersey-servlet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>

    <!-- Include the following init-param if you want to do package scanning -->
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>
            com.example
        </param-value>
    </init-param>
    <!-- Or use the following init-param if you want to do class register -->
    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>com.example.Java8TimeParamConverterProvider</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

希望对你有帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2022-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    • 2021-10-22
    相关资源
    最近更新 更多