2.7.6. 将基于字符串的注解转换为对象


JAX-RS @*Param 注释,包括 @QueryParam@MatrixParam@HeaderParam 、@Path Param 和 @FormParam,以原始 HTTP 请求中的字符串表示。如果这些对象具有 valueOf(String) 静态方法或采用一个 String 参数的构造器,这些注入的参数可转换为对象。

如果您有一个类,其中 valueOf() 方法或字符串构造器不存在或不适合 HTTP 请求,JAX-RS 提供了 javax.ws.rs.ext.ParamConverterProviderjavax.ws.rs.ext.ParamConverter,以帮助将消息参数值转换为对应的自定义 Java 类型。ParamConverterProvider 必须在 JAX-RS 运行时以编程方式注册,并且必须标上 @Provider 注释,以便在提供程序扫描阶段由 JAX-RS 运行时自动发现。

例如:以下步骤演示了如何创建自定义 POJO 对象。从消息参数值(如 @QueryParam、@PathParam@MatrixParam@HeaderParam 转换为 POJO 对象的转换是通过实施 ParamConverter Provider 接口实现的。

  1. 创建自定义 POJO 类。

    public class POJO {
      private String name;
    
      public String getName() {
        return name;
      }
    
      public void setName(String name) {
        this.name = name;
      }
    }
  2. 创建自定义 POJO Converter 类。

    public class POJOConverter implements ParamConverter<POJO> {
      public POJO fromString(String str) {
        System.out.println("FROM STRNG: " + str);
        POJO pojo = new POJO();
        pojo.setName(str);
        return pojo;
      }
    
      public String toString(POJO value) {
        return value.getName();
      }
    }
  3. 创建自定义 POJO Converter Provider 类。

    public class POJOConverterProvider implements ParamConverterProvider {
      @Override
      public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
        if (!POJO.class.equals(rawType)) return null;
        return (ParamConverter<T>)new POJOConverter();
      }
    }
  4. 创建自定义 MyResource 类。

    @Path("/")
    public class MyResource {
      @Path("{pojo}")
      @PUT
      public void put(@QueryParam("pojo") POJO q, @PathParam("pojo") POJO pp, @MatrixParam("pojo") POJO mp,
        @HeaderParam("pojo") POJO hp) {
        ...
      }
    }
扩展 ParamConverter 的功能

在 JAX-RS 语义中,ParamConverter 转换代表单个对象的单个字符串。RESTEasy 扩展语义,以允许 ParamConverter 解析多个对象的字符串表示,并生成 List<T>Set<T>、Sorted Set<T>、 数组 或任何其他多值数据结构。

例如,请考虑以下资源:

@Path("queryParam")
public static class TestResource {
   @GET
   @Path("")
   public Response conversion(@QueryParam("q") List<String> list) {
      return Response.ok(stringify(list)).build();
   }
}

private static <T> String stringify(List<T> list) {
   StringBuffer sb = new StringBuffer();
   for (T s : list) {
      sb.append(s).append(',');
   }
   return sb.toString();
}

按照如下所示调用 TestResource,使用标准表示法:

@Test
public void testQueryParamStandard() throws Exception {
   ResteasyClient client = new ResteasyClientBuilder().build();
   Invocation.Builder request = client.target("http://localhost:8081/queryParam?q=20161217&q=20161218&q=20161219").request();
   Response response = request.get();
   System.out.println("response: " + response.readEntity(String.class));
}

结果结果 :20161217,20161218,20161219.

如果要使用用逗号分开的表示法,您可以添加:

public static class MultiValuedParamConverterProvider implements ParamConverterProvider
   @SuppressWarnings("unchecked")
   @Override
   public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
      if (List.class.isAssignableFrom(rawType)) {
         return (ParamConverter<T>) new MultiValuedParamConverter();
      }
      return null;
   }
}

public static class MultiValuedParamConverter implements ParamConverter<List<?>> {
   @Override
   public List<?> fromString(String param) {
      if (param == null || param.trim().isEmpty()) {
         return null;
      }
      return parse(param.split(","));
   }

   @Override
   public String toString(List<?> list) {
      if (list == null || list.isEmpty()) {
         return null;
      }
      return stringify(list);
   }

   private static List<String> parse(String[] params) {
      List<String> list = new ArrayList<String>();
      for (String param : params) {
         list.add(param);
      }
      return list;
   }
}

现在,您可以按如下方式调用 TestResource:

@Test
public void testQueryParamCustom() throws Exception {
   ResteasyClient client = new ResteasyClientBuilder().build();
   Invocation.Builder request = client.target("http://localhost:8081/queryParam?q=20161217,20161218,20161219").request();
   Response response = request.get();
   System.out.println("response: " + response.readEntity(String.class));
}

获得 回复:20161217,20161218,20161219.

在本例中,MultiValuedParamConverter.fromString() 函数会创建并返回 aArrayList,以便可以重写 TestResource.conversion() 功能:

@Path("queryParam")
public static class TestResource {

   @GET
   @Path("")
   public Response conversion(@QueryParam("q") ArrayList<String> list) {
      return Response.ok(stringify(list)).build();
   }
}

另外,还可重写 MultiValuedParamConverter 以返回 LinkListTestResource.conversion()中的 参数列表可以是 ListLinkedList

最后,请注意,此扩展也适用于数组。例如,

public static class Foo {
    private String foo;
    public Foo(String foo) {
        this.foo = foo;
    }
    public String getFoo() {
        return foo;
    }
}

public static class FooArrayParamConverter implements ParamConverter < Foo[] > {
    @Override
    public Foo[] fromString(String value) {
        String[] ss = value.split(",");
        Foo[] fs = new Foo[ss.length];
        int i = 0;
        for (String s: ss) {
            fs[i++] = new Foo(s);
        }
        return fs;
    }

    @Override
    public String toString(Foo[] values) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < values.length; i++) {
            sb.append(values[i].getFoo()).append(",");
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }
}

@Provider
public static class FooArrayParamConverterProvider implements ParamConverterProvider {
    @SuppressWarnings("unchecked")
    @Override
    public < T > ParamConverter < T > getConverter(Class < T > rawType, Type genericType, Annotation[] annotations) {
        if (rawType.equals(Foo[].class));
        return (ParamConverter < T > ) new FooArrayParamConverter();
    }
}

@Path("")
public static class ParamConverterResource {

    @GET
    @Path("test")
    public Response test(@QueryParam("foos") Foo[] foos) {
        return Response.ok(new FooArrayParamConverter().toString(foos)).build();
    }
}
java.util.Optional Parameter Types

RESTEasy 提供了多种额外的 java.util.Optional 参数类型。这些参数类型充当打包程序对象类型。它们允许用户输入可选类型参数,并使用 Optional.orElse() 等方法取消所有 null 检查。

@Path("/double")
@GET
public String optDouble(@QueryParam("value") OptionalDouble value) {
    return Double.toString(value.orElse(4242.0));
}

上例演示了 OptionalDouble 可用作参数类型。如果 @QueryParam 中未提供值,则将返回默认值。以下参数类型支持可选参数:

  • @QueryParam
  • @MatrixParam
  • @FormParam
  • @HeaderParam
  • @CookieParam
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.