2.7.6. 将基于字符串的注解转换为对象
JAX-RS @*Param
注释,包括 @QueryParam
、@MatrixParam
、@HeaderParam
、@Path
Param 和 @FormParam
,以原始 HTTP 请求中的字符串表示。如果这些对象具有 valueOf(String)
静态方法或采用一个 String
参数的构造器,这些注入的参数可转换为对象。
如果您有一个类,其中 valueOf()
方法或字符串构造器不存在或不适合 HTTP 请求,JAX-RS 提供了 javax.ws.rs.ext.ParamConverterProvider
和 javax.ws.rs.ext.ParamConverter
,以帮助将消息参数值转换为对应的自定义 Java 类型。ParamConverterProvider
必须在 JAX-RS 运行时以编程方式注册,并且必须标上 @Provider
注释,以便在提供程序扫描阶段由 JAX-RS 运行时自动发现。
例如:以下步骤演示了如何创建自定义 POJO 对象。从消息参数值(如 @QueryParam
、@PathParam
、@MatrixParam
、@HeaderParam
转换为 POJO 对象的转换是通过实施
接口实现的。
ParamConverter
Provider
创建自定义 POJO 类。
public class POJO { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
创建自定义 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(); } }
创建自定义 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(); } }
创建自定义 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
以返回 LinkList
,TestResource.conversion()中的
参数列表可以是 List
或 LinkedList
。
最后,请注意,此扩展也适用于数组。例如,
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