论坛首页 Java企业应用论坛

JAXB开发的技巧

浏览 9211 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-11-20  
   大家经常都会遇到xml格式文档的开发,对于解析XML和封装XML格式,我们自然而然的会想到JAXB,JAXB允许以XML格式存储和读取数据,而不需要程序的类结构实现特定的读取XML和保存XML的代码。
以下是需要输出的XML文本格式
<Books>
  <Book>
    <name>书名A</name>
    <author>作者A</author>
    <price>作者A</price>
  </Book>
  <Book>
    <name>书名B</name>
    <author>作者B</author>
    <price>作者B</price>
  </Book>
</Books>

首先我们需要使用XML Schema来描述XML格式,怎样自动生成xsd,我们可以通过trang.jar这个包来生成
java -jar trang.jar a.xml a.xsd

生成的XSD文件格式如下
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="Books">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" ref="Book"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="Book">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="name"/>
        <xs:element ref="author"/>
        <xs:element ref="price"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="name" type="xs:NCName"/>
  <xs:element name="author" type="xs:NCName"/>
  <xs:element name="price" type="xs:NCName"/>
</xs:schema>

现在可以使用jdk自带的xjc命令来生成代码了,xjc的具体使用方面就不多说,大家可以自己看看它的帮助文档
$ xjc a.xsd
parsing a schema...
compiling a schema...
generated\Book.java
generated\Books.java
generated\ObjectFactory.java


package generated;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element ref="{}Book" maxOccurs="unbounded"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "book"
})
@XmlRootElement(name = "Books")
public class Books {

    @XmlElement(name = "Book", required = true)
    protected List<Book> book;

    /**
     * Gets the value of the book property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the book property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getBook().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link Book }
     * 
     * 
     */
    public List<Book> getBook() {
        if (book == null) {
            book = new ArrayList<Book>();
        }
        return this.book;
    }

}


package generated;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element ref="{}name"/>
 *         &lt;element ref="{}author"/>
 *         &lt;element ref="{}price"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "name",
    "author",
    "price"
})
@XmlRootElement(name = "Book")
public class Book {

    @XmlElement(required = true)
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlSchemaType(name = "NCName")
    protected String name;
    @XmlElement(required = true)
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlSchemaType(name = "NCName")
    protected String author;
    @XmlElement(required = true)
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlSchemaType(name = "NCName")
    protected String price;

    /**
     * Gets the value of the name property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getName() {
        return name;
    }

    /**
     * Sets the value of the name property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setName(String value) {
        this.name = value;
    }

    /**
     * Gets the value of the author property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getAuthor() {
        return author;
    }

    /**
     * Sets the value of the author property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setAuthor(String value) {
        this.author = value;
    }

    /**
     * Gets the value of the price property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getPrice() {
        return price;
    }

    /**
     * Sets the value of the price property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setPrice(String value) {
        this.price = value;
    }

}


package generated;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.namespace.QName;


/**
 * This object contains factory methods for each 
 * Java content interface and Java element interface 
 * generated in the generated package. 
 * <p>An ObjectFactory allows you to programatically 
 * construct new instances of the Java representation 
 * for XML content. The Java representation of XML 
 * content can consist of schema derived interfaces 
 * and classes representing the binding of schema 
 * type definitions, element declarations and model 
 * groups.  Factory methods for each of these are 
 * provided in this class.
 * 
 */
@XmlRegistry
public class ObjectFactory {

    private final static QName _Author_QNAME = new QName("", "author");
    private final static QName _Price_QNAME = new QName("", "price");
    private final static QName _Name_QNAME = new QName("", "name");

    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: generated
     * 
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link Book }
     * 
     */
    public Book createBook() {
        return new Book();
    }

    /**
     * Create an instance of {@link Books }
     * 
     */
    public Books createBooks() {
        return new Books();
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     * 
     */
    @XmlElementDecl(namespace = "", name = "author")
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    public JAXBElement<String> createAuthor(String value) {
        return new JAXBElement<String>(_Author_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     * 
     */
    @XmlElementDecl(namespace = "", name = "price")
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    public JAXBElement<String> createPrice(String value) {
        return new JAXBElement<String>(_Price_QNAME, String.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
     * 
     */
    @XmlElementDecl(namespace = "", name = "name")
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    public JAXBElement<String> createName(String value) {
        return new JAXBElement<String>(_Name_QNAME, String.class, null, value);
    }

}

下面我们就可以开始来写代码了
package generated;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

import javax.xml.bind.JAXB;

public class Test {

	public static void main(String[] args) throws FileNotFoundException {
		marshal(new FileOutputStream("out.xml"));

		unmarshal(new FileReader("out.xml"));
	}

	private static void unmarshal(FileReader reader) {
		try {
			Books books = JAXB.unmarshal(reader, Books.class);
			System.out.println(books.getBook().size());
			System.out.println(books.getBook().get(0).getName());
			System.out.println(books.getBook().get(0).getAuthor());
			System.out.println(books.getBook().get(0).getPrice());
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
			}
		}
	}

	private static void marshal(OutputStream output) {
		ObjectFactory factory = new ObjectFactory();

		Books books = factory.createBooks();

		List<Book> bookList = books.getBook();

		Book book = factory.createBook();
		book.setName("书名A");
		book.setAuthor("作者A");
		book.setPrice("价格A");
		bookList.add(book);

		book = factory.createBook();
		book.setName("书名B");
		book.setAuthor("作者B");
		book.setPrice("价格B");
		bookList.add(book);

		book = factory.createBook();
		book.setName("书名C");
		book.setAuthor("作者C");
		book.setPrice("价格C");
		bookList.add(book);

		try {
			JAXB.marshal(books, output);
		} finally {
			try {
				output.close();
			} catch (IOException e) {
			}
		}
	}

}
   发表时间:2011-11-22  
挽尊

我觉得很好, 以前没接触过 。 没人顶, 看来大家都是大贤啊
0 请登录后投票
   发表时间:2011-11-24  

JAX-WS 的Dispatch client可以用到类似的方式

先通过xjc生成相关类

在通过类似如下的代码访问web services

 

URL wsdlLocation = new URL("http://127.0.0.1:8080/cxfDemo/DemoService?wsdl");
		QName serviceName = new QName("http://demo.com", "DemoService");
		
		QName portName = new QName("http://demo.com", "DemoPort");
		JAXBContext context = JAXBContext.newInstance("com.test.bbc");
		Service service = Service.create(wsdlLocation, serviceName);
		Dispatch<Object> dispatch = service.createDispatch(portName, context, Service.Mode.PAYLOAD);
		ObjectFactory factory = new ObjectFactory();
		QueryPerson queryPerson = factory.createQueryPerson();
		JAXBElement<QueryPerson> jaxbElement = factory.createQueryPerson(queryPerson);
		JAXBElement<QueryPersonResponse> retJaxbElement = (JAXBElement<QueryPersonResponse>)dispatch.invoke(jaxbElement);
		QueryPersonResponse res = retJaxbElement.getValue();
		Person person = res.getReturn();
		System.out.println(person.getName());
 
0 请登录后投票
   发表时间:2011-11-24   最后修改:2011-11-24
以前用xjc生成的类,对于复杂的schema,会产生一些啰嗦的类。
比方一个list属性或者 string属性,当在schema中将其定义为element而非属性时,xjc后会产生一个类来描述改elment。
这在schema中为了重用有必要,但在java中就显得啰嗦了,做了不必要的抽象和封装
0 请登录后投票
   发表时间:2011-11-24  
JAXB会产生很多类,不便管理,我们大部分使用Smooks解析XML
0 请登录后投票
   发表时间:2011-11-25  
zhuyl_wind 写道
JAXB会产生很多类,不便管理,我们大部分使用Smooks解析XML

Smooks 能根据schema 生成  class 么?
0 请登录后投票
   发表时间:2011-11-26  
freish 写道

JAX-WS 的Dispatch client可以用到类似的方式

先通过xjc生成相关类

在通过类似如下的代码访问web services

 

 

URL wsdlLocation = new URL("http://127.0.0.1:8080/cxfDemo/DemoService?wsdl");
		QName serviceName = new QName("http://demo.com", "DemoService");
		
		QName portName = new QName("http://demo.com", "DemoPort");
		JAXBContext context = JAXBContext.newInstance("com.test.bbc");
		Service service = Service.create(wsdlLocation, serviceName);
		Dispatch<Object> dispatch = service.createDispatch(portName, context, Service.Mode.PAYLOAD);
		ObjectFactory factory = new ObjectFactory();
		QueryPerson queryPerson = factory.createQueryPerson();
		JAXBElement<QueryPerson> jaxbElement = factory.createQueryPerson(queryPerson);
		JAXBElement<QueryPersonResponse> retJaxbElement = (JAXBElement<QueryPersonResponse>)dispatch.invoke(jaxbElement);
		QueryPersonResponse res = retJaxbElement.getValue();
		Person person = res.getReturn();
		System.out.println(person.getName());
 

其实在java里面对于webservice的调用也可以用jdk自带的wsimport命令来生成,例如:

wsimport stock.wsdl -b stock.xml -b stock.xjb

wsimport -d generated http://example.org/stock?wsdl

0 请登录后投票
   发表时间:2011-11-26  
zhuyl_wind 写道
JAXB会产生很多类,不便管理,我们大部分使用Smooks解析XML

对于自动生成的类,我们是不需要经常管理的,通讯方式是xml格式,我们比较关系的是如果这个xml格式有变动,我们是否可以比较高效的修改代码,例如xml格式变了,我们只需使用xjc命令通过新的schema文件来生成类和对逻辑做些改动即可。
0 请登录后投票
   发表时间:2012-01-13  
JAXB是否可以生成多层结构?

比如,顶层是一个Map,Map里面包含List和Map和Object,List里面也可以存在List、Map和Object。
0 请登录后投票
   发表时间:2012-10-30  
很有用,非常感谢,分享这么好的东西。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics