如何创建一个处理原始int的ParamConverter <integer>?

时间:2016-01-07 16:48:41

标签: java java-ee jax-rs

所以我想在jax-rs:

中创建自定义ParamConverter<Integer>
public class IntParamConverter implements ParamConverter<Integer>{

    @Override
    public Integer fromString(String value) {
        try{
            return Integer.valueOf(value);
        }catch (Exception e){
            //do some stuff
            throw new BadRequestEx("Convert Exception");
        }
    }
    @Override
    public String toString(Integer value) {
        return String.valueOf(value);
    }
}

然后我通过ParamConverterProvider注册它:

@Provider
public class CustomParamConverterHandler implements ParamConverterProvider {

        @Override
        public <T> ParamConverter<T> getConverter(final Class<T> rawType, Type genericType, Annotation[] annotations) {
            if (rawType.equals(Integer.class)){
                return (ParamConverter<T>) new IntParamConverter();
            }
            return null;
        }
    }

然后在资源POJO中使用它,如下所示:

    @GET
    @Path("/conv")
    @Produces({MediaType.TEXT_PLAIN})
    public String conv(@QueryParam("no") int no) {
        return ""+no;
    }

在运行时(使用system.out测试)我发现Tomee(Apache cfx?)不使用我的IntParamConverter。如果我声明@QueryParam("no") Integer no而不是@QueryParam("no") int no,那么一切正常(tomee使用我的自定义paramConverter。

我尝试使用原始int注册我的IntParamConverter

if (rawType.equals(int.class)){
     return (ParamConverter<T>) new IntParamConverter();
}

但随后会发生运行时异常:

java.lang.ClassCastException: Cannot cast java.lang.Integer to int
    at java.lang.Class.cast(Class.java:3369)
    at org.apache.cxf.jaxrs.utils.InjectionUtils.handleParameter(InjectionUtils.java:388)
    at org.apache.cxf.jaxrs.utils.InjectionUtils.createParameterObject(InjectionUtils.java:978)
    at org.apache.cxf.jaxrs.utils.JAXRSUtils.readQueryString(JAXRSUtils.java:1210)

如何创建这样一个处理原始int的ParamConverter?

2 个答案:

答案 0 :(得分:2)

你不能。

Java泛型在编译时都被转换为java.lang.Object(通过名为 type erasure 的进程)。

int这样的原始类型没有java.lang.Object作为基类,因此在这种情况下无法进行此类转换。

答案 1 :(得分:1)

我不肯肯定地说这是一个错误,但他们对InjectionUtils.handleParameter的实施很奇怪。他们有以下

// [...]
Object result = null;
try {
    result = createFromParameterHandler(value, pClass, genericType, paramAnns, message); 
} catch (IllegalArgumentException nfe) {
    throw createParamConversionException(pType, nfe);
}

ParamConveter获取价值。然后他们这样做

if (result != null) {
    return pClass.cast(result);
}
// [...]

显然,cast将被尝试并失败。但是没有理由像原始类型那样投射,反射的Method#invoke会照顾到这一点。换句话说,您可以(并且必须)将Integer值传递给Method#invoke,运行时将负责为您转换它。

如果他们想要进行额外的验证,他们可以先检查目标类型是否是基本类型,然后进行相应的验证(检查您的值是否属于相应的包装类型)。对于其他类型,它们可以回退到cast(因为方法返回类型是绑定到T的通用pClass)或使用类似isInstance的内容。

我不会与开发者一起打开一张票,但是如此高使用率的库应该能够做到这一点。

  

如何创建这样一个处理原始int的ParamConverter?

你不能。 ParamConverter是一个通用类,原语不适用于泛型。但是,图书馆应该支持为您进行最后的Integerint转换,但似乎它没有。