Xml JAXB/MOXy能否将元素值和元素属性映射到同一POJO字段?
我刚刚开始使用JAXB处理web服务,以将传入的SOAP文档解组到我们的域类中。我遇到了一个技术挑战,这是由丹麦政府机构使用的OIO XML格式决定的。除其他外,该格式声明不允许将xml模式属性nillable用于xml元素定义。因此,我必须为我的挑战找到另一种解决办法 描述 我们有一些数字和日期可以由webservice客户端发送以更新应用程序。这些数字和日期映射到等效类型的POJO字段。挑战在于如何通过构造和发送正确的XML来重置此类POJO字段的值 发送12:31:34T01-01-2010。。。。。将POJO字段更新为指定值 但是,我无法通过发送重置该字段,因为datetime元素不允许使用该字段 我也不能发送,因为OIO XML标准不允许发送 因此,我认为发送是一个严峻的解决方案,因为OIO XML标准不应禁止它 这是如何带来挑战的 如果startTime元素包含delete=“true”属性,那么对应的POJO字段应该设置为null; 如果没有delete属性,则将有效元素值传输到POJO字段 @XMLElement注释只允许我映射startTime值,例如Xml JAXB/MOXy能否将元素值和元素属性映射到同一POJO字段?,xml,xsd,jaxb,eclipselink,moxy,Xml,Xsd,Jaxb,Eclipselink,Moxy,我刚刚开始使用JAXB处理web服务,以将传入的SOAP文档解组到我们的域类中。我遇到了一个技术挑战,这是由丹麦政府机构使用的OIO XML格式决定的。除其他外,该格式声明不允许将xml模式属性nillable用于xml元素定义。因此,我必须为我的挑战找到另一种解决办法 描述 我们有一些数字和日期可以由webservice客户端发送以更新应用程序。这些数字和日期映射到等效类型的POJO字段。挑战在于如何通过构造和发送正确的XML来重置此类POJO字段的值 发送12:31:34T01-01-201
class MyClass{
@XMLElement
private Date startTime;
}
如何强制delete属性也影响MyClass.startTime字段的值
致以最良好的祝愿,
Jesper您可以为此使用XmlAdapter。适配器将与日期对象进行转换。自适应对象将具有两个属性。第一个是用@XmlValue注释的日期属性,第二个是用@XmlAttribute注释的布尔属性。明天我将发布一个完整的示例 MyClass 我们将用@XmlJavaTypeAdapter注释startTime属性
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
class MyClass{
private Date startTime;
@XmlJavaTypeAdapter(DateAdapter.class)
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
}
日期适配器
在DateAdapter类中,我们将在Date实例和具有两个属性(Date和boolean)的类之间进行转换
演示
以下演示代码可用于演示此代码:
import java.util.Date;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(MyClass.class);
System.out.println(jc);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
MyClass myClass1 = new MyClass();
marshaller.marshal(myClass1, System.out);
MyClass myClass2 = new MyClass();
myClass2.setStartTime(new Date());
marshaller.marshal(myClass2, System.out);
}
}
进一步扩展:
- 您可以通过添加@XmlElement(name=“foo”)注释来控制startTime属性的元素名称
- 您可以使用MOXy的@XmlPath(“foo/bar”)注释(如@XmlPath())进一步控制XML表示
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
class MyClass{
private Date startTime;
@XmlJavaTypeAdapter(DateAdapter.class)
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
}
日期适配器
在DateAdapter类中,我们将在Date实例和具有两个属性(Date和boolean)的类之间进行转换
演示
以下演示代码可用于演示此代码:
import java.util.Date;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(MyClass.class);
System.out.println(jc);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
MyClass myClass1 = new MyClass();
marshaller.marshal(myClass1, System.out);
MyClass myClass2 = new MyClass();
myClass2.setStartTime(new Date());
marshaller.marshal(myClass2, System.out);
}
}
进一步扩展:
- 您可以通过添加@XmlElement(name=“foo”)注释来控制startTime属性的元素名称
- 您可以使用MOXy的@XmlPath(“foo/bar”)注释(如@XmlPath())进一步控制XML表示
- 非常感谢您的回答。它似乎适用于非常简单的场景,但对于稍微复杂一些的场景,我没有成功
我试着在我自己的领域里模仿你的代码,只是我在整理数据而不是编组
适配器类:
public class DeleteStringAdapter extends XmlAdapter<DeletableString, String> {
@Override
public DeletableString marshal(String value) throws Exception {
System.out.println("MARSHALL: " + value);
return new DeletableString(value);
}
@Override
public String unmarshal(DeletableString v) throws Exception {
System.out.println("UNMARSHALL: " + v);
if(v.isDelete() != null && v.isDelete()){
return null;
}
return v.getValue();
}
带批注的工作域类:
@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlRootElement(name = "xml-fragment")
public class SimpleNavne implements Serializable{
private String forNavn = "";
private String fornavneMrkKode = "";
@XmlElement(name="PersonGivenName")
@XmlJavaTypeAdapter(value = DeleteStringAdapter.class)
public String getForNavn() {
return forNavn;
}
public void setForNavn(String forNavn) {
this.forNavn = forNavn;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(SimpleNavne.class.getSimpleName() + "[");
builder.append("forNavn=");
builder.append(forNavn);
builder.append("]");
return builder.toString();
}
}
演示
文件:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns:xml-fragment xmlns:ns="http://cpr.csc.com/navne">
<ns:PersonGivenName delete="false">010</ns:PersonGivenName>
</ns:xml-fragment>
但是,在SimpleName域类中引入带@XMLPath注释的字段时,我会遇到问题
修改的域类
@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlRootElement(name = "xml-fragment")
public class SimpleNavne implements Serializable{
private String forNavn = "";
private String fornavneMrkKode = "";
@XmlElement(name="PersonGivenName")
@XmlJavaTypeAdapter(value = DeleteStringAdapter.class)
public String getForNavn() {
return forNavn;
}
public void setForNavn(String forNavn) {
this.forNavn = forNavn;
}
@XmlPath("/PersonGivenNameMarkingStructure/MarkingCode/text()")
public String getFornavneMrkKode() {
return fornavneMrkKode;
}
public void setFornavneMrkKode(String forNavnMrk) {
this.fornavneMrkKode = forNavnMrk;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(SimpleNavne.class.getSimpleName() + "[");
builder.append(", forNavn=");
builder.append(forNavn);
builder.append(", fornavneMrkKode=");
builder.append(fornavneMrkKode);
builder.append("]");
return builder.toString();
}
}
修改文件:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns:xml-fragment xmlns:ns="http://cpr.csc.com/navne">
<ns:PersonGivenName delete="true">010</ns:PersonGivenName>
<ns:PersonGivenNameMarkingStructure>
<ns:MarkingCode>011</ns:MarkingCode>
</ns:PersonGivenNameMarkingStructure>
</ns:xml-fragment>
但应该是:
SimpleNavne[forNavn=010, fornavneMrkKode=011]
我是做错了什么,还是莫西不支持这种情况
另外,我尝试过使用MOXy 2.1.1和2.2.0-M3,结果相同非常感谢您的回答。它似乎适用于非常简单的场景,但对于稍微复杂一些的场景,我没有成功 我试着在我自己的领域里模仿你的代码,只是我在整理数据而不是编组 适配器类:
public class DeleteStringAdapter extends XmlAdapter<DeletableString, String> {
@Override
public DeletableString marshal(String value) throws Exception {
System.out.println("MARSHALL: " + value);
return new DeletableString(value);
}
@Override
public String unmarshal(DeletableString v) throws Exception {
System.out.println("UNMARSHALL: " + v);
if(v.isDelete() != null && v.isDelete()){
return null;
}
return v.getValue();
}
带批注的工作域类:
@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlRootElement(name = "xml-fragment")
public class SimpleNavne implements Serializable{
private String forNavn = "";
private String fornavneMrkKode = "";
@XmlElement(name="PersonGivenName")
@XmlJavaTypeAdapter(value = DeleteStringAdapter.class)
public String getForNavn() {
return forNavn;
}
public void setForNavn(String forNavn) {
this.forNavn = forNavn;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(SimpleNavne.class.getSimpleName() + "[");
builder.append("forNavn=");
builder.append(forNavn);
builder.append("]");
return builder.toString();
}
}
演示
文件:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns:xml-fragment xmlns:ns="http://cpr.csc.com/navne">
<ns:PersonGivenName delete="false">010</ns:PersonGivenName>
</ns:xml-fragment>
但是,在SimpleName域类中引入带@XMLPath注释的字段时,我会遇到问题
修改的域类
@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlRootElement(name = "xml-fragment")
public class SimpleNavne implements Serializable{
private String forNavn = "";
private String fornavneMrkKode = "";
@XmlElement(name="PersonGivenName")
@XmlJavaTypeAdapter(value = DeleteStringAdapter.class)
public String getForNavn() {
return forNavn;
}
public void setForNavn(String forNavn) {
this.forNavn = forNavn;
}
@XmlPath("/PersonGivenNameMarkingStructure/MarkingCode/text()")
public String getFornavneMrkKode() {
return fornavneMrkKode;
}
public void setFornavneMrkKode(String forNavnMrk) {
this.fornavneMrkKode = forNavnMrk;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(SimpleNavne.class.getSimpleName() + "[");
builder.append(", forNavn=");
builder.append(forNavn);
builder.append(", fornavneMrkKode=");
builder.append(fornavneMrkKode);
builder.append("]");
return builder.toString();
}
}
修改文件:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns:xml-fragment xmlns:ns="http://cpr.csc.com/navne">
<ns:PersonGivenName delete="true">010</ns:PersonGivenName>
<ns:PersonGivenNameMarkingStructure>
<ns:MarkingCode>011</ns:MarkingCode>
</ns:PersonGivenNameMarkingStructure>
</ns:xml-fragment>
但应该是:
SimpleNavne[forNavn=010, fornavneMrkKode=011]
我是做错了什么,还是莫西不支持这种情况
另外,在回答您的第二个问题时,我尝试使用MOXy 2.1.1和2.2.0-M3,结果相同:
20-Oct-2010 2:50:46 PM javax.xml.bind.ContextFinder find
FINE: Trying to locate forum80/jaxb.properties
20-Oct-2010 2:50:46 PM javax.xml.bind.ContextFinder loadJAXBProperties
FINE: loading props from file:/C:/Workspaces/EclipseLink-Trunk/SCRATCH/bin/forum80/jaxb.properties
20-Oct-2010 2:50:46 PM javax.xml.bind.ContextFinder find
FINE: found
20-Oct-2010 2:50:46 PM javax.xml.bind.ContextFinder safeLoadClass
FINE: Trying to load org.eclipse.persistence.jaxb.JAXBContextFactory
20-Oct-2010 2:50:46 PM javax.xml.bind.ContextFinder newInstance
FINE: loaded org.eclipse.persistence.jaxb.JAXBContextFactory from jar:file:/C:/Workspaces/EclipseLink-2.1/eclipselink.jar!/org/eclipse/persistence/jaxb/JAXBContextFactory.class
UNMARSHALL: DeletableString[delete=true, value=010]
SimpleNavne[, forNavn=null, fornavneMrkKode=011]
此结果与您看到的结果不同:
SimpleNavne[forNavn=010, fornavneMrkKode=]
我们可能需要调整XML适配器中的逻辑以处理特定的XML示例。在XML片段中,您为映射到“forNavn”属性的“PersonGivenName”元素指定delete=“true”和一个值,在这种情况下,null或值是否应获胜
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns:xml-fragment xmlns:ns="http://cpr.csc.com/navne">
<ns:PersonGivenName delete="true">010</ns:PersonGivenName>
<ns:PersonGivenNameMarkingStructure>
<ns:MarkingCode>011</ns:MarkingCode>
</ns:PersonGivenNameMarkingStructure>
</ns:xml-fragment>
更新:
我已经通过电子邮件向您发送了我用来调试您的问题的Java项目,您介意运行它以查看是否得到相同的结果吗?希望您能得到相同的输出,我们可以找出导致错误行为的增量。回答您的第二个问题:
20-Oct-2010 2:50:46 PM javax.xml.bind.ContextFinder find
FINE: Trying to locate forum80/jaxb.properties
20-Oct-2010 2:50:46 PM javax.xml.bind.ContextFinder loadJAXBProperties
FINE: loading props from file:/C:/Workspaces/EclipseLink-Trunk/SCRATCH/bin/forum80/jaxb.properties
20-Oct-2010 2:50:46 PM javax.xml.bind.ContextFinder find
FINE: found
20-Oct-2010 2:50:46 PM javax.xml.bind.ContextFinder safeLoadClass
FINE: Trying to load org.eclipse.persistence.jaxb.JAXBContextFactory
20-Oct-2010 2:50:46 PM javax.xml.bind.ContextFinder newInstance
FINE: loaded org.eclipse.persistence.jaxb.JAXBContextFactory from jar:file:/C:/Workspaces/EclipseLink-2.1/eclipselink.jar!/org/eclipse/persistence/jaxb/JAXBContextFactory.class
UNMARSHALL: DeletableString[delete=true, value=010]
SimpleNavne[, forNavn=null, fornavneMrkKode=011]
此结果与您看到的结果不同:
SimpleNavne[forNavn=010, fornavneMrkKode=]
我们可能需要调整XML适配器t中的逻辑