25
votes

Ok, so I've searched stackoverflow and found unanswered sub-topics regarding this issue, that's why I'd like to have this question clearly pointed out:

Is there any tool that will generate the Simple Xml library's annotated java class from an xsd schema?

I received a couple of xsd files describing the objects returned by a restful web-service someone else has developed and currently I've translated those schemas to the simple-xml annotated classes. Those will be used in my Android app. It would be better to just automatically synchronize any changes to the schemas and regenerate the classes from them. The ws guys have a repository of Jackson compliant classes for those schemas, however I don't want to use Jackson - I'm using Spring Android, so I'd prefer to go with the preferred simple-xml. There must be something that does the trick like JAXB's xjc tool.

If there is no such tool - can you think of any traps in implementing a script that generates a .java file for simple-xml from the schema? Maybe any hints for tools worth extending that would just require defining what annotations to generate and when?

In advance - thanks a lot for your answers!

3
Did you ever find a solution to this problem? I also would like to start with an XSD file, generate Java classes, and then use those classes with Simple-XML. - stackoverflowuser2010

3 Answers

4
votes

I do not believe that JAXB can be used on Android because of missing package requirements (see here), especially with earlier versions of the Android API. What you could do instead is send your XSD through xjc and get JAXB class output and then write a script to convert the JAXB annotations into the equivalent Simple XML annotations. This should do exactly what you were looking for.

However, ideally, and if you had the time, you could check out the source for xjc and extend it to be able to output JAXB or Simple annotated classes.

4
votes

I wrote a library to generate SimpleXML Java annotated classes from XSD.

Here is the link: https://github.com/yeshodhan/android-jaxb

Eg:

XML Schema

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://person.mickoo.com/"
            targetNamespace="http://person.mickoo.com/" elementFormDefault="qualified">

    <xsd:element name="Person" type="Person"/>

    <xsd:complexType name="Person">
        <xsd:sequence>
            <xsd:element name="FirstName" type="xsd:string" minOccurs="0" />
            <xsd:element name="LastName" type="xsd:string" minOccurs="0" />
            <xsd:element name="Adult" type="xsd:boolean" minOccurs="0" />
            <xsd:element name="Addresses" type="Addresses" minOccurs="0" />
            <xsd:element name="Gender" type="Gender" minOccurs="0" />
            <xsd:element name="Favorite_Fruits" type="Fruits" minOccurs="0" maxOccurs="3"/>
            <xsd:element name="SomeThing_really_whacky-by-the-user" type="xsd:string" minOccurs="0" />
        </xsd:sequence>
        <xsd:attribute name="id" type="xsd:string"/>
    </xsd:complexType>

    <xsd:complexType name="Addresses">
        <xsd:sequence>
            <xsd:element name="Address" type="Address" minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence>
    </xsd:complexType>

    <xsd:complexType name="Address">
        <xsd:sequence>
            <xsd:element name="Line1" type="xsd:string" minOccurs="0" />
            <xsd:element name="Line2" type="xsd:string" minOccurs="0" />
            <xsd:element name="City" type="xsd:string" minOccurs="0" />
            <xsd:element name="State" type="xsd:string" minOccurs="0" />
            <xsd:element name="Country" type="xsd:string" minOccurs="1" />
            <xsd:element name="PostalCode" type="xsd:string" minOccurs="0" />
        </xsd:sequence>
    </xsd:complexType>

    <xsd:simpleType name="Gender">
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="MALE"/>
            <xsd:enumeration value="FEMALE"/>
            <xsd:enumeration value="NOT_SPECIFIED"/>
        </xsd:restriction>
    </xsd:simpleType>

    <xsd:simpleType name="Fruits">
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="Apple"/>
            <xsd:enumeration value="Banana"/>
            <xsd:enumeration value="Mango"/>
            <xsd:enumeration value="Orange"/>
            <xsd:enumeration value="Grapes"/>
            <xsd:enumeration value="Watermelon"/>
            <xsd:enumeration value="Peach"/>
            <xsd:enumeration value="Apricot"/>
            <xsd:enumeration value="Grapefruit"/>
        </xsd:restriction>
    </xsd:simpleType>

</xsd:schema>

Generated Java Classes

package com.mickoo.person;

import org.simpleframework.xml.Element;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;


@Root(name = "Address")
@Namespace(reference = "http://person.mickoo.com/")
public class Address {

    @Element(name = "Line1", required = false)
    private String line1;
    @Element(name = "Line2", required = false)
    private String line2;
    @Element(name = "City", required = false)
    private String city;
    @Element(name = "State", required = false)
    private String state;
    @Element(name = "Country", required = true)
    private String country;
    @Element(name = "PostalCode", required = false)
    private String postalCode;

    public Address() {
    }

    public String getLine1() {
        return line1;
    }

    public void setLine1(String line1) {
        this.line1 = line1;
    }

    public String getLine2() {
        return line2;
    }

    public void setLine2(String line2) {
        this.line2 = line2;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getPostalCode() {
        return postalCode;
    }

    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }

}

package com.mickoo.person;

import java.util.List;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;


@Root(name = "Addresses")
@Namespace(reference = "http://person.mickoo.com/")
public class Addresses {

    @ElementList(name = "Address", entry = "Address", inline = true, required = false)
    private List<Address> address;

    public Addresses() {
    }

    public List<Address> getAddress() {
        return address;
    }

    public void setAddress(List<Address> address) {
        this.address = address;
    }

}

package com.mickoo.person;

import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;

@Root(name = "Fruits")
@Namespace(reference = "http://person.mickoo.com/")
public enum Fruits {

    Apple,
    Banana,
    Mango,
    Orange,
    Grapes,
    Watermelon,
    Peach,
    Apricot,
    Grapefruit;

}

package com.mickoo.person;

import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;

@Root(name = "Gender")
@Namespace(reference = "http://person.mickoo.com/")
public enum GenderEnum {

    MALE(0, "Men are from Mars"),
    FEMALE(1, "Women are from Venus"),
    NOT_SPECIFIED(2, "Can't say anything");
    private final Integer id;
    private final String description;

    private GenderEnum(Integer id, String description) {
        this.id = id;
        this.description = description;
    }

    public Integer id() {
        return id;
    }

    public String description() {
        return description;
    }

}


package com.mickoo.person;

import java.util.List;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;


@Root(name = "Person")
@Namespace(reference = "http://person.mickoo.com/")
public class Person {

    @Element(name = "FirstName", required = false)
    private String firstName;
    @Element(name = "LastName", required = false)
    private String lastName;
    @Element(name = "Adult", required = false)
    private Boolean adult;
    @Element(name = "Addresses", required = false)
    private Addresses addresses;
    @Element(name = "Gender", required = false)
    private GenderEnum gender;
    @ElementList(name = "Favorite_Fruits", entry = "Favorite_Fruits", inline = true, required = false)
    private List<Fruits> favoriteFruits;
    @Element(name = "SomeThing_really_whacky-by-the-user", required = false)
    private String someThingReallyWhackyByTheUser;
    @Attribute(name = "id", required = false)
    private String id;

    public Person() {
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Boolean getAdult() {
        return adult;
    }

    public void setAdult(Boolean adult) {
        this.adult = adult;
    }

    public Addresses getAddresses() {
        return addresses;
    }

    public void setAddresses(Addresses addresses) {
        this.addresses = addresses;
    }

    public GenderEnum getGender() {
        return gender;
    }

    public void setGender(GenderEnum gender) {
        this.gender = gender;
    }

    public List<Fruits> getFavoriteFruits() {
        return favoriteFruits;
    }

    public void setFavoriteFruits(List<Fruits> favoriteFruits) {
        this.favoriteFruits = favoriteFruits;
    }

    public String getSomeThingReallyWhackyByTheUser() {
        return someThingReallyWhackyByTheUser;
    }

    public void setSomeThingReallyWhackyByTheUser(String someThingReallyWhackyByTheUser) {
        this.someThingReallyWhackyByTheUser = someThingReallyWhackyByTheUser;
    }

    public String getId() {
        return id;
    }

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

}

Usage

➜  target git:(master) ✗ java -jar android-jaxb-1.0.jar --help
usage: java -jar android-jaxb-1.0.jar [options] your-schema-file.xsd
---------------------------------------------------------------------
 -b,--bindings <arg>      (optional) bindings JSON file
 -d,--destination <arg>   destination directory for generated classes
 -h,--help                Help on usage
 -p,--package <arg>       package name for generated classes. Eg.:
                          com.example.app
 -v,--version             Version
---------------------------------------------------------------------
0
votes

As far as I know, Simple XML is used to create annotated classes to marshall/demarshall XML.
The Java Web Services frameworks, use specific bindings:
E.g. CXF supports (besides JAXB) Aegis, XML Beans etc CXF data bindings
Axis2 supports ADB, XMLBeans etc Axis2 data bindings
Same for JAX-WS
I do not know about Spring WS (but I doubt they support specifically simple)
IMHO, if you need absolutely to use Simple XML, just create the classes yourself. This seems feasible in your case since you note:

I received a couple of xsd files describing the objects returned by a restful web-service 

So for a few files may be it is possible. I do not think you should worry about changes in the schema by the web service implementers, since if they do changes you would have to regenerate your client part anyhow. In any case once a web service is deployed the schemas do not change that often otherwise all the client apps would be affected.
If you want to create your own tool, then you would have to create a code generator that would parse the xsd files and create annotated classes for Simple XML. This seems to me a lot of effort
Hope this helps