经过一番搜索,我很快就发现基本上有两个选择:
选项1
您可以传递一个包含所有其他参数的“包装对象”到服务中。您可能需要使用JAXB注释(如@XmlRootElement)对此包装类进行注释,以便它能够与基于Jettison的提供程序一起使用,但如果您使用的是Jackson,则不需要这样做。只需将内容类型设置为正确的类型,正确的消息正文阅读器就会被调用。
当然,这仅适用于POST类型的服务(据我所知)。
示例
这只是将原始问题中提到的服务转换为使用包装对象的示例。
@Service("myService")
class RestService {
@POST
@Produces("application/json")
@Path("/fooBar")
public Result fooBar(
@FormParam("") FooBarParamsWrapper wrapper
) throws WebServiceException {
doSomething(wrapper.foo);
}
}
class ParamsWrapper {
double foo, bar;
MyComplexObject object;
}
选项2
您可以提供一些特殊的字符串格式,将对象打包到其中,然后在类中实现一个构造函数,需要接受一个字符串,或者一个静态的valueOf(String s)方法或一个静态的fromString(String s)方法,以从该字符串创建一个对象。或者创建一个执行完全相同操作的ParameterHandler。
据我所知,只有第二种方法才能让您使用JSONP从浏览器调用服务(因为JSONP是限制为GET的技巧)。 我选择这条路线是为了能够在URI中传递复杂对象的数组。
以下是如何使用此方法的示例域类和服务:
示例
@GET
@Path("myService")
public void myService(@QueryParam("a") MyClass [] myVals) {
}
class MyClass {
public int foo;
public int bar;
public static MyClass fromString(String jsonRepresentation) {
ObjectMapper mapper = new ObjectMapper();
MyClass o= null;
try {
o = mapper.readValue(jsonRepresentation, MyClass.class );
} catch (IOException e) {
throw new WebApplicationException()
}
return o;
}
}
一个URI http://my-server.com/myService?a={"foo":1, "bar":2}&a={"foo":100, "bar":200}
在这种情况下将被反序列化为由两个MyClass对象组成的数组。
2019年评论:
看到这个答案在2019年仍然有一些点击,我觉得我应该发表评论。事后来看,我不会推荐选项2,因为通过这些步骤只是为了能够进行GET调用而增加了复杂性,这可能并不值得。如果您的服务接受如此复杂的输入,由于输入的排列方式过多,您可能无法利用客户端缓存。我会配置服务器上的适当跨源共享(CORS)头并POST输入。然后专注于在服务器上缓存任何可缓存的内容。