Как указать адаптер (ы), которые JAXB использует для маршалинга / демаршалинга данных? - PullRequest
9 голосов
/ 11 мая 2011

Есть ли способ указать Адаптер, который JAXB использует для маршалинга / демаршалинга объектов в моей схеме XML?

Например, если я хочу проанализировать следующее как целое число:

<SpecialValue>0x1234</SpecialValue>

Я могу использовать в своей схеме следующее:

<xs:simpleType name="HexInt">
    <xs:annotation> 
        <xs:appinfo>
            <jaxb:javaType name="int" parseMethod="Integer.decode" />
        </xs:appinfo>
    </xs:annotation>  
    <xs:restriction base="xs:string">
        <xs:pattern value="0x[0-9a-fA-F]+" />
    </xs:restriction>
</xs:simpleType>
<xs:element name="SpecialValue" type="HexInt" />

Когда я запускаю схему с помощью инструмента XJC, строка «0x1234» должна быть декодирована с использованием Integer.decode () в качестве целого числа со значением0x1234 или 4660 в десятичном виде.Созданный класс Adapter отражает это должным образом:

public Integer unmarshal(String value) {
    return (Integer.decode(value));
}

Однако, когда я хочу перенаправить значение обратно в элемент XML (который является литералом String), класс Adapter выполняет следующее:

public String marshal(Integer value) {
    if (value == null) {
        return null;
    }
    return value.toString();
}

В этом случае строковое значение целого числа 0x1234 (4660 в десятичном виде) равно "4660", что не соответствует моей схеме (поскольку у него нет префикса "0x").

Как я могу сказать адаптеру, что я хочу, чтобы целое число 0x1234 маршалировалось как строковый литерал "0x1234"?Я хотел бы иметь возможность делать это в схеме, чтобы я мог просто генерировать новые классы Java без необходимости изменять вывод.Возможно ли это?

Редактировать: Основываясь на принятом ответе, вот что я сделал, чтобы получить эту работу:

Я написал метод в классе com.example.Parse вызвал toHexString ():

public static String toHexString(int value)
{
    return ("0x" + Integer.toHexString(value));
}

Затем я указал моей схеме на этот метод для печати:

<xs:simpleType name="HexInt">
    <xs:annotation> 
        <xs:appinfo>
            <jaxb:javaType name="int" parseMethod="Integer.decode" printMethod="com.example.Parse.toHexString" />
        </xs:appinfo>
    </xs:annotation>  
    <xs:restriction base="xs:string">
        <xs:pattern value="0x[0-9a-fA-F]+" />
    </xs:restriction>
</xs:simpleType>

Ответы [ 3 ]

8 голосов
/ 14 июля 2013

Очень похожая проблема: «Как сопоставить строковые координаты с java.awt.Point?»

(0) Схема

<xsd:simpleType name="Point">
    <xsd:restriction base="xsd:string">
        <xsd:pattern value="([0-9])+,([0-9])+" />
    </xsd:restriction>
</xsd:simpleType>

<xsd:complexType name="HexAreaBorder">
    <xsd:sequence minOccurs="1" maxOccurs="1">
        <xsd:element minOccurs="1" maxOccurs="1" name="type" type="xsd:string" />
        <xsd:element minOccurs="1" maxOccurs="1" name="name" type="xsd:string" />
        <xsd:element name="points" type="Point" minOccurs="1" maxOccurs="unbounded" />
    </xsd:sequence>
</xsd:complexType>

(1) Создать класс адаптера, расширяющий XmlAdapter.

package com.kjcode.hexgrid.jaxbadapter;
import java.awt.Point;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class PointAdapter extends XmlAdapter<String, Point> {

    @Override
    public Point unmarshal(String v) throws Exception {
        String[] coords = v.split(",");
        return new Point(Integer.parseInt(coords[0]), Integer.parseInt(coords[1]));
    }

    @Override
    public String marshal(Point v) throws Exception {
        return String.format("%d,%d", v.x, v.y);
    }
}

(2) Создать файл привязок. Ключ должен добавить: jaxb: extensionBindingPrefixes = "xjc" xmlns: xjc = "http://java.sun.com/xml/ns/jaxb/xjc"

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    jaxb:extensionBindingPrefixes="xjc" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    xmlns="hexmap" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    jaxb:version="2.1">

    <jaxb:bindings schemaLocation="hexmap.xsd">
        <jaxb:globalBindings>
            <xjc:javaType adapter="com.kjcode.hexgrid.jaxbadapter.PointAdapter" name="java.awt.Point" xmlType="Point" />
        </jaxb:globalBindings>
    </jaxb:bindings>
</jaxb:bindings>

(3) Настроить pom.xml

<plugin>
    <groupId>com.sun.tools.xjc.maven2</groupId>
    <artifactId>maven-jaxb-plugin</artifactId>
    <version>1.1.1</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <generatePackage>com.kjcode.hexmap.api.logic.field.generated</generatePackage>
        <extension>true</extension>
    </configuration>
</plugin>

(4) JAXB сгенерирует

public class HexAreaBorder {

    @XmlElement(required = true)
    protected String type;
    @XmlElement(required = true)
    protected String name;
    @XmlElement(required = true, type = String.class)
    @XmlJavaTypeAdapter(PointAdapter.class)
    protected List<Point> points = new LinkedList<Point>();
6 голосов
/ 11 мая 2011

Попробуйте это

<jaxb:javaType name="int" parseMethod="Integer.decode" 
                          printMethod="Integer.toHexString"/>

Я еще не проверял это, но я помню, что использовал что-то очень похожее.

0 голосов
/ 11 мая 2011

Вы хотите пользовательский адаптер.Вот публикация, которая имеет дело с пользовательским логическим результатом, но может быть применена и к вашему сценарию.

Кроме того, вот документация по API для JAXB XmlAdapter: http://jaxb.java.net/nonav/2.1/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...