Java 将bean属性的子集公开为REST服务的XML响应
我不知道如何最好地解释这一点,所以这可能有点长,请容忍我 假设我有一个具有一系列属性的java bean:Java 将bean属性的子集公开为REST服务的XML响应,java,web-services,rest,xml-serialization,Java,Web Services,Rest,Xml Serialization,我不知道如何最好地解释这一点,所以这可能有点长,请容忍我 假设我有一个具有一系列属性的java bean: public interface Customer { public String getFirstName(); public String getLastName(); public Address getAddress(); // embedded bean with its own properties ... // lots more } 显然,
public interface Customer {
public String getFirstName();
public String getLastName();
public Address getAddress(); // embedded bean with its own properties
... // lots more
}
显然,有一个相应的实现,另外还定义了适当的setter(尽管setter可能不会在某些属性的接口中公开)
有一个服务(POJO接口+实现)定义了可以对客户执行的一系列操作(CRUD、一些find()查询等)。服务是通过Spring引导的,整个过程在本地和通过RMI运行良好
现在我有了一个客户端(iPhone应用程序),它需要访问通过上述API公开的功能的小子集,包括服务操作和API属性。其想法是通过REST样式的API公开此子集:
GET /services/customers/1234
返回
<customer>
<firstName>Homer</firstName>
<lastName>Simpson</lastName>
<city>Springfield</city>
</customer>
荷马
辛普森
斯普林菲尔德
甚至可能
<customer firstName="Homer" lastName="Simpson" city="Springfield" />
问题是——我该怎么做?我(简要地)研究了JAXB/CXF/Jersey,看起来我必须定义一个模式,基于它生成一组类,并将数据从API实体复制到这些类。有没有办法避免这些
理想情况下,我希望在API实体中注释适当的属性,并让它们(并且只有它们)自动编组。如果需要,我可以为web服务端点编写专用接口/实现;注释现有的一个会更好
另一个(更紧迫的)问题是——我在做什么蠢事吗?有没有更简单和/或更好的方法?
我上一次使用web服务是Axis1.1倍,上一次使用iPhone是:-),所以任何指针都将非常感谢
更新:澄清一下-我正在寻找最简单的方法将javabean属性的子集打包成XML(或者可能是JSON?),而无需编写/生成额外的类来表示所述属性子集。上面的例子过于简单,实际上API非常广泛,涉及很多类。如果可能的话,我真的希望避免重复。谷歌搜索似乎表明,在JAXB中使用接口是一件痛苦的事情,这一点和另一点都可以看出
如果您的POJO是一个类而不是一个接口,那么它可能更容易实现。我将(另一个JAX-RS实现)用于JAXB,我只需要用@XmlRootElement注释我的POJO类。另一方面,我已经编写了自定义http客户机代码,以便使用JAXB对同一个带注释的类进行marshall/unmarshall(如果可以使用的话,将是automagic with RESTEasy客户机代理框架)。注意,我没有定义模式,但是我可以做很多事情,因为我可以控制RESTfulWeb服务的两个方面
泽西有一个你可能想看看的地方。CXF还有一个类似于RESTEasy的基于代理的机制
看一看RESTful Java with JAX-RS手册,它涵盖了我发现有帮助的以下内容:
- 休息服务概念
- 各种实现的概述,包括客户端API支持
- 代码示例
@GET
@Produces( { MediaType.APPLICATION_XML })
@Path("/customers/{id}")
public Customer getCustomer(@PathParam("id") int id) {
...
return customer;
}
POJO示例:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
Address address;
String name;
// annotate with XmlTransient to prevent mapping this property/type to XML
@XmlTransient
String ssn;
...
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Address {
String planet;
...
}
我的首选是使用JAXB注释对您已有的类进行注释,并让绑定编译器通过对注释的源文件运行
schemagen
来基于您已有的类创建模式
我发现JAXB在从java类创建模式以及从模式创建java类时非常有用且相对容易使用,我在创建用于服务工作中的保险单的web服务时使用这些模式。最简单的方法是:使用XML序列化API,如XStream或Simple,这些都是针对您所问的这种从POJO到XML的问题而设计的。选择子集并切换到属性很容易,如下所示:
class Customer {
@XStreamAsAttribute
String firstName;
@XStreamAsAttribute
String lastName;
@XStreamOmitField
Address address();
}
XStream是一个序列化库,我已经在使用它了。它没有提供一种可行的数据绑定方法——例如,字段和getter可能不完全匹配。另外,即使它可以被改编成数据封送器,这仍然只是问题的一部分,而不是一个整体解决方案。我同意XStream只是一个序列化库,没有办法使用接口而不是POJO,但这是一种更干净的方式(既然你在后台有它们,为什么不使用它们呢?)。您描述的问题不需要数据绑定,因为它是一种单向转换(或者我不明白为什么在支持重命名和省略字段时应该采用更复杂的方法),接口只是一个API外观;这与此无关。XStream的问题是无法将其用于bean编组。换句话说,如果我有一个
getSomething()
方法,它不是一个真正的访问器(例如,它没有相应的this.something
字段,但返回一些计算值),那么我就不走运了-序列化非常好,封送不太好。谢谢你的回答。我有实际的bean类;接口是用来保持一个干净的独立API的,仅此而已。我在看RESTEasy,但它似乎与CXF/Jersey没有本质区别;它们似乎都使用JAXB进行编组,我看不出如何跳过为其创建(生成)XML模式和映射类的过渡步骤,它们是JAX-RS实现的不同风格。我没有定义XML模式,即使通过创建JAXB封送器/封送器的自定义客户机代码来处理POJO也没有问题。我已经用代码示例更新了答案。注意,action方法返回POJO,这是RESTEasy提供的处理JAXB注释的POJO w的自动逻辑(对于其他实现可能相同)/