4
votes

I would like to generate jaxb xsd schema from class files in jar. Currently, I am using jaxb2-maven-plugin to generate schema using java files.

<plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>jaxb2-maven-plugin</artifactId>
        <version>${maven.plugin.jaxb2}</version>
        <executions>
           <execution>
              <id>schemagen</id>
              <goals>
                 <goal>schemagen</goal>
              </goals>
              <phase>process-classes</phase>
              <configuration>
                 <quiet>true</quiet>
                 <includes>
                    <include>com/someProject/domain/*.java</include>
                 </includes>
                 <outputDirectory>${project.build.directory}/schemas</outputDirectory>
                 <clearOutputDir>true</clearOutputDir>
              </configuration>
           </execution>
        </executions>
     </plugin>

But, I have a use case where I am getting a dependency jar file and would like to generate out of some classes from that jar file. Can anyone suggest how can it be done.

2
I do have an article which does exactly the opposite of what you have asked - javareferencegv.blogspot.com/2013/10/… Watching this question for answers thoughCrickcoder
opposite :) Do you have any thoughts on how can it be done ?White Roses
I feel we can use the class in jars the same way we use in our class folder. If not we can extract the classes in that jar to a desired folder and then use them. (Using Ant would be good)Crickcoder
Would this Answer help : stackoverflow.com/questions/12307396/… ?Patrice M.
This is opposite of what I need. I would like to generate jaxb xsd schema from class files in a jarWhite Roses

2 Answers

2
votes

For simplicity reasons I reuse the code presented in this article to demonstrate the necessary steps to generate a Jaxb Schema from a Java class stored inside a Jar-archive

The code consists of two classes - Employee and Address:

package base.package;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "employee")
public class Employee 
{
    @XmlAttribute
    private int id;
    private String name;
    private double salary;
    private String designation;
    private Address address;

    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public double getSalary() { return salary; }
    public void setSalary(double salary) { this.salary = salary; }
    public String getDesignation() { return designation; }
    public void setDesignation(String designation) { this.designation = designation; }
    public Address getAddress() { return address; }
    public void setAddress(Address address) { this.address = address; }
}

and a referenced class:

package base.package;

public class Address 
{
    private String line1;
    private String line2;
    private String city;
    private String state;
    private long zipcode;

    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 long getZipcode() { return zipcode; }
    public void setZipcode(long zipcode) { this.zipcode = zipcode; }
}

This code is now compiled using the following command: javac -d bin src/base/package/*.java. This will compile all source files located in src to the bin directory:

base-dir
|- src
|  \- base
|     \- package
|        |- Employee.java
|        \- Address.java
\- bin
   \- base
      \- package
         |- Employee.class
         \- Address.class

To get a proper Jar-archive for the compiled classes use: jar -cf test.jar -C bin/ . This will generate a test.jar archive with the following content:

test.jar
|- base
|  \- package
|     |- Employee.class
|     \- Address.class
\- META-INF
   \- MANIFEST.MF

You could now remove the bin directory and all of its content as all the files we need are stored within the archive and to prove that the schema is actually generated from the files inside the Jar archive.

As all preparations are finally done, the actual issue can be tackled - how to generate the schema from .class-files located in that test.jar archive:

Simply run this command: schemagen -cp test.jar base.package.Employee and it should generate a schema definition similar to the snippet below:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="employee" type="employee"/>

  <xs:complexType name="employee">
    <xs:sequence>
      <xs:element name="address" type="address" minOccurs="0"/>
      <xs:element name="designation" type="xs:string" minOccurs="0"/>
      <xs:element name="salary" type="xs:double"/>
      <xs:element name="name" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="id" type="xs:int" use="required"/>
  </xs:complexType>

  <xs:complexType name="address">
    <xs:sequence>
      <xs:element name="city" type="xs:string" minOccurs="0"/>
      <xs:element name="line1" type="xs:string" minOccurs="0"/>
      <xs:element name="line2" type="xs:string" minOccurs="0"/>
      <xs:element name="state" type="xs:string" minOccurs="0"/>
      <xs:element name="zipcode" type="xs:long"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

Hope this was simple enough to follow


Edit: It seems that the jaxb2-maven-plugin as well as the ant-task are not able to use class-files at all, so probably the simplest and easiest solution would be to provide a script file (.bat on windows; .sh on *nix/Mac) where you just invoke the command manually:

As I'm currently running on Windows 7 a script that automatically generates the schema into a schemas subdirectory of the project would look like this:

schemagen -cp path/to/jar/*.jar -d ./schemas/ package.ClassName

You can then simply invoke that script (which I have placed in a scripts subdirectory of the project) using the maven exec-plugin which is bound to the generate-sources phase:

<plugin>
    <artifactId>exec-maven-plugin</artifactId>
    <groupId>org.codehaus.mojo</groupId>
    <executions>
        <execution>
            <id>Generate schemas from class files contained in a jar</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>exec</goal>
            </goals>
            <configuration>
                <executable>${basedir}/scripts/generate-sources.bat</executable>
            </configuration>
        </execution>
    </executions>
</plugin>

The schemas should then get automatically generated on executing mvn generate-sources or any later phase maven provides.


Edit: I've modified the script slightly as it is able to deal with wildcards, though you have to specify *.jar instead of only * - but I guess this should be fine enough, at least this saves you from manually typing the names of the Jar-files that contain the JAXB classes

1
votes

You can write a program to create a JAXBContext on your domain model and then call the generateSchema method on the JAXBContext to generate the XML Schema.

Example

import java.io.IOException;
import javax.xml.bind.*;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;

public class Demo {

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

            @Override
            public Result createOutput(String namespaceURI, String suggestedFileName)
                throws IOException {
                return new StreamResult(suggestedFileName);
            }

        });

    }

}