수색…


소개

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 SE 7

유효한 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&amp;d=identicon&amp;r=PG"/>
<?xml version="1.0" encoding="UTF-8"?>

<user name="Jon Skeet (Earth 2)" image="https://www.gravatar.com/avatar/6d8ebb117e8d83d74ea95fbdd0f87e13?s=328&amp;d=identicon&amp;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;


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow