Java Language
JAXB
수색…
소개
JAXB 또는 JAXB ( Java Architecture for XML Binding )는 Java 개발자가 Java 클래스를 XML 표현에 매핑 할 수있게 해주는 소프트웨어 프레임 워크입니다. 이 페이지는 자바 객체를 XML 형식으로 마샬링 및 언 마셜링하기 위해 주로 제공되는 기능에 대한 자세한 예제를 사용하여 JAXB 독자를 소개하고 그 반대도 마찬가지입니다.
통사론
JAXB.marshall (object, fileObjOfXML);
Object obj = JAXB.unmarshall (fileObjOfXML, className);
매개 변수
매개 변수 | 세부 |
---|---|
fileObjOfXML | XML 파일의 File 객체 |
className | .class 확장자를 가진 클래스 이름 |
비고
JDK에서 사용할 수있는 XJC 도구를 사용하면 xml 스키마 ( .xsd
파일)에 설명 된 xml 구조의 Java 코드를 자동으로 생성 할 수 있습니다 ( XJC 항목 참조).
XML 파일 작성 (객체 마샬링)
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class User {
private long userID;
private String name;
// getters and setters
}
어노테이션 XMLRootElement
를 사용하여 클래스를 XML 파일의 루트 요소로 표시 할 수 있습니다.
import java.io.File;
import javax.xml.bind.JAXB;
public class XMLCreator {
public static void main(String[] args) {
User user = new User();
user.setName("Jon Skeet");
user.setUserID(8884321);
try {
JAXB.marshal(user, new File("UserDetails.xml"));
} catch (Exception e) {
System.err.println("Exception occurred while writing in XML!");
} finally {
System.out.println("XML created");
}
}
}
marshal()
은 객체의 내용을 XML 파일에 쓰는 데 사용됩니다. 여기서 user
객체와 새 File
객체는 marshal()
인수로 전달됩니다.
성공적으로 실행되면 class-path에 아래 내용이있는 UserDetails.xml
이라는 XML 파일이 만들어집니다.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
<name>Jon Skeet</name>
<userID>8884321</userID>
</user>
XML 파일 읽기 (언 마샬링)
아래 내용으로 UserDetails.xml
이라는 XML 파일을 읽으려면
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
<name>Jon Skeet</name>
<userID>8884321</userID>
</user>
아래처럼 User.java
라는 POJO 클래스가 필요하다.
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class User {
private long userID;
private String name;
// getters and setters
}
여기서는 XML 노드에 따라 변수와 클래스 이름을 만들었습니다. 이들을 매핑하기 위해 클래스의 XmlRootElement
주석을 사용합니다.
public class XMLReader {
public static void main(String[] args) {
try {
User user = JAXB.unmarshal(new File("UserDetails.xml"), User.class);
System.out.println(user.getName()); // prints Jon Skeet
System.out.println(user.getUserID()); // prints 8884321
} catch (Exception e) {
System.err.println("Exception occurred while reading the XML!");
}
}
}
여기서 unmarshal()
메소드는 XML 파일을 구문 분석하는 데 사용됩니다. XML 파일 이름과 클래스 유형을 두 개의 인수로 취합니다. 그런 다음 객체의 getter 메서드를 사용하여 데이터를 인쇄 할 수 있습니다.
XmlAdapter를 사용하여 원하는 xml 형식 생성
원하는 XML 형식이 Java 객체 모델과 다른 경우 XmlAdapter 구현을 사용하여 모델 객체를 XML 형식 객체로 변환하거나 그 반대로 변환 할 수 있습니다. 이 예제는 필드의 이름을 가진 요소의 속성에 필드 값을 저장하는 방법을 보여줍니다.
public class XmlAdapterExample {
@XmlAccessorType(XmlAccessType.FIELD)
public static class NodeValueElement {
@XmlAttribute(name="attrValue")
String value;
public NodeValueElement() {
}
public NodeValueElement(String value) {
super();
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public static class ValueAsAttrXmlAdapter extends XmlAdapter<NodeValueElement, String> {
@Override
public NodeValueElement marshal(String v) throws Exception {
return new NodeValueElement(v);
}
@Override
public String unmarshal(NodeValueElement v) throws Exception {
if (v==null) return "";
return v.getValue();
}
}
@XmlRootElement(name="DataObject")
@XmlAccessorType(XmlAccessType.FIELD)
public static class DataObject {
String elementWithValue;
@XmlJavaTypeAdapter(value=ValueAsAttrXmlAdapter.class)
String elementWithAttribute;
}
public static void main(String[] args) {
DataObject data = new DataObject();
data.elementWithValue="value1";
data.elementWithAttribute ="value2";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JAXB.marshal(data, baos);
String xmlString = new String(baos.toByteArray(), StandardCharsets.UTF_8);
System.out.println(xmlString);
}
}
자동 필드 / 속성 XML 매핑 구성 (@XmlAccessorType)
Annotation @XmlAccessorType
은 필드 / 속성이 자동으로 XML로 serialize되는지 여부를 결정합니다. @XmlElement
, @XmlAttribute
또는 @XmlTransient
필드 및 메소드 주석은 기본 설정보다 우선합니다.
public class XmlAccessTypeExample {
@XmlAccessorType(XmlAccessType.FIELD)
static class AccessorExampleField {
public String field="value1";
public String getGetter() {
return "getter";
}
public void setGetter(String value) {}
}
@XmlAccessorType(XmlAccessType.NONE)
static class AccessorExampleNone {
public String field="value1";
public String getGetter() {
return "getter";
}
public void setGetter(String value) {}
}
@XmlAccessorType(XmlAccessType.PROPERTY)
static class AccessorExampleProperty {
public String field="value1";
public String getGetter() {
return "getter";
}
public void setGetter(String value) {}
}
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
static class AccessorExamplePublic {
public String field="value1";
public String getGetter() {
return "getter";
}
public void setGetter(String value) {}
}
public static void main(String[] args) {
try {
System.out.println("\nField:");
JAXB.marshal(new AccessorExampleField(), System.out);
System.out.println("\nNone:");
JAXB.marshal(new AccessorExampleNone(), System.out);
System.out.println("\nProperty:");
JAXB.marshal(new AccessorExampleProperty(), System.out);
System.out.println("\nPublic:");
JAXB.marshal(new AccessorExamplePublic(), System.out);
} catch (Exception e) {
System.err.println("Exception occurred while writing in XML!");
}
}
} // outer class end
산출
Field:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleField>
<field>value1</field>
</accessorExampleField>
None:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleNone/>
Property:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleProperty>
<getter>getter</getter>
</accessorExampleProperty>
Public:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExamplePublic>
<field>value1</field>
<getter>getter</getter>
</accessorExamplePublic>
수동 필드 / 속성 XML 매핑 구성
@XmlElement
, @XmlAttribute
또는 @XmlTransient
주석과 패키지 javax.xml.bind.annotation
@XmlElement
, 프로그래머가 마크 된 필드 또는 프로퍼티를 직렬화하는 방법과 방법을 지정할 수 있도록 ( @XmlTransient
합니다.
@XmlAccessorType(XmlAccessType.NONE) // we want no automatic field/property marshalling
public class ManualXmlElementsExample {
@XmlElement
private String field="field value";
@XmlAttribute
private String attribute="attr value";
@XmlAttribute(name="differentAttribute")
private String oneAttribute="other attr value";
@XmlElement(name="different name")
private String oneName="different name value";
@XmlTransient
private String transientField = "will not get serialized ever";
@XmlElement
public String getModifiedTransientValue() {
return transientField.replace(" ever", ", unless in a getter");
}
public void setModifiedTransientValue(String val) {} // empty on purpose
public static void main(String[] args) {
try {
JAXB.marshal(new ManualXmlElementsExample(), System.out);
} catch (Exception e) {
System.err.println("Exception occurred while writing in XML!");
}
}
}
기존 데이터를 다시 사용하도록 XmlAdapter 인스턴스 지정
때로는 특정 데이터 인스턴스가 사용되어야합니다. 레크리에이션은 바람직하지 않으며 static
데이터를 참조하면 코드 냄새가납니다.
Unmarshaller
가 사용해야하는 XmlAdapter
인스턴스를 지정할 수 있습니다.이 인스턴스를 사용하면 사용자가 0 인수 생성자없이 XmlAdapter
를 사용할 수 있고 / 또는 어댑터에 데이터를 전달할 수 있습니다.
예
사용자 클래스
다음 클래스에는 이름과 사용자의 이미지가 포함됩니다.
import java.awt.image.BufferedImage;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
public class User {
private String name;
private BufferedImage image;
@XmlAttribute
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlJavaTypeAdapter(value=ImageCacheAdapter.class)
@XmlAttribute
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
}
public User(String name, BufferedImage image) {
this.name = name;
this.image = image;
}
public User() {
this("", null);
}
}
어댑터
동일한 이미지를 메모리에 두 번 생성하지 않고 데이터를 다시 다운로드하지 않으려면 어댑터가 이미지를 맵에 저장합니다.
유효한 Java 7 코드의 경우 getImage
메소드를 다음으로 대체하십시오.
public BufferedImage getImage(URL url) {
BufferedImage image = imageCache.get(url);
if (image == null) {
try {
image = ImageIO.read(url);
} catch (IOException ex) {
Logger.getLogger(ImageCacheAdapter.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
imageCache.put(url, image);
reverseIndex.put(image, url);
}
return image;
}
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class ImageCacheAdapter extends XmlAdapter<String, BufferedImage> {
private final Map<URL, BufferedImage> imageCache = new HashMap<>();
private final Map<BufferedImage, URL> reverseIndex = new HashMap<>();
public BufferedImage getImage(URL url) {
// using a single lookup using Java 8 methods
return imageCache.computeIfAbsent(url, s -> {
try {
BufferedImage img = ImageIO.read(s);
reverseIndex.put(img, s);
return img;
} catch (IOException ex) {
Logger.getLogger(ImageCacheAdapter.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
});
}
@Override
public BufferedImage unmarshal(String v) throws Exception {
return getImage(new URL(v));
}
@Override
public String marshal(BufferedImage v) throws Exception {
return reverseIndex.get(v).toExternalForm();
}
}
XML 예제
다음 2 개의 xml은 Jon Skeet 과 그의 지구 2에 해당합니다. 둘 다 동일하게 보이므로 동일한 아바타를 사용합니다.
<?xml version="1.0" encoding="UTF-8"?>
<user name="Jon Skeet" image="https://www.gravatar.com/avatar/6d8ebb117e8d83d74ea95fbdd0f87e13?s=328&d=identicon&r=PG"/>
<?xml version="1.0" encoding="UTF-8"?>
<user name="Jon Skeet (Earth 2)" image="https://www.gravatar.com/avatar/6d8ebb117e8d83d74ea95fbdd0f87e13?s=328&d=identicon&r=PG"/>
어댑터 사용
ImageCacheAdapter adapter = new ImageCacheAdapter();
JAXBContext context = JAXBContext.newInstance(User.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
// specifiy the adapter instance to use for every
// @XmlJavaTypeAdapter(value=ImageCacheAdapter.class)
unmarshaller.setAdapter(ImageCacheAdapter.class, adapter);
User result1 = (User) unmarshaller.unmarshal(Main.class.getResource("user.xml"));
// unmarshal second xml using the same adapter instance
Unmarshaller unmarshaller2 = context.createUnmarshaller();
unmarshaller2.setAdapter(ImageCacheAdapter.class, adapter);
User result2 = (User) unmarshaller2.unmarshal(Main.class.getResource("user2.xml"));
System.out.println(result1.getName());
System.out.println(result2.getName());
// yields true, since image is reused
System.out.println(result1.getImage() == result2.getImage());
XML 네임 스페이스를 직렬화 가능 Java 클래스에 바인딩합니다.
이것은 XML 네임 스페이스를 직렬화 가능 Java 클래스에 바인드하는 package-info.java
파일의 예입니다. 이것은 네임 스페이스를 사용하여 직렬화되어야하는 Java 클래스와 동일한 패키지에 있어야합니다.
/**
* A package containing serializable classes.
*/
@XmlSchema
(
xmlns =
{
@XmlNs(prefix = MySerializableClass.NAMESPACE_PREFIX, namespaceURI = MySerializableClass.NAMESPACE)
},
namespace = MySerializableClass.NAMESPACE,
elementFormDefault = XmlNsForm.QUALIFIED
)
package com.test.jaxb;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
XmlAdapter를 사용하여 문자열을 자릅니다.
package com.example.xml.adapters;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringTrimAdapter extends XmlAdapter<String, String> {
@Override
public String unmarshal(String v) throws Exception {
if (v == null)
return null;
return v.trim();
}
@Override
public String marshal(String v) throws Exception {
if (v == null)
return null;
return v.trim();
}
}
그리고 package-info.java에 다음 선언을 추가하십시오.
@XmlJavaTypeAdapter(value = com.example.xml.adapters.StringTrimAdapter.class, type = String.class)
package com.example.xml.jaxb.bindings;// Packge where you intend to apply trimming filter
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;