2
votes

My problem seems pretty simple, yet I was unable to find anything exactly like it on stackoverflow.

I'm using jaxb to marshall/unmarshall this object:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "root")
public class MyJaxbObject implements Serializable
{

    @XmlElement(name = "DELETE")
    @XmlJavaTypeAdapter(BooleanIntAdapter.class)
    private Boolean delete;

    @XmlElement(name = "message")
    private String message;

     constructors.. getters... setters...
}

My BooleanAdapter is a simple XmlAdapter<Integer, Boolean> that turns true/false to 1/0 and back.

Unmarshalling works, but marshalling does not. it always yeilds this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <DELETE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.or/2001/XMLSchema" xsi:type="xs:boolean">true</DELETE>
    <message>***DONE***</message>
</root>

When I change the xml element config to @XmlElement(name = "DELETE",type = Boolean.class) unmarshalling of the boolean fails and marshalling yields this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <DELETE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:int">1</DELETE>
    <message>***DONE***</message>
</root>

I put simple print messages in the marshal/unmarshal methods of the xml adapter and tried to marshal/unmarshal this kind of object.

I saw that without type declaration unmarshal method is called but marshal is not. With the type declaration only marshal is called.

Help?? How can I marshal/unmarshal my Boolean to/from {1,0} and possibly get rid of the xsi:type in the marshalled xml?

Edit - this is the code i used to test marshal/unmarshal:

    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    JAXBContext context = javax.xml.bind.JAXBContext.newInstance("my.package.classes");
    Unmarshaller unmarshal = context.createUnmarshaller();
    Marshaller marshal = context.createMarshaller();
    marshal.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

    String str = "<root><DELETE>1</DELETE><message>***DONE***</message></root>";
    DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
    Document d = null;
    d = builder.parse(new InputSource(new StringReader(str)));

    MyJaxbObject myJaxUnmarsh = unmarshal.unmarshal(d.getFirstChild(), MyJaxbObject.class).getValue();
    System.out.println(myJaxUnmarsh.getMessage() + " , " + myJaxUnmarsh.getDelete());

    MyJaxbObject myJax = new MyJaxbObject();
    myJax.setDelete(true);
    myJax.setMessage("***DONE***");
    marshal.marshal(myJax, System.out);
2
UPDATE: I opened a new project to test this issue and it worked flawlessly. So it must be some dependency in my project that's overriding something in JAXB behavior and causing this problem. I'm using maven and can provide the pom.xml. but before, does anyone have any knowledge of what libraries can interfere with jaxb operation?samz
FOUND THE CULPRIT - its cxf lib: cxf-rt-core. going to check if there are known issues with this and jaxb. will post an update when i find a fix.samz

2 Answers

2
votes

With the following implementation of BooleanIntAdapter:

BooleanIntAdapter

package forum9380680;

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

public class BooleanIntAdapter extends XmlAdapter<Integer, Boolean> {

    @Override
    public Boolean unmarshal(Integer v) throws Exception {
        return v.equals(1);
    }

    @Override
    public Integer marshal(Boolean v) throws Exception {
        if(v) {
            return 1;
        } else {
            return 0;
        }
    }

}

Output

I get the following output:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <DELETE>1</DELETE>
   <message>***DONE***</message>
</root>

Below is the rest of the code I used:

Demo

package forum9380680;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

public class Demo {

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

        MyJaxbObject object = new MyJaxbObject();
        object.setDelete(true);
        object.setMessage("***DONE***");

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(object, System.out);
    }

}

MyJaxbObject

package forum9380680;

import java.io.Serializable;

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "root")
public class MyJaxbObject implements Serializable
{

    @XmlElement(name = "DELETE")
    @XmlJavaTypeAdapter(BooleanIntAdapter.class)
    private Boolean delete;

    @XmlElement(name = "message")
    private String message;

    public Boolean getDelete() {
        return delete;
    }

    public void setDelete(Boolean delete) {
        this.delete = delete;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}
0
votes

found the problem:

CXF pom makes the project use jaxb-impl version 2.1.0. Without CXF the project uses the JDK default which was 2.1.10 in my case. see: http://jaxb.java.net/guide/Which_JAXB_RI_is_included_in_which_JDK_.html

I added the following under dependency management to fix the problem

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.2.5</version>
    <type>jar</type>
    <scope>compile</scope>
</dependency>