Search code examples
arraysjaxbbytejaxb2unmarshalling

jaxb2Marshaller unmarshals XML into an empty byte arra


here's the problem. I'm using Spring 3.0.4 to create a rest web service (and actually I am a novice). I want to persist an object via hibernate passed by the client as an XML representation. To accomplish this task I use jaxb2.

The object the client send is a node having two sons objects, namely data and metadata.

the problem is that when the client sends its XML the SIUserData is unmarshalled in an umpredictable byte[] array: sometimes a part of the imput is cut away and sometimes it is simply empty.

for example this input

<.SINode>
    <.SIUserMeta>a lot of meta<./SIUserMeta>
    <.SIUserData>BBB<./SIUserData>
<./SINode>

is unmarshalled in an object with an empty StorageInterfaceData content attribute.

I believe the problem affects the handling of byte[] since I tryied to change the type of StorageInterfaceData content attribute in a String end everything works fine :S .

It follows the code.

node

@Entity
@Table(name="sinode")
@XmlRootElement(name="SINode")
public class StorageInterfaceNode extends BulkObject  implements Serializable{


    private Integer id;
    private String name;
    private StorageInterfaceMetadata metadata;
    private StorageInterfaceData data;

    public StorageInterfaceNode() {
        super();
        // TODO Auto-generated constructor stub
    }

    public StorageInterfaceNode(Integer id, String name, StorageInterfaceMetadata metadata,
            StorageInterfaceData data) {
        super();
        this.id = id;
        this.name = name;
        this.metadata = metadata;
        this.data = data;
    }

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id", unique=true, nullable=false)
    @XmlTransient
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @XmlTransient
    @Column(name="name", unique=true)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @OneToOne(cascade= CascadeType.ALL)
    @XmlElement(name="SIUserMeta")
    public StorageInterfaceMetadata getMetadata() {
        return metadata;
    }
    public void setMetadata(StorageInterfaceMetadata metadata) {
        this.metadata = metadata;
    }

    @OneToOne(cascade= CascadeType.ALL)
    @XmlElement(name="SIUserData")
    public StorageInterfaceData getData() {
        return data;
    }
    public void setData(StorageInterfaceData data) {
        this.data = data;
    }

}

data

@Entity
@Table(name="data")
public class StorageInterfaceData extends BulkObject implements Serializable{


    private Integer id;
    private String dataName;
    private byte[] content;

    public StorageInterfaceData() {
        super();
        // TODO Auto-generated constructor stub
    }

    public StorageInterfaceData(byte[] content) {
        super();
        this.content = content;
    }

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id", unique=true)
    @XmlTransient
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name="name", unique=true, nullable=false)
    @XmlTransient
    public String getDataName() {
        return dataName;
    }

    public void setDataName(String dataName) {
        this.dataName = dataName;
    }

    @Column(name="content", nullable=false)
    @XmlValue
    public byte[] getContent() {
        return content;
    }

    public void setContent(byte[] content) {
        this.content = content;
    }
}

bulkobject

@XmlTransient
public class BulkObject {

    private Integer id;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

}

metadata class is omitted not to be too verbose. Can anyone clear the thing please?


Solution

  • ok, I think I get the point.

    I really don't know why, but during the unmarshalling procedure JAXB2 assumes deliberately that the stuff within my SIUserData tags are encoded in base64. I made my test writing plain text and what it was returned was something senseless to me.

    For example, I wrote "a lot of data" (textually) within SIUserData tags and I POSTed the node. Once I GET it back I read "alotofda" and it made me a little upset. I could understand that the white spaces disappeared but why should it cut the final "ta"?! From my point of view there was some problems in handling byte[].

    I was wrong and this is how the thing goes: For the application "a lot of data" is a base64 encoded input. JAXB2 handles it internally performing a decoding and obtaining "jZ-¡÷Z". When I ask it back with a GET, JAXB2 performs the inverse operation obtaining "alotofda". The problem pops up because "a lot of data" is not a base64 compliant string. The same thing happens with the "BBB" string I mentioned above in the question. If I use real base64 encoded data everything works perfectly. It is my luck, since it is the way I have to manage my data. Just for completeness, anyone knows how to handle data in XML using different formats? And how to overcome this JAXB2 behaviour?