How to handle forward references of XML IDREF with JAXB XmlAdapter during unmarshal?

前端 未结 1 668
执笔经年
执笔经年 2020-12-11 08:25

Is it possible to handle forward references of XML IDREF elements in JAXB XmlAdapter during the unmarshal process? For example, I have the followin

相关标签:
1条回答
  • 2020-12-11 08:38

    I have an answer to your related question I outlined how an XmlAdapter could be used to implement the use case where the first occurrence of an object was marshalled via containment/nesting and all other occurrences were marshalled by reference:

    • Can JAXB marshal by containment at first then marshal by @XmlIDREF for subsequent references?

    Option #1 - @XmlID/@XmlIDREF

    If all of your Person objects are all represented through nesting and you want to introduce some key based relationships then you are best of using @XmlID to mark a field/property as the key, and @XmlID to map a field/property as a foreign key. Your Person class would look something like:

    @XmlAccessorType(XmlAccessType.FIELD)
    public class Person {
    
        @XmlID
        private String id;
    
        @XmlIDREF
        private Person guardian;
    }
    

    For More Information

    • http://blog.bdoughan.com/2010/10/jaxb-and-shared-references-xmlid-and.html

    Option #2 - Using XmlAdapter

    If you updated the XmlAdapter from my previous answer to be:

    package forum7587095;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlSeeAlso;
    import javax.xml.bind.annotation.XmlType;
    import javax.xml.bind.annotation.adapters.XmlAdapter;
    
    public class PhoneNumberAdapter extends XmlAdapter<PhoneNumberAdapter.AdaptedPhoneNumber, PhoneNumber>{
    
        private List<PhoneNumber> phoneNumberList = new ArrayList<PhoneNumber>();
        private Map<String, PhoneNumber> phoneNumberMap = new HashMap<String, PhoneNumber>();
    
        @XmlSeeAlso(AdaptedWorkPhoneNumber.class)
        @XmlType(name="phone-number")
        public static class AdaptedPhoneNumber {
            @XmlAttribute public String id;
            public String number;
    
            public AdaptedPhoneNumber() {
            }
    
            public AdaptedPhoneNumber(PhoneNumber phoneNumber) {
                id = phoneNumber.getId();
                number = phoneNumber.getNumber();
            }
    
            public PhoneNumber getPhoneNumber() {
                PhoneNumber phoneNumber = new PhoneNumber();
                phoneNumber.setId(id);
                phoneNumber.setNumber(number);
                return phoneNumber;
            }
    
        }
    
        @XmlType(name="work-phone-number")
        public static class AdaptedWorkPhoneNumber extends AdaptedPhoneNumber {
    
            public String extension;
    
            public AdaptedWorkPhoneNumber() {
            }
    
            public AdaptedWorkPhoneNumber(WorkPhoneNumber workPhoneNumber) {
                super(workPhoneNumber);
                extension = workPhoneNumber.getExtension();
            }
    
            @Override
            public WorkPhoneNumber getPhoneNumber() {
                WorkPhoneNumber phoneNumber = new WorkPhoneNumber();
                phoneNumber.setId(id);
                phoneNumber.setNumber(number);
                phoneNumber.setExtension(extension);
                return phoneNumber;
            }
    }
    
        @Override
        public AdaptedPhoneNumber marshal(PhoneNumber phoneNumber) throws Exception {
            AdaptedPhoneNumber adaptedPhoneNumber;
            if(phoneNumberList.contains(phoneNumber)) {
                if(phoneNumber instanceof WorkPhoneNumber) {
                    adaptedPhoneNumber = new AdaptedWorkPhoneNumber();
                } else {
                    adaptedPhoneNumber = new AdaptedPhoneNumber();
                }
                adaptedPhoneNumber.id = phoneNumber.getId();
            } else {
                if(phoneNumber instanceof WorkPhoneNumber) {
                    adaptedPhoneNumber = new AdaptedWorkPhoneNumber((WorkPhoneNumber)phoneNumber);
                } else {
                    adaptedPhoneNumber = new AdaptedPhoneNumber(phoneNumber);
                }
                phoneNumberList.add(phoneNumber);
            }
            return adaptedPhoneNumber;
        }
    
        @Override
        public PhoneNumber unmarshal(AdaptedPhoneNumber adaptedPhoneNumber) throws Exception {
            PhoneNumber phoneNumber = phoneNumberMap.get(adaptedPhoneNumber.id);
            if(null != phoneNumber) {
                if(adaptedPhoneNumber.number != null) {
                    phoneNumber.setNumber(adaptedPhoneNumber.number);
                }
                return phoneNumber;
            }
            phoneNumber = adaptedPhoneNumber.getPhoneNumber();
            phoneNumberMap.put(phoneNumber.getId(), phoneNumber);
            return phoneNumber;
        }
    
    }
    

    Then you will be able to unmarshal XML documents that look like the following where the reference happens first:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <customer>
        <phone-number id="A"/>
        <phone-number id="B">
            <number>555-BBBB</number>
        </phone-number>
        <phone-number id="A">
            <number>555-AAAA</number>
        </phone-number>
        <phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W">
            <number>555-WORK</number>
            <extension>1234</extension>
        </phone-number>
        <phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"/>
    </customer>
    
    0 讨论(0)
提交回复
热议问题