我为JAX-WS(Metro)和JAX-RS(Jersey)使用通用的JAXB模型。我有以下请求代码段:
<xs:element name="CreatedProjFolders">
<xs:complexType>
<xs:sequence>
<xs:element name="CreatedProjFolder" type="tns:CreatedProjFolder" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="parentItemId" type="tns:itemId" use="required" />
</xs:complexType>
</xs:element>
<xs:complexType name="CreateProjFolder">
<xs:attribute name="itemId" type="tns:itemId" use="required" />
...
</xs:complexType>
XJC生成了这个类:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"createProjFolders"
})
@XmlRootElement(name = "CreateProjFolders")
public class CreateProjFolders {
@XmlElement(name = "CreateProjFolder", required = true)
@NotNull
@Size(min = 1)
@Valid
// Name has been pluralized with JAXB bindings file
protected List<CreateProjFolder> createProjFolders;
@XmlAttribute(name = "parentItemId", required = true)
@NotNull
@Size(max = 128)
protected String parentItemId;
...
}
适当的JSON POST应如下所示:
{"parentItemId":"P5J00142301", "createProjFolders":[
{"itemId":"bogus"}
]}
但实际上必须看起来像:
{"parentItemId":"P5J00142301", "CreateProjFolder":[
{"itemId":"bogus"}
]}
如何重命名JSON的属性名称,只类似于Java中的属性名称(protected List<CreateProjFolder> createProjFolders
)?
答案 0 :(得分:2)
当MOXy用作JSON绑定提供程序时,JSON键与@XmlElement
注释中的specfieid相同。例如,当你有:
@XmlElement(name = "CreateProjFolder", required = true)
protected List<CreateProjFolder> createProjFolders;
你会得到:
{"parentItemId":"P5J00142301", "CreateProjFolder":[
{"itemId":"bogus"}
]}
如果您希望JSON中的名称与XML中的名称不同,则可以利用MOXy的外部映射元数据来覆盖注释中指定的内容:
答案 1 :(得分:1)
在阅读了Blaise的帖子和博客之后,我花了两天的时间才想出一个有效的解决方案。首先,MOXyJsonProvider
和ConfigurableMoxyJsonProvider
的当前状态使其成为一种痛苦的经验,使其成功并且从未为此设计过。
我的第一个测试是创建一个与泽西岛完全分离的洁净室实现,并以main
方法运行。
以下是main
方法:
public static void main(String[] args) throws JAXBException {
Map<String, Object> props = new HashMap<>();
InputStream importMoxyBinding = MOXyTest.class
.getResourceAsStream("/json-binding.xml");
List<InputStream> moxyBindings = new ArrayList<>();
moxyBindings.add(importMoxyBinding);
props.put(JAXBContextProperties.OXM_METADATA_SOURCE, moxyBindings);
props.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
props.put(JAXBContextProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
JAXBContext jc = JAXBContext.newInstance("my.package",
CreateProjFolders.class.getClassLoader(), props);
Unmarshaller um = jc.createUnmarshaller();
InputStream json = MOXyTest.class
.getResourceAsStream("/CreateProjFolders.json");
Source source = new StreamSource(json);
JAXBElement<CreateProjFolders> create = um.unmarshal(source, CreateProjFolders.class);
CreateProjFolders folders = create.getValue();
System.out.printf("Used JAXBContext: %s%n", jc);
System.out.printf("Unmarshalled structure: %s%n", folders);
Marshaller m = jc.createMarshaller();
m.setProperty(MarshallerProperties.INDENT_STRING, " ");
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
System.out.print("Marshalled structure: ");
m.marshal(folders, System.out);
}
此处为json-binding.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="my.package"
xml-mapping-metadata-complete="false">
<xml-schema namespace="urn:namespace"
element-form-default="QUALIFIED" />
<java-types>
<java-type name="CreateProjFolders">
<xml-root-element />
<java-attributes>
<xml-element java-attribute="projFolders" name="createProjFolders" />
</java-attributes>
</java-type>
<java-type name="CreateProjFolder">
<java-attributes>
<xml-element java-attribute="access" name="access" />
</java-attributes>
</java-type>
<java-type name="Access">
<java-attributes>
<xml-element java-attribute="productionSites" name="productionSites" />
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
和示例输入文件:
{"parentItemId":"some-id",
"createProjFolders":[
{"objectNameEn":"bogus", "externalProjectId":"123456",
"access":{"productionSites":["StackOverflow"], "user":"michael-o"}}
]
}
解组和编组工作完美无瑕。现在,如何让它与泽西岛合作?你不能,因为你无法传递JAXBContext属性。
由于MOXyJsonProvider
功能,您需要将MOXy的AutoDiscoverable
以及Jersey Media MOXy的整个源(XML内容)复制到新的Maven项目中。这个包将取代原来的依赖。
应用following patches。修补程序并不完美,因为某些代码是重复的,因此是多余的,但可以在以后的故障单中完成。
现在在Application.class
:
InputStream importMoxyBinding = MyApplication.class
.getResourceAsStream("/json-binding.xml");
List<InputStream> moxyBindings = new ArrayList<>();
moxyBindings.add(importMoxyBinding);
final MoxyJsonConfig jsonConfig = new MoxyJsonConfig();
jsonConfig.setOxmMedatadataSource(moxyBindings);
ContextResolver<MoxyJsonConfig> jsonConfigResolver = jsonConfig.resolver();
register(jsonConfigResolver);
现在试试吧。在针对不同型号的多次通话后,您会看到JAXBExceptions
带有&#39;文件过早结束&#39;。你会问你为什么?!原因是MOXyJsonProvider
每个域类创建并缓存JAXBContexts
而不是每个包,这意味着您的输入流被多次读取但在第一次读取后已经关闭。你迷路了。您需要重置流但不能更改MOXy的内部内容。这是一个简单的solution:
public class ResetOnCloseInputStream extends BufferedInputStream {
public ResetOnCloseInputStream(InputStream is) {
super(is);
super.mark(Integer.MAX_VALUE);
}
@Override
public void close() throws IOException {
super.reset();
}
}
并将您的Application.class
换成
moxyBindings.add(new ResetOnCloseInputStream(importMoxyBinding));
在你感受到屁股的痛苦之后,享受魔力!
最后的话:
OXM_METADATA_SOURCE
的人。严重?