开发者

How do I specify the adapter(s) which JAXB uses for marshaling/unmarshaling data?

开发者 https://www.devze.com 2023-03-04 04:08 出处:网络
Is there a way to specify the Adapter which JAXB uses for marshaling/unmarshaling objects in my XML schema?

Is there a way to specify the Adapter which JAXB uses for marshaling/unmarshaling objects in my XML schema?

For example, if I want to parse the following as an integer:

<SpecialValue>0x1234</SpecialValue>

I can use the following in my schema:

<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" />

When I run the schema through the XJC tool, the String "0x1234" should be decoded using Integer.decode() as the Integer with value 0x1234, or 4660 in decimal. The Adapter class that is generated reflects this properly:

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

However, when I want to marshal the value back to an XML element (which is a String literal), the Adapter class does the following:

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

In this case, the String value of the integer 0x1234 (4660 in decimal) is "4660", which does not adhere to my schema (because it has no "0x" prefix).

How can I开发者_如何学Go tell the Adapter that I want the integer 0x1234 to be marshalled as the "0x1234" String literal? I would be like to be able to do this within the schema so that I can just generate new Java classes without having to modify the output. Is this possible?

Edit: Based on the accepted answer, here is what I did to get this working:

I wrote a method in a class com.example.Parse called toHexString():

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

Then I pointed my schema to that method for printing:

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


Very similar problem: "How to map String coordinates to java.awt.Point ?"

(0) Schema

<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) Create adapter class that extends 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) Create bindings file. The key is to add: 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) Configure 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 will generate

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>();


Try this

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

I haven't tested it though but I remember using something very similar.


You want a custom Adapter. Here's a post that deals with a custom boolean result, but could be applied to your scenario as well.

In addition, here's the API documentation for JAXB's XmlAdapter: http://jaxb.java.net/nonav/2.1/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html

Hope this helps!

0

精彩评论

暂无评论...
验证码 换一张
取 消