Wednesday, January 9, 2013

How to generate a zip file of schemas from JAXB annotated class

This utility class will zip up all the schemas generated from a JAXB annotated class. I've found it handy sometimes.
package org.moten.david.util.xml;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;

/**
 * Utility class for xml schemas.
 * 
 * @author dxm
 * 
 */
public class SchemaUtil {

 /**
  * Returns a zip file containing all schemas generated from the given class.
  * The class may or may not have xml annotations as per normal JAXB
  * marshaler creation. All non-fundamental classes referenced by the class
  * will be described in the schema as well.
  * 
  * @param os
  *            the output stream to write the zip file to
  * @param cls
  *            the class to generate the schemas from
  */
 public static void writeSchemasAsZip(OutputStream os, Class cls) {
  try {
   JAXBContext context = JAXBContext.newInstance(cls);
   Map map = new HashMap();
   SchemaOutputResolver sor = new MySchemaOutputResolver(map);
   context.generateSchema(sor);

   ZipOutputStream zip = new ZipOutputStream(os);
   for (Entry entry : map.entrySet()) {
    ZipEntry ze = new ZipEntry(entry.getKey());
    zip.putNextEntry(ze);
    zip.write(entry.getValue().toByteArray());
    zip.closeEntry();
   }
   zip.close();
  } catch (IOException e) {
   throw new RuntimeException(e);
  } catch (JAXBException e) {
   throw new RuntimeException(e);
  }
 }

 private static class MySchemaOutputResolver extends SchemaOutputResolver {

  private final Map map;

  MySchemaOutputResolver(Map map) {
   this.map = map;
  }

  @Override
  public synchronized Result createOutput(String namespaceURI,
    String suggestedFileName) throws IOException {
   System.out.println(suggestedFileName);
   File file = new File(suggestedFileName);
   ByteArrayOutputStream bytes = new ByteArrayOutputStream();
   map.put(suggestedFileName, bytes);
   StreamResult result = new StreamResult(bytes);
   result.setSystemId(file.toURI().toURL().toString());
   return result;
  }
 }
}