25

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!

quietmint
  • 13,885
  • 6
  • 48
  • 73
  • 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 Sep 23 '15 at 22:25

3 Answers3

4

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
---------------------------------------------------------------------
Yeshodhan Kulkarni
  • 2,844
  • 1
  • 16
  • 19
  • 1
    java -jar android-jaxb-1.0.jar -d ... Metadata.xsd Code Generator Initialized. Destination Directory: D:\Projects\Android\XsdToSimpleXML [Element /frequencyConfig Min Occurs: null, Max Occurs: null ] of type [null] [Start of sequence Min Occurs: 1, Max Occurs: 1 ] [Element /frequencyConfig/dateStart Min Occurs: 1, Max Occurs: 1 ] of type [dateTime] Exception in thread "main" java.lang.NullPointerException at com.sun.codemodel.JVar.annotate(JVar.java:188) at com.mickoo.xml.xsd2simplexml.GeneratedClass.addElement(GeneratedClass .java:62) – Peter Barbanyaga Dec 17 '15 at 05:21
  • 2
    Your lib generate many exceptions like "Exception in thread "main" java.lang.NullPointerException at com.sun.codemodel.JVar.annotate" for sequences. Why? – Peter Barbanyaga Dec 17 '15 at 05:43
  • Can you send me the XSD you are trying to parse? – Yeshodhan Kulkarni Jan 11 '16 at 05:49
  • How can I understand problem appeares because I don't use JSON-description. Is use JSON-description neccessery? – Peter Barbanyaga Jan 11 '16 at 06:38
  • Yeshodhan, is there any chance you're still working on this project? I'd like to use it but I get a NullPointerException when I try to – alicjab Dec 02 '16 at 13:46
  • I know this is pretty old, but I got a successful conversion out of it with, two things to note: 1. You need to pass the destination and package options. If you only pass the package option, the generator will throw an NPE 2. You can only use simple types or you'll get a NPE. "xsd:date" for example, is not supported. I manually replaced each type that caused a NPE. You can tell which type is causing the issue by looking at the last node that was printed out before the NPE, and replacing it with a basic type – Selali Adobor Jun 06 '19 at 15:02
4

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.

Community
  • 1
  • 1
Robert Massaioli
  • 13,379
  • 7
  • 57
  • 73
0

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

Cratylus
  • 52,998
  • 69
  • 209
  • 339
  • Spring Android Rest Template module depends on simple-xml (source: http://static.springsource.org/spring-android/docs/1.0.x/reference/html/rest-template.html) I was curious about the tools dedicated for Simple. I am aware of the alternatives, I just wanted to use Spring Android :) The ws team is at the development of a server application that we want to access via Android client. The automation of the xsd -> java would mean less work. Once they change something, some scripts might automatically regenerate the objects in the Android client app. – Dariusz Jędrzejczyk May 31 '11 at 23:06