Java-код для XML/XSD без использования аннотации

Мне нужно, чтобы маршал и unmarshall Java-класс для XML. Класс, который мне не принадлежит, что я не могу добавить анотации, чтобы использовать JAXB.

Есть ли хороший способ конвертировать Java в XML с данным противопоставлением?

Кроме того, подумал, что инструмент может быть полезен, но я бы более интересовался тем, что есть некоторый Java API, чтобы сделать то же самое.

Ответ 1

Примечание. Я EclipseLink JAXB (MOXy) и член группы JAXB (JSR-222).

DOMAIN MODEL

Я буду использовать следующую модель домена для этого ответа. Обратите внимание, что в модели нет аннотаций JAXB.

Клиент

package forum11693552;

import java.util.*;

public class Customer {

    private String firstName;
    private String lastName;
    private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public List<PhoneNumber> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }

}

PhoneNumber

package forum11693552;

public class PhoneNumber {

    private String type;
    private String number;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

}

ВАРИАНТ № 1 - реализация любого JAXB (JSR-222)

JAXB является конфигурацией по исключению, это означает, что вам нужно добавить примечания, в которых вы хотите, чтобы поведение отображения отличалось от значения по умолчанию. Ниже приведена ссылка на пример, демонстрирующий, как использовать любой JAXB impl без аннотаций:

Demo

package forum11693552;

import javax.xml.bind.*;
import javax.xml.namespace.QName;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        Customer customer = new Customer();
        customer.setFirstName("Jane");
        customer.setLastName("Doe");

        PhoneNumber workPhone = new PhoneNumber();
        workPhone.setType("work");
        workPhone.setNumber("555-1111");
        customer.getPhoneNumbers().add(workPhone);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        JAXBElement<Customer> rootElement = new JAXBElement<Customer>(new QName("customer"), Customer.class, customer);
        marshaller.marshal(rootElement, System.out);
    }

}

Выход

<customer>
    <firstName>Jane</firstName>
    <lastName>Doe</lastName>
    <phoneNumbers>
        <number>555-1111</number>
        <type>work</type>
    </phoneNumbers>
</customer>

Дополнительная информация


ВАРИАНТ # 2 - Внешний документ сопоставления EclipseLink JAXB (MOXy)

Если вы хотите настроить сопоставления, вы можете быть заинтересованы в расширении внешнего документа MOXy. Пример документа сопоставления выглядит следующим образом:

oxm.xml

<?xml version="1.0"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum11693552">
    <java-types>
        <java-type name="Customer">
            <xml-root-element />
            <java-attributes>
                <xml-element java-attribute="firstName" name="first-name" />
                <xml-element java-attribute="lastName" name="last-name" />
                <xml-element java-attribute="phoneNumbers" name="phone-number" />
            </java-attributes>
        </java-type>
        <java-type name="PhoneNumber">
            <java-attributes>
                <xml-attribute java-attribute="type" />
                <xml-value java-attribute="number" />
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

jaxb.properties

Чтобы включить MOXy в качестве вашего провайдера JAXB, вам необходимо включить файл с именем jaxb.properties в том же пакете, что и ваша модель домена, со следующей записью (см.: <а3 > ):

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Demo

При использовании EclipseLink MOXy в качестве поставщика JAXB (см.) вы можете использовать внешний файл сопоставления при загрузке JAXBContext

package forum11693552;

import java.util.*;
import javax.xml.bind.*;
import javax.xml.namespace.QName;
import org.eclipse.persistence.jaxb.JAXBContextFactory;

public class Demo {

    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String,Object>(1);
        properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum11693552/oxm.xml");
        JAXBContext jc = JAXBContext.newInstance(new Class[] {Customer.class}, properties);

        Customer customer = new Customer();
        customer.setFirstName("Jane");
        customer.setLastName("Doe");

        PhoneNumber workPhone = new PhoneNumber();
        workPhone.setType("work");
        workPhone.setNumber("555-1111");
        customer.getPhoneNumbers().add(workPhone);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        JAXBElement<Customer> rootElement = new JAXBElement<Customer>(new QName("customer"), Customer.class, customer);
        marshaller.marshal(rootElement, System.out);
    }

}

Выход

<?xml version="1.0" encoding="UTF-8"?>
<customer>
   <first-name>Jane</first-name>
   <last-name>Doe</last-name>
   <phone-number type="work">555-1111</phone-number>
</customer>

Дополнительная информация

Ответ 2

Вы посмотрели XStream? Он будет deserialise/deserialise стандартного POJO без аннотаций или XSD. Вы можете настроить персонализацию, чтобы повлиять на то, как элементы отображаются в XML и в значительной степени работают из коробки.

Ответ 3

Вы можете написать пользовательские XmlAdapter и аннотировать поля ограниченного типа с помощью аннотации XmlJavaTypeAdapter. Основы будут примерно такими:

public enum CannotBeAnnotated { value1, value2; }
@XmlRootElement(name="client")
public class ClientClass {
    @XmlJavaTypeAdapter(Bridge.class)
    public CannotBeAnnotated;
}
@XmlRootElement(name="representation")
public class XmlType {
    @XmlValue
    public String value;
}
public class Bridge extends XmlAdapter<XmlType, CannotBeAnnotated>{
    public XmlType marshal(CannotBeAnnotated c) {
        XmlType x=new XmlType(); 
        x.value=c.name();
        return x;
    }
    public CannotBeAnnotated unmarshall(XmlType x) {
        return CannotBeAnnotated.valueOf(x.value);
    }
}

Конечно, для перечислений это не было бы полезно, поскольку JAXB знает, как с ними бороться. Я просто выбрал перечисление для простоты, чтобы вы могли видеть идею:

  • Создайте представление XML, которое вы контролируете
  • Напишите адаптер, преобразующий этот тип Java в желаемый тип
  • Аннотировать "клиентский" код, ссылающийся на адаптер для желаемого типа.
  • Profit.