Giới thiệu về JAXB
JAXB (Java Architecture for XML Binding) cung cấp cơ chế chuyển đổi hai chiều giữa đối tượng Java và tài liệu XML. Bài viết này tập trung vào các ví dụ JAXB thực tế, bao gồm thao tác với nội dung XML, tùy chỉnh ánh xạ giữa Schema và Java, cũng như tạo Schema từ các lớp Java có chú thích.
Các ví dụ được tổ chức thành ba nhóm chính:
- Ví dụ cơ bản: Minh họa giải nén (unmarshal), sửa đổi và đóng gói (marshal) dữ liệu XML.
- Ví dụ tùy chỉnh: Hướng dẫn điều chỉnh ánh xạ mặc định giữa XML Schema và Java.
- Ví dụ Java-to-Schema: Chỉ cách tạo XML Schema từ các lớp Java có chú thích.
Thiết lập môi trường
Trước khi bắt đầu, hãy tải và cài đặt gói JAXB RI (Reference Implementation) từ jaxb.java.net. Các tệp mẫu nằm trong thư mục jaxb-ri-install/samples/.
Ví dụ cơ bản
1. Sửa đổi và đóng gói (Modify Marshal)
Ví dụ này minh họa cách thay đổi nội dung của cây đối tượng Java và đóng gói lại thành XML.
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import primer.po.*;
public class Main {
public static void main(String[] args) throws Exception {
// 1. Tạo context cho package primer.po
JAXBContext jc = JAXBContext.newInstance("primer.po");
// 2. Giải nén file XML thành đối tượng Java
Unmarshaller unmarshaller = jc.createUnmarshaller();
PurchaseOrder po = (PurchaseOrder) unmarshaller.unmarshal(new FileInputStream("po.xml"));
// 3. Sửa đổi thông tin địa chỉ thanh toán
USAddress address = po.getBillTo();
address.setName("John Bob");
address.setStreet("242 Main Street");
address.setCity("Beverly Hills");
address.setState("CA");
address.setZip(new BigDecimal("90210"));
// 4. Đóng gói đối tượng Java trở lại XML
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(po, System.out);
}
}
2. Giải nén và xác thực (Unmarshal Validate)
Ví dụ này cho thấy cách kích hoạt tính năng xác thực trong quá trình giải nén XML.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.ValidationEventLocator;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import primer.po.*;
import org.xml.sax.SAXException;
public class Main {
public static void main(String[] args) throws Exception {
// 1. Tạo JAXB context
JAXBContext jc = JAXBContext.newInstance("primer.po");
// 2. Tạo Unmarshaller và bật chế độ xác thực
Unmarshaller unmarshaller = jc.createUnmarshaller();
// 3. Thiết lập Schema để xác thực
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File("po.xsd"));
unmarshaller.setSchema(schema);
// 4. Thử giải nén file po.xml (có thể chứa lỗi cố ý)
try {
PurchaseOrder po = (PurchaseOrder) unmarshaller.unmarshal(
new FileInputStream("po.xml"));
System.out.println("Giải nén thành công!");
} catch (UnmarshalException ue) {
System.out.println("Lỗi xác thực: " + ue.getMessage());
} catch (JAXBException je) {
je.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
Trình biên dịch JAXB (xjc)
Trình biên dịch xjc chuyển đổi XML Schema thành các lớp Java. Cú pháp cơ bản:
xjc [-options ...] <schema-file>... [-b >bindinfo<]...
Các tùy chọn quan trọng:
-nv: Bỏ qua kiểm tra schema chặt chẽ.-extension: Cho phép sử dụng extension của JAXB.-b file: Chỉ định tệp ràng buộc bên ngoài.-d dir: Thư mục đầu ra cho các lớp Java.-p package: Tên package cho các lớp được sinh ra.-verbose: Hiển thị thông tin chi tiết trong quá trình biên dịch.
Trình tạo Schema (schemagen)
schemagen tạo XML Schema từ các lớp Java có chú thích JAXB.
schemagen [-d path] [java-source-files]
Tùy chỉnh ánh xạ Schema - Java
JAXB cho phép tùy chỉnh ánh xạ mặc định thông qua hai cơ chế:
- Inline: Khai báo trực tiếp trong tệp XML Schema.
- External: Sử dụng tệp ràng buộc bên ngoài (thường có đuôi
.xjb).
Các loại khai báo tùy chỉnh
| Khai báo | Phạm vi | Mô tả |
|---|---|---|
<globalBindings> |
Toàn cục | Ảnh hưởng đến toàn bộ schema. |
<schemaBindings> |
Schema | Xác định package và quy tắc đặt tên. |
<class> |
Lớp | Tùy chỉnh tên lớp Java hoặc lớp cài đặt. |
<property> |
Thuộc tính | Điều chỉnh cách ánh xạ thuộc tính. |
<javaType> |
Kiểu dữ liệu | Ghi đè chuyển đổi kiểu XML-Java. |
<typesafeEnumClass> |
Enum | Ánh xạ simpleType thành enum. |
<javadoc> |
Tài liệu | Thêm Javadoc tùy chỉnh. |
Ví dụ tùy chỉnh Inline
Trong tệp po.xsd, chúng ta thêm các khai báo tùy chỉnh:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
jxb:version="1.0">
<xsd:annotation>
<xsd:appinfo>
<jxb:globalBindings
fixedAttributeAsConstantProperty="true"
collectionType="java.util.Vector"
typesafeEnumMemberName="generateError"/>
<jxb:schemaBindings>
<jxb:package name="primer.myPo"/>
<jxb:nameXmlTransform>
<jxb:elementName suffix="Element"/>
</jxb:nameXmlTransform>
</jxb:schemaBindings>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType name="PurchaseOrderType">
<xsd:annotation>
<xsd:appinfo>
<jxb:class name="POType">
<jxb:javadoc>
A <b>Purchase Order</b> consists of addresses and items.
</jxb:javadoc>
</jxb:class>
</xsd:appinfo>
</xsd:annotation>
<!-- ... -->
</xsd:complexType>
</xsd:schema>
Ví dụ tùy chỉnh External
Tạo tệp binding.xjb:
<jxb:bindings
version="1.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="po.xsd" node="/xs:schema">
<jxb:globalBindings
fixedAttributeAsConstantProperty="true"
collectionType="java.util.Vector"/>
<jxb:schemaBindings>
<jxb:package name="primer.myPo"/>
</jxb:schemaBindings>
<jxb:bindings node="//xs:complexType[@name='USAddress']">
<jxb:class>
<jxb:javadoc>
<![CDATA[First line of documentation for a <b>USAddress</b>.]]>
</jxb:javadoc>
</jxb:class>
<jxb:bindings node=".//xs:element[@name='name']">
<jxb:property name="toName"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
Lớp chuyển đổi kiểu dữ liệu tùy chỉnh
package primer;
import java.math.BigInteger;
import javax.xml.bind.DatatypeConverter;
public class MyDatatypeConverter {
public static short parseIntegerToShort(String value) {
BigInteger result = DatatypeConverter.parseInteger(value);
return (short) result.intValue();
}
public static String printShortToInteger(short value) {
BigInteger result = BigInteger.valueOf(value);
return DatatypeConverter.printInteger(result);
}
}
Ví dụ Java-to-Schema
Các ví dụ này minh họa cách sử dụng chú thích JAXB để ánh xạ lớp Java sang XML Schema.
j2s-xmlAccessorOrder
Kiểm soát thứ tự các phần tử trong XML bằng @XmlAccessorOrder và @XmlType.propOrder.
import javax.xml.bind.annotation.*;
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
@XmlType(propOrder = {"name", "city"})
public class USAddress {
private String name;
private String city;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
}
j2s-xmlAdapter
Sử dụng XmlAdapter để ánh xạ HashMap tùy chỉnh.
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;
// Lớp đại diện XML trung gian
class PurchaseListType {
private List<PartEntry> entry;
public List<PartEntry> getEntry() { return entry; }
public void setEntry(List<PartEntry> entry) { this.entry = entry; }
}
class PartEntry {
@XmlAttribute
private int key;
@XmlValue
private String value;
// getters, setters...
}
// Adapter chuyển đổi giữa HashMap và PurchaseListType
public class AdapterPurchaseListToHashMap
extends XmlAdapter<PurchaseListType, HashMap<Integer, String>> {
@Override
public HashMap<Integer, String> unmarshal(PurchaseListType v) throws Exception {
HashMap<Integer, String> map = new HashMap<>();
for (PartEntry entry : v.getEntry()) {
map.put(entry.getKey(), entry.getValue());
}
return map;
}
@Override
public PurchaseListType marshal(HashMap<Integer, String> v) throws Exception {
PurchaseListType plt = new PurchaseListType();
List<PartEntry> entries = new ArrayList<>();
for (Map.Entry<Integer, String> entry : v.entrySet()) {
PartEntry pe = new PartEntry();
pe.setKey(entry.getKey());
pe.setValue(entry.getValue());
entries.add(pe);
}
plt.setEntry(entries);
return plt;
}
}
// Sử dụng trong lớp chính
public class KitchenWorldBasket {
@XmlJavaTypeAdapter(AdapterPurchaseListToHashMap.class)
private HashMap<Integer, String> basket;
}
j2s-xmlAttribute
Ánh xạ trường hoặc thuộc tính thành thuộc tính XML.
import javax.xml.bind.annotation.*;
public class USAddress {
@XmlAttribute
private String country = "US";
private String name;
private String street;
@XmlAttribute
public String getState() { return state; }
public void setState(String state) { this.state = state; }
}
j2s-xmlRootElement
Xác định tên phần tử gốc cho lớp.
import javax.xml.bind.annotation.*;
@XmlRootElement(name = "purchaseOrder")
public class PurchaseOrderType {
private USAddress shipTo;
private USAddress billTo;
// getters, setters...
}
j2s-xmlSchemaType
Tùy chỉnh ánh xạ kiểu dữ liệu XML.
import javax.xml.bind.annotation.*;
import javax.xml.datatype.XMLGregorianCalendar;
public class TrackingOrder {
@XmlSchemaType(name = "date")
private XMLGregorianCalendar shipDate;
@XmlSchemaType(name = "gMonthDay")
private XMLGregorianCalendar orderDate;
}
j2s-xmlType
Ánh xạ lớp thành kiểu phức tạp (complexType) trong Schema.
import javax.xml.bind.annotation.*;
@XmlType(name = "oContext",
factoryClass = OrderFormsFactory.class,
factoryMethod = "newOrderInstance")
public class OrderContext {
public OrderContext() { }
}
class OrderFormsFactory {
public OrderContext newOrderInstance() {
return new OrderContext();
}
}
Kết luận
JAXB là một công cụ mạnh mẽ giúp đơn giản hóa việc xử lý XML trong Java. Bằng cách kết hợp các kỹ thuật cơ bản (giải nén, sửa đổi, đóng gói) với các tùy chỉnh linh hoạt, bạn có thể kiểm soát hoàn toàn quá trình chuyển đổi giữa XML và đối tượng Java. Các ví dụ Java-to-Schema mở rộng khả năng này, cho phép bạn bắt đầu từ các lớp Java và tạo ra các Schema tương ứng một cách tự động.