JAXB用于为JSON或XML自然返回的列表

我正在使用MOXy和Jersey实现一个RESTful API,并希望自然地为JSON和XML返回列表,我的意思是XML包含整个集合的元素标记以及集合项,而JSON包含仅用于集合的标记。

例如,我想返回一个“组织”资源,其中包含设施和位置的嵌套列表。 作为XML:

 1 XYZ   1 Telephone   3 Whiteboard     1 REGION London   2 REGION Manchester    

而作为JSON:

 { "id": 1, "name": "XYZ", "facilities": [ { "id": 1, "text": "Telephone" }, { "id": 3, "text": "Whiteboard" } ], "locations": [ { "id": 1, "kind": "REGION", "name": "London" }, { "id": 2, "kind": "REGION", "name": "Manchester" } ] } 

不幸的是,我似乎无法获得允许我为XML和JSON返回这样的输出的代码库。 如果我使用一个类来包装嵌套列表,那么XML看起来是正确的但不是JSON(参见下面的“ExternalFacilities”)。 如果我将嵌套列表定义为ArrayList子类,则JSON显示正确但不是XML(请参阅下面的“ExternalLocations”)。

XML示例显示“设施”列表正确但不是“位置”

看到没有包含“位置”列表的XML元素(就像“设施”一样),并且每个位置都有一个复数元素名称。

  1 XYZ   1 Telephone   3 Whiteboard    1 REGION London   2 REGION Manchester   

JSON示例显示“位置”列表正确但不是“设施”

看到“facility”列表是一个包含JSON数组的JSON对象,而我只想要JSON数组(带有复数元素名称)。

 { "id": 1, "name": "XYZ", "facilities": { "facility": [ { "id": 1, "text": "Telephone" }, { "id": 3, "text": "Whiteboard" } ] }, "locations": [ { "id": 1, "kind": "REGION", "name": "London" }, { "id": 2, "kind": "REGION", "name": "Manchester" } ] } 

上面的示例使用相同的代码生成,只需更改Accept HTTP标头以使Jersey返回JSON而不是XML。 以下是课程的摘录:

ExternalOrganisation.java

 @XmlRootElement(name="organisation") @XmlAccessorType(XmlAccessType.FIELD) public class ExternalOrganisation { private String name; private ExternalFacilities facilities; private ExternalLocations locations; ... } 

ExternalFacilities.java

 @XmlRootElement(name="facilities") public class ExternalFacilities { @XmlElementRef private List list; ... } 

ExternalLocations.java

 @XmlRootElement(name="locations") public class ExternalLocations extends ArrayList { ... } 

ExternalFacility.java

 @XmlRootElement(name="facility") @XmlType(propOrder={"id", "uri", "kind", "text"}) public class ExternalFacility extends ExternalBase { // id inherited private String text; .... } 

ExternalLocation.java

 @XmlRootElement(name="location") @XmlType(propOrder={"id", "kind", "name"}) public class ExternalLocation extends ExternalBase { // id inherited @XmlElement private LocationKind kind; @XmlElement private String name; ... } 

似乎最初类似于这个问题,但我不是试图混合我的列表中的对象类型。

您可以执行以下操作以获取所需的XML和JSON表示forms:

第一步 – 利用@XMLElementWrapper

代替:

 @XmlRootElement(name="organisation") @XmlAccessorType(XmlAccessType.FIELD) public class ExternalOrganisation { private String name; private ExternalFacilities facilities; private ExternalLocations locations; ... } 

您可以使用@XmlElementWrapper执行以下操作(请参阅: http : //blog.bdoughan.com/2010/09/jaxb-collection-properties.html ):

 @XmlRootElement(name="organisation") @XmlAccessorType(XmlAccessType.FIELD) public class ExternalOrganisation { private String name; @XmlElementWrapper @XmlElementRef private List facilities; @XmlElementWrapper @XmlElementRef private List locations; ... } 

步骤#2 – 利用MOXy的Wrapper作为数组名称属性

通过将包装器指定为数组名称属性,MOXy将使用@XmlElementWrapper的值作为JSON数组名称。

 import java.util.*; import javax.ws.rs.core.Application; import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider; public class YourApplication extends Application { @Override public Set> getClasses() { HashSet> set = new HashSet>(1); set.add(YourService.class); return set; } @Override public Set getSingletons() { MOXyJsonProvider moxyJsonProvider = new MOXyJsonProvider(); moxyJsonProvider.setWrapperAsArrayName(true); HashSet set = new HashSet(1); set.add(moxyJsonProvider); return set; } } 

了解更多信息