4

I'm executing a Maven Project with the below source

package com.coderplus.jaxb;

import java.util.HashMap;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlJavaTypeAdapter(PropertiesMapAdapter.class)
public class PropertiesMap<K,V> extends HashMap<String,String>
{

}

..

package com.coderplus.jaxb;

import java.util.Map.Entry;

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


public class PropertiesMapAdapter extends
        XmlAdapter<Properties, PropertiesMap<String, String>> {

    @Override
    public PropertiesMap<String, String> unmarshal(Properties properties)
            throws Exception {
        PropertiesMap<String, String> retVal = new PropertiesMap<String, String>();
        if (null != properties) {
            for (Property param : properties.getProperty()) {
                retVal.put(param.getName(), param.getValue());
            }
        }
        return retVal;
    }

    @Override
    public Properties marshal(PropertiesMap<String, String> propertiesMap)
            throws Exception {
        Properties properties = new Properties();
        if (propertiesMap != null) {
            for (Entry<String, String> entry : propertiesMap.entrySet()) {
                Property param = new Property();
                param.setName(entry.getKey());
                param.setValue(entry.getValue());
                properties.getProperty().add(param);
            }
        }
        return properties;
    }
}

..

package com.coderplus.jaxb;  
import javax.xml.bind.*;


public class Demo {

    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);
        Root root = new Root();
        PropertiesMap map = new PropertiesMap();
        map.put("hello", "World");
        map.put("name", "value");
        root.setProperties(map);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

}

...

Schema in src/main/resources

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xd="http://www.w3.org/2001/XMLSchema">
    <xsd:complexType name="Properties">
        <xsd:sequence>
            <xsd:element name="Property" type="Property" minOccurs="0"
                maxOccurs="unbounded" />
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="Property">
        <xsd:simpleContent>
            <xsd:extension base="xsd:string">
                <xsd:attribute name="name" type="xsd:string" />
            </xsd:extension>
        </xsd:simpleContent>
    </xsd:complexType>

    <xsd:element name="Root">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="Properties" type="Properties" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema> 

Binding file in src/main/resources

<jaxb:bindings version="2.0"
        xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
        xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <jaxb:bindings schemaLocation="map.xsd">
        <jaxb:bindings node="//xs:element[@name='Properties']">
            <jaxb:property>
                <jaxb:baseType name="com.coderplus.jaxb.PropertiesMap&lt;String,String&gt;" />
            </jaxb:property>
        </jaxb:bindings>
    </jaxb:bindings>
</jaxb:bindings>

and finally the pom file

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.coderplus.jaxb</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.9.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <generatePackage>com.coderplus.jaxb</generatePackage>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

The Demo Class produces the below output when I execute it using JDK 1.6

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
    <Properties>
        <Property name="hello">World</Property>
        <Property name="name">value</Property>
    </Properties>
</Root>

but for some reason, it generates the below with JDK 1.7 and up (newer JAXB?)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
    <properties>
        <entry>
            <key xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">hello</key>
            <value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">World</value>
        </entry>
        <entry>
            <key xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">name</key>
            <value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">value</value>
        </entry>
    </properties>
</Root>

How can I get it working on JDK 1.7 or the newer version of JAXB?

Some More Info:

The maven-jaxb2-plugin generates the below class along with others

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "properties"
})
@XmlRootElement(name = "Root")
public class Root {

    @XmlElement(name = "Properties", required = true, type = Properties.class)
    protected PropertiesMap<String, String> properties;

    public PropertiesMap<String, String> getProperties() {
        return properties;
    }

    public void setProperties(PropertiesMap<String, String> value) {
        this.properties = value;
    }

}

If I manually go in and add the annotation @XmlJavaTypeAdapter(PropertiesMapAdapter.class) like in the code below, then it works

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "properties"
})
@XmlRootElement(name = "Root")
public class Root {

    @XmlElement(name = "Properties", required = true, type = Properties.class)
    @XmlJavaTypeAdapter(PropertiesMapAdapter.class)
    protected PropertiesMap<String, String> properties;

    public PropertiesMap<String, String> getProperties() {
        return properties;
    }

    public void setProperties(PropertiesMap<String, String> value) {
        this.properties = value;
    }

}

How can I make the maven-jaxb2-plugin to add the XmlJavaTypeAdapter automatically? In case it would help, this link has the zipped Maven Project

user1516873
  • 5,060
  • 2
  • 37
  • 56
coderplus
  • 5,793
  • 5
  • 34
  • 54

1 Answers1

0

Try adding the xjc:javaType customization.

<xjc:javaType name="org.acme.foo.PropertiesMap"
 adapter="org.acme.foo.PropertiesMapAdapter"/>
lexicore
  • 42,748
  • 17
  • 132
  • 221
  • I had tried that, but if gives a "compiler was unable to honor this conversion customization..." error.Seems like it will only work with simpleTypes? – coderplus Sep 22 '14 at 18:22
  • Hm, maybe. Not sure. Ok, now the last and most powerful. Annotate plugin can annotate anything with anything for you: http://confluence.highsource.org/display/J2B/Annotate+Plugin – lexicore Sep 22 '14 at 18:25
  • I have been working on the annotate plugin for a couple of days and finally got it to work today. It seems that annotate doesn't work for complex XPaths with ref attributes(at least in my case). Amended the schema to get this sorted. Thank a lot :-) – coderplus Sep 23 '14 at 11:04
  • Please file an issue on github with the case that does not work. – lexicore Sep 23 '14 at 11:05
  • sure, will create a dummy example and file a case. Thanks again :) – coderplus Sep 23 '14 at 11:08
  • @coderplus Please send me a PR with your test case: https://github.com/highsource/jaxb2-annotate-plugin/tree/master/tests – lexicore Sep 26 '14 at 08:27