2013年9月16日星期一

JDev_041:怎样从Java得到XML?

开发运行环境:JDeveloper 11.1.1.7

本文探讨的问题是:如果你已经有了Java类,比如一些POJO类,如何把它们转换为XML?
这里需要用到JAXB的技术,关于JAXB的介绍,请参考《JAXB介绍》,本文不再赘述。
从Java到XML的过程,用专业的术语表示就是Marshal。

1. 创建POJO类
(1)Company.java
package java2xml;

import java.io.ByteArrayOutputStream;

import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlType(namespace = "http://myNameSpace")
@XmlRootElement(name = "Corporation")
public class Company {

    private String name;
    @XmlElement
    private List employees;

    public Company() {
    }

    @XmlElement
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List getEmployees() {
        return EmpManager.getEmpManager().getEmps();
    }

    public void setEmployees() {
        EmpManager.getEmpManager().resetData();
    }
}
注意,原来加在属性name上的批注@XmlElement,改到加在方法getName()上。
如果不改的话,执行schemagen.exe时会抛出如下异常:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "name"
this problem is related to the following location:
at public java.lang.String java2xml.Company.getName()
at java2xml.Company
this problem is related to the following location:
at private java.lang.String java2xml.Company.name
at java2xml.Company

(2)Emp.java
比较简单,从略。

2. 运行schemagen.exe 生成 XML Schema
在JDK的bin目录下有一个命令:schemagen.exe,运行如下脚本生成XML Schema:
schemagen.exe -d D:\JDevRuntime\JDev11117\mywork\Java2Xml\Java2Xml\src -cp D:\JDevRuntime\JDev11117\mywork\Java2Xml\Java2XML\classes java2xml.Company java2xml.Emp

会生成两个xsd文件:
(1)schema1.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" targetNamespace="http://myNameSpace" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:import schemaLocation="schema2.xsd"/>

  <xs:complexType name="company">
    <xs:sequence>
      <xs:element name="employees" type="emp" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="name" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

(2)schema2.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:ns1="http://myNameSpace" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:import namespace="http://myNameSpace" schemaLocation="schema1.xsd"/>

  <xs:element name="Corporation" type="ns1:company"/>


  <xs:complexType name="emp">
    <xs:sequence>
      <xs:element name="comm" type="xs:double" minOccurs="0"/>
      <xs:element name="deptno" type="xs:long" minOccurs="0"/>
      <xs:element name="empno" type="xs:long" minOccurs="0"/>
      <xs:element name="ename" type="xs:string" minOccurs="0"/>
      <xs:element name="job" type="xs:string" minOccurs="0"/>
      <xs:element name="mgr" type="xs:long" minOccurs="0"/>
      <xs:element name="sal" type="xs:double" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

3. 生成JAXB对象
(1)右键schema1.xsd,选择“Generate JAXB 2.0 Content Model”:

(2)为了不与原来的POJO类冲突,这里放到另一个目录

4. 修改自动生成的POJO类
(1)在Company.java中增加如下方法:

    public Company() {
        resetData();
    }

    public void resetData() {
        createEmp((long)7369, "SMITH", "CLERK", (long)7902, (double)800, null,
                  (long)20);
        createEmp((long)7499, "ALLEN", "SALESMAN", (long)7698, (double)1600,
                  (double)300, (long)30);
        createEmp((long)7521, "WARD", "SALESMAN", (long)7698, (double)1250,
                  (double)500, (long)30);
        createEmp((long)7566, "JONES", "MANAGER", (long)7839, (double)2975,
                  null, (long)20);
        createEmp((long)7654, "MARTIN", "SALESMAN", (long)7698, (double)1250,
                  (double)1400, (long)30);
        createEmp((long)7698, "BLAKE", "MANAGER", (long)7839, (double)2850,
                  null, (long)30);
        createEmp((long)7782, "CLARK", "MANAGER", (long)7839, (double)2450,
                  null, (long)10);
        createEmp((long)7788, "SCOTT", "ANALYST", (long)7566, (double)3000,
                  null, (long)20);
        createEmp((long)7839, "KING", "PRESIDENT", null, (double)5000, null,
                  (long)10);
        createEmp((long)7844, "TURNER", "SALESMAN", (long)7698, (double)1500,
                  (double)0, (long)30);
        createEmp((long)7876, "ADAMS", "CLERK", (long)7788, (double)1100, null,
                  (long)20);
        createEmp((long)7900, "JAMES", "CLERK", (long)7698, (double)950, null,
                  (long)30);
        createEmp((long)7902, "FORD", "ANALYST", (long)7566, (double)3000,
                  null, (long)20);
        createEmp((long)7934, "MILLER", "CLERK", (long)7782, (double)1300,
                  null, (long)10);
    }

    public void createEmp(Long empno, String ename, String job, Long mgr,
                          Double sal, Double comm, Long deptno) {
        Emp newEmp = new ObjectFactory().createEmp();

        newEmp.update(empno, ename, job, mgr, sal, comm, deptno);
        getEmployees().add(newEmp);
    }

    public static void main(String[] args) throws JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance("java2xml.generated");
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
        ObjectFactory objf = new ObjectFactory();
        Company company = objf.createCompany();
        company.setName("Ma Ping and Friends");
        marshaller.marshal(company, System.out);
    }
main函数中使用了Marshaller对象,使用ObjectFactory创建了Company对象,然后marshal该对象并输出。

(2)在Emp.java中增加如下方法:

    public void update(Long empno, String ename, String job, Long mgr,
                       Double sal, Double comm, Long deptno) {
        this.empno = empno;
        this.ename = ename;
        this.job = job;
        this.mgr = mgr;
        this.sal = sal;
        this.comm = comm;
        this.deptno = deptno;
    }

5. 运行修改后的Company.java
输出的XML内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<Corporation xmlns:ns0="http://myNameSpace">
   <employees>
      <deptno>20</deptno>
      <empno>7369</empno>
      <ename>SMITH</ename>
      <job>CLERK</job>
      <mgr>7902</mgr>
      <sal>800.0</sal>
   </employees>
   <employees>
      <comm>300.0</comm>
      <deptno>30</deptno>
      <empno>7499</empno>
      <ename>ALLEN</ename>
      <job>SALESMAN</job>
      <mgr>7698</mgr>
      <sal>1600.0</sal>
   </employees>
   <employees>
      <comm>500.0</comm>
      <deptno>30</deptno>
      <empno>7521</empno>
      <ename>WARD</ename>
      <job>SALESMAN</job>
      <mgr>7698</mgr>
      <sal>1250.0</sal>
   </employees>
   <employees>
      <deptno>20</deptno>
      <empno>7566</empno>
      <ename>JONES</ename>
      <job>MANAGER</job>
      <mgr>7839</mgr>
      <sal>2975.0</sal>
   </employees>
   <employees>
      <comm>1400.0</comm>
      <deptno>30</deptno>
      <empno>7654</empno>
      <ename>MARTIN</ename>
      <job>SALESMAN</job>
      <mgr>7698</mgr>
      <sal>1250.0</sal>
   </employees>
   <employees>
      <deptno>30</deptno>
      <empno>7698</empno>
      <ename>BLAKE</ename>
      <job>MANAGER</job>
      <mgr>7839</mgr>
      <sal>2850.0</sal>
   </employees>
   <employees>
      <deptno>10</deptno>
      <empno>7782</empno>
      <ename>CLARK</ename>
      <job>MANAGER</job>
      <mgr>7839</mgr>
      <sal>2450.0</sal>
   </employees>
   <employees>
      <deptno>20</deptno>
      <empno>7788</empno>
      <ename>SCOTT</ename>
      <job>ANALYST</job>
      <mgr>7566</mgr>
      <sal>3000.0</sal>
   </employees>
   <employees>
      <deptno>10</deptno>
      <empno>7839</empno>
      <ename>KING</ename>
      <job>PRESIDENT</job>
      <sal>5000.0</sal>
   </employees>
   <employees>
      <comm>0.0</comm>
      <deptno>30</deptno>
      <empno>7844</empno>
      <ename>TURNER</ename>
      <job>SALESMAN</job>
      <mgr>7698</mgr>
      <sal>1500.0</sal>
   </employees>
   <employees>
      <deptno>20</deptno>
      <empno>7876</empno>
      <ename>ADAMS</ename>
      <job>CLERK</job>
      <mgr>7788</mgr>
      <sal>1100.0</sal>
   </employees>
   <employees>
      <deptno>30</deptno>
      <empno>7900</empno>
      <ename>JAMES</ename>
      <job>CLERK</job>
      <mgr>7698</mgr>
      <sal>950.0</sal>
   </employees>
   <employees>
      <deptno>20</deptno>
      <empno>7902</empno>
      <ename>FORD</ename>
      <job>ANALYST</job>
      <mgr>7566</mgr>
      <sal>3000.0</sal>
   </employees>
   <employees>
      <deptno>10</deptno>
      <empno>7934</empno>
      <ename>MILLER</ename>
      <job>CLERK</job>
      <mgr>7782</mgr>
      <sal>1300.0</sal>
   </employees>
   <name>Ma Ping and Friends</name>
</Corporation>

小结:实际应用中,为了能够让原始的POJO类和自动生成的同名POJO类不冲突,需要写包装类CompanyWrapper,EmpWrapper,这样所有的操作都统一针对Wrapper类的操作。

Project 下载:Java2Xml.7z

参考文献:
1. http://technology.amis.nl/2011/06/24/creating-an-xml-document-based-on-my-pojo-domain-model-how-will-jaxb-help-me/
2. http://technology.amis.nl/2011/06/25/turning-any-xml-document-into-java-object-graph-using-jaxb-2-0/
3. http://technology.amis.nl/2008/06/15/how-to-quickly-generate-an-xsd-xml-schema-definition-based-on-a-java-class-model-using-jdeveloper-11g/
4. http://www.developer.com/services/article.php/3722211/Using-JAXB-in-JDeveloper-1013.htm
5. http://biemond.blogspot.com/2008/02/jaxb-20-in-jdeveloper-10g-and-11g.html

没有评论: