สำหรับส่วนที่สั่งให้ทำงาน เช่น ใน main method
// 1. สร้าง Object ที่ต้องการแปลง
Student student = new Student(65001, "สมศักดิ์ เรียนดี", "วิศวกรรมคอมพิวเตอร์");
// 2. สร้าง JAXB Context และ Marshaller
JAXBContext context = JAXBContext.newInstance(Student.class);
Marshaller marshaller = context.createMarshaller();
// 3. ตั้งค่าให้ XML ที่สร้างออกมาสวยงาม (มีการย่อหน้า)
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
// 4. ทำการ Marshalling (แปลง Object เป็น XML)
// แสดงผลลัพธ์ออกทางหน้าจอ
System.out.println("--- XML Output ---");
marshaller.marshal(student, System.out);
// หรือบันทึกเป็นไฟล์
marshaller.marshal(student, new File("student.xml"));
System.out.println("\nไฟล์ student.xml ถูกสร้างเรียบร้อยแล้ว");
แต่ตัว class เราต้องมีการเตรียมการก่อน จะได้รู้ว่า ค่าไหนเป็น tag อะไร ใน xml file
Tag ที่น่าจะใช้บ่อยๆ
- @XmlRootElement
- @XmlElement
- @XmlAttribute
- @XmlAccessorType
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
/**
*
* @author Thada
*/
@XmlRootElement(name = "student") // บอกว่า Root element ของ XML คือ <student>
public class Student {
private int id;
private String name;
private String major;
// Constructors
public Student() {}
public Student(int id, String name, String major) {
this.id = id;
this.name = name;
this.major = major;
}
// Getters and Setters
@XmlElement(name = "student_id") // กำหนดชื่อ tag สำหรับ field นี้
public int getId() { return id; }
public void setId(int id) { this.id = id; }
@XmlElement(name = "full_name")
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@XmlElement(name = "faculty")
public String getMajor() { return major; }
public void setMajor(String major) { this.major = major; }
}
Library ที่จำเป็นต้องใช้คือ JAXB ซึ่งหลังๆมานี้ไม่ได้เป็นส่วนหนึ่งใน Java Standard SDK แล้ว
// https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api
implementation("javax.xml.bind:jaxb-api:2.3.1")
// https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl
implementation("com.sun.xml.bind:jaxb-impl:4.0.5")
@XmlAccessorType(XmlAccessType.FIELD)
Annotation นี้ใช้กำหนดว่า JAXB ควรจะเข้าถึงข้อมูลส่วนไหนในคลาสเพื่อนำไปสร้างเป็น XML Element โดย XmlAccessType.FIELD เป็นการสั่งให้ JAXB เข้าถึง “Field” หรือตัวแปรทั้งหมดในคลาสโดยตรง ไม่ว่าตัวแปรนั้นจะเป็น public, private, หรือ protected ก็ตาม
@XmlAccessorType: Annotation สำหรับกำหนดรูปแบบการเข้าถึงข้อมูลXmlAccessType.FIELD: ระบุให้ JAXB สนใจที่ Field (ตัวแปร) ของคลาสโดยตรง โดยไม่ต้องผ่าน methodgetterหรือsetter
พูดง่ายๆ คือ @XmlAccessorType เป็นตัวกำหนด “กฎ” ว่า JAXB จะมองหาสิ่งที่จะแปลงเป็น XML จากที่ไหน (Field, Getter/Setter, ฯลฯ) ส่วน @XmlElement ใช้สำหรับ “ปรับแต่ง” หรือ “ชี้เป้า” เป็นพิเศษ
เมื่อใช้ @XmlAccessorType(XmlAccessType.FIELD)
- ไม่จำเป็นต้องใส่
@XmlElementที่ getter เลย JAXB จะอ่านค่าจากตัวแปรprivateหรือpublicโดยอัตโนมัติ - ถ้าจะใส่
@XmlElementก็ต่อเมื่อต้องการปรับแต่งบางอย่างที่ Field นั้นๆ เช่น เปลี่ยนชื่อ Tag ใน XML
เมื่อไม่มี @XmlAccessorType ถูกกำหนดไว้ JAXB จะทำงานในโหมด PUBLIC_MEMBER โดยอัตโนมัติ ซึ่งมีกฎดังนี้:
- JAXB จะสแกนหา
publicgetter/setter ทุกคู่ และpublicfield ทั้งหมด เพื่อนำไปสร้างเป็น XML - มันจะไม่สนใจ
privatefield โดยสิ้นเชิง (ตราบใดที่ไม่มีpublicgetter/setter ที่สอดคล้องกัน)
เปรียบเสมือน JAXB มองคลาสของคุณผ่าน “Interface สาธารณะ” ซึ่งก็คือ public method และ public field นั่นเอง
การใส่ @XmlElement ที่ public getter เป็นวิธีที่สอดคล้องกับโหมดการทำงานเริ่มต้นนี้มากที่สุด
- ความสอดคล้อง: คุณกำลังติดป้ายกำกับ (Annotation) ในตำแหน่งเดียวกับที่ JAXB กำลังมองหาข้อมูลอยู่แล้ว ทำให้โค้ดเข้าใจง่ายและตรงไปตรงมา
- รองรับ Logic ใน Getter: หาก getter ของคุณมีตรรกะบางอย่าง (เช่น การจัดรูปแบบข้อความ) การใส่ Annotation ที่ getter จะรับประกันว่าผลลัพธ์ที่ผ่านตรรกะแล้วเท่านั้นที่จะถูกนำไปใส่ใน XML
ถ้าให้ง่าย ก็ใช้ @XmlAccessorType เป็น FIELD ไปก่อน
ตรงไหนอยากให้พิเศษก็ค่อยแทรก @XmlElement เป็นตัวๆไป
@XmlAttribute 🏷️
Annotation นี้จะสั่งให้ JAXB แปลง field ของ Java ให้กลายเป็น attribute ของ tag แม่ (parent element) แทนที่จะสร้างเป็น tag ลูก (child element) ที่ซ้อนอยู่ข้างใน
@XmlRootElement(name = "book")
@XmlAccessorType(XmlAccessType.FIELD)
public class Book {
// ใช้ @XmlAttribute เพื่อกำหนดให้ "id" เป็น attribute ของ <book>
@XmlAttribute
private long id;
// ใช้ @XmlElement (หรือปล่อยว่าง) เพื่อให้ "title" เป็น element ลูก
@XmlElement
private String title;
// Constructors, Getters, Setters...
}
<book id="123">
<title>JAXB for Beginners</title>
</book>
@XmlSeeAlso({Drill.class})
ใช้เพื่อแจ้งให้ JAXB ทราบล่วงหน้าเกี่ยวกับคลาสย่อย (subclass) ที่อาจเกิดขึ้นเมื่อทำงานกับคลาสแม่ (superclass) ที่มีความสัมพันธ์แบบ Inheritance (การสืบทอดคุณสมบัติ)
พูดง่ายๆ คือ มันเป็นการบอก JAXB ว่า “เวลาคุณเจอคลาสแม่นี้ ให้เตรียมรู้จักคลาสลูกชื่อ Drill ไว้ด้วยนะ เพราะมันอาจจะถูกใช้งาน
// คลาสแม่ (Superclass)
@XmlAccessorType(XmlAccessType.FIELD)
public abstract class Tool {
private String name;
}
// คลาสลูก (Subclass)
public class Drill extends Tool {
private int rpm;
}
// คลาสที่เก็บรายการ Tool
@XmlRootElement
public class ToolBox {
private List<Tool> tools;
}
แล้วเราพยายามแปลง (Marshal) ToolBox ที่มี Drill อยู่ข้างใน โปรแกรมจะเกิด Error 💥 เพราะตอนที่ JAXB สร้าง Context จากคลาส ToolBox มันจะเห็นแค่ Tool แต่ไม่รู้จัก Drill

