17

I have a binding file like this

<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <jxb:bindings schemaLocation="example.xsd" node="/xs:schema">
    <jxb:schemaBindings>
        <jxb:package name="example" />
    </jxb:schemaBindings>
    <jxb:globalBindings>
        <jxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
            parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
            printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
        <jxb:javaType name="java.util.Calendar" xmlType="xs:date"
            parseMethod="javax.xml.bind.DatatypeConverter.parseDate"
            printMethod="javax.xml.bind.DatatypeConverter.printDate" />
        <jxb:javaType name="java.util.Calendar" xmlType="xs:time"
            parseMethod="javax.xml.bind.DatatypeConverter.parseTime"
            printMethod="javax.xml.bind.DatatypeConverter.printTime" />
    </jxb:globalBindings>

  </jxb:bindings>
</jxb:bindings>

The schema class are generated in "example" (correct), but the XmlAdapters in "org.w3._2001.xmlschema" (wrong). How can I fix this?

G_H
  • 11,739
  • 3
  • 38
  • 82
Puce
  • 37,247
  • 13
  • 80
  • 152

5 Answers5

12

For Apache CXF users, the cleanest way is to use the -p option offered by wsdl2java.

-p [wsdl-namespace=]PackageName

Specifies zero, or more, package names to use for the generated code. Optionally specifies the WSDL namespace to package name mapping.

In our case

-p http://www.w3.org/2001/XMLSchema=org.acme.foo

If you use the cxf-codegen-plugin, then just add another pair of <extraarg>.

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>${cxf.version}</version>
        [...]
    <extraarg>-p</extraarg>
    <extraarg>http://www.w3.org/2001/XMLSchema=org.acme.foo</extraarg>
        [...]
</plugin>

No need for a targetNamespace pointing at the reserved XSD namespace and no need for catch-all jaxb package binding.

Alain Pannetier
  • 9,315
  • 3
  • 41
  • 46
  • 1
    Note if you have multiple WSDL's, and specify the same package for all of them, then you can still run into issues due to anonymous naming ("Adapter org.w3._2001.xmlschema.Adapter4 is not applicable to the field type java.lang.Integer", which is what led me here). However, if you specify a _different_ package, you resolve the issue, but then you have multiple copies of the same adapters in different packages (possibly with different names), which doesn't feel terribly elegant. I used John Zhang's solution below (but copying the previously auto-generated Adapters as a starting point). – DarthPablo Jun 29 '17 at 10:35
12

The better way to use GlobalBinding is to specify explicit adapter instead of using this parse/print pair. For example, instead of the following:

<jaxb:javaType name="java.lang.Long" xmlType="xs:long"
                      parseMethod="com.mypackage.myclass.parseLong"
                  printMethod="com.mypackage.myclass.print"/>

Instead, you should:

<xjc:javaType name="java.lang.Long" xmlType="xs:long"
                  adapter="com.mypackage.LongAdapter"/>

Remember to add namespace for xjc:

xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
          jxb:extensionBindingPrefixes="xjc"

The class LongAdapter would be like this:

public class LongAdapter
extends XmlAdapter<String, Long>
{


public Long unmarshal(String value) {
    return your_util_class.parseLong(value);
}

public String marshal(Long value) {
    return your_util_class.print(value);
}

}

In this way, since you specified adapter classes explicitely, jaxb won't generate default adapters with the default package name org.w3._2001.xmlschema.

It is very important to avoid to use the default package name org.w3._2001.xmlschema. Taking one example, if you have one project A and one project B, and both of them have some schema and bindings. In the old way, both of them generate adapters with exactly the same full qualified names, e.g. org.w3._2001.xmlschema.Adapter1. However, this adapter might be for Long in project A and for Integer in project B. Then, let's say you have a downstream project C using both A and B. Now the problem gets nasty. If C needs to use Adapter1, you cannot predict the used one is from A for Long or from B for Integer. Then, your application C might work fine in some time but maybe fail in a strange way in some other situations. If this happens, the type exception would be like:

org.w3._2001.xmlschema.Adapter1 is not applicable to the field type java.lang.Double...

The solution mentioned by Roy Truelove seems not working when I tried it in my environment with maven-jaxb2-plugin even if the theory is correct.

John Zhang
  • 1,043
  • 2
  • 13
  • 22
11

The org.w3._2001.xmlschema package is created here because XJC has to generate a class that extends javax.xml.bind.annotation.adapters.XmlAdapter, which in turn calls your parse/print static methods. For some reason, it puts them into this package, rather than somewhere more useful.

You haven't said which JAXB implementation you use, but the JAXB RI has an extension to the javaType binding customization which allows you to specify a subclass of XmlAdapter directly, rather than parseMethod/printMethod pairs. This removes the need to generate the synthetic XmlAdapter bridge class. See the RI docs for how to do this.

I imagine EclipseLink/Moxy has something similar to this, but I'm not sure if the XJC that ships with Java6 is capable of it (Sun seems to have removed half of the useful stuff from the RI when they brought it into the JRE).

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • I'm using Java SE 6 u24 and the following Maven plugin: org.jvnet.jaxb2.maven2 maven-jaxb2-plugin 0.7.5 So I think it's JAXB 2.1 – Puce Mar 17 '11 at 14:06
  • I'm fine with the generated adapters (since they are only used internatlly), but I want them in the same package as the other generated classes. – Puce Mar 17 '11 at 14:13
  • If I would use a custom hand-written adapter. Would this be possible with JAXB 2.1? Maybe by defining an extension for the Maven plugin somehow (custom extensions are supported, I used that before). Also I want to define the customization in an external binding file rather than the XSD (the link you provided shows how to do this directly in an XSD.) How can do this with an XJB file and Maven? – Puce Mar 17 '11 at 14:18
  • Good instructions for this approach: http://blog.steveperkins.info/2011/01/changing-jaxb-generated-adapter-classes/ (I added a comment with an example DateAdapter implementation). – penfold Nov 14 '13 at 09:47
8

I had this problem as well, solved it using this.

The basic premise is that you include a schema in your XJC compilation with following contents:

<schema xmlns="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.w3.org/2001/XMLSchema"
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
  jaxb:version="2.0">
  <annotation><appinfo>
    <jaxb:schemaBindings>
      <jaxb:package name="org.acme.foo"/>
    </jaxb:schemaBindings>
  </appinfo></annotation>
</schema>

You then adjust the package name to where you want the generated adapters to be placed. XJC will believe that this schema is part of the schema set for W3C XML Schema itself and will honour the bindings in it.

G_H
  • 11,739
  • 3
  • 38
  • 82
Roy Truelove
  • 22,016
  • 18
  • 111
  • 153
  • I haven't tried it yet, but since the tip is in the (un)official JAXB guide, I guess this is the way to go. Thnaks. – Puce Sep 06 '11 at 23:15
  • Link now leads to github where that anchor isn't found. Prime example as to why link-only answers aren't worth anything. – Scorpio Feb 22 '18 at 10:32
  • 1
    @Scorpio Very true. Fortunately the link has been updated. I've edited the answer to include the essentials in it to avoid this in the future. – G_H Apr 10 '19 at 14:04
0

Use the built in converters for common datatypes.

<jxb:javaType name="java.lang.Integer" xmlType="xs:integer"              
parseMethod="javax.xml.bind.DatatypeConverter.parseInt"                  
printMethod="javax.xml.bind.DatatypeConverter.printInt" />
wozza xing
  • 51
  • 1
  • 1