You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@xmlbeans.apache.org by "BEEKER, ANDREAS (Allianz Deutschland AG)" <ex...@allianz.de> on 2008/05/27 20:07:08 UTC

Multiple classloader and schema versioning

Hi,

I'm trying to use XmlBeans (2.3) with different versions of a schema
in a web application.

Background story ... (what I want ...)
So lets say we have a schema for an element called "headstats",
which is also the root element. In all the schemas I would
introduce an attribute "version" in the root element and by
pre-parsing (or something else) I would know the version of
that xml beforehand.
The types would be suffixed with the version, so the element
headstats would belong to the headstats10 type.

The problem ...
The XmlBeans-Faq suggest to use multiple class loaders if
the elements have the same name in different schemas.
So what I've tried is to seperate the java classes and
the generated xsb files in two jars.
The java classes (headstats10-java.jar) go into the
WEB-INF/lib directory and will be in the classloader of
the calling webapp code.
The xsb files (headstats10-schema.jar) go into directory
not covered by the webapp-container.

This is how I wanted to get the xmlbean:

private void testClassLoaderInner() throws Exception {
  ClassLoader ctxCL = Thread.currentThread().getContextClassLoader();
  // maybe overwriting the context class loader here ???
  URL urljava = ctxCL.getResource("WEB-INF/lib/headstats10-java.jar");
  URL urlschema = ctxCL.getResource("WEB-INF/schema/headstats10-schema.jar");
  ClassLoader myCL = new URLClassLoader(new URL[]{urlschema,urljava}, ctxCL);
  SchemaTypeLoader stl = XmlBeans.typeLoaderForClassLoader(myCL);
  TouchpointListType tlt = (TouchpointListType)stl.newInstance(TouchpointListType.type, null);
  TouchpointType tt = tlt.addNewTouchpoint();
}

... but in the generated code of the TouchpointListType there is a reference
on the webapp classloader (...class.getClassLoader()) and not my SchemaTypeLoader

public interface TouchpointListType extends org.apache.xmlbeans.XmlObject
{
  public static final org.apache.xmlbeans.SchemaType type = (org.apache.xmlbeans.SchemaType)
    org.apache.xmlbeans.XmlBeans.typeSystemForClassLoader(TouchpointListType.class.getClassLoader(),
    "schemaorg_apache_xmlbeans.system.s83BE290BC2BDEAA4F2C07CDF89814312").resolveHandle("touchpointlisttypecf0atype");

... so I will get a NoClassDefFoundError or similar.

Any suggestions how solve that classloader problem or how to
support different versions of a schema?

Thanks for your help,
Andreas Beeker.

Re: Multiple classloader and schema versioning

Posted by "BEEKER, ANDREAS (Allianz Deutschland AG)" <ex...@allianz.de>.
Ok it works now. It was an issue of some residues of earlier XmlBeans work
(generated classes and jars ...)

I have some kind of factory class now, which is called like this 

// using TouchpointListType.class instead of the literal would throw a NoClassDefError here ...
....util.xml.types11.headstats.TouchpointListDocument tlt =
   (....util.xml.types11.headstats.TouchpointListDocument)
   XmlBeanFactory.parseXml(xmlString11, "headstats11", "TouchpointListDocument");

... and contains these methods ...

public static XmlObject parseXml(String xmlstring, String schema,
   String type, String namespace, XmlOptions options) throws XmlException {
   SchemaTypeLoader stl = loadSchema(schema);
   SchemaType st = stl.findType(new QName(namespace, type));
   XmlObject xo = stl.parse(xmlstring, st, options);
   return xo;
}

private static synchronized SchemaTypeLoader loadSchema(String schema) {
   if (schemaLoader == null) {
      schemaLoader = new HashMap();
   }
   SchemaTypeLoader stl = (SchemaTypeLoader)schemaLoader.get(schema);
   if (stl == null) {
      // I use the default classloader (from the web container) instead
      // of the context classloader to not have any problems with the
      // cached SchemaTypeLoaders in different thread contexts
      ClassLoader thisCL = XmlBeanFactory.class.getClassLoader();
      URL urlschema = thisCL.getResource("WEB-INF/schema/"+schema+"-schema.jar");
      ClassLoader myCL = new URLClassLoader(new URL[]{urlschema}, thisCL);
      stl = XmlBeans.typeLoaderForClassLoader(myCL);
      schemaLoader.put(schema, stl);
   }
   return stl;
}

Regards,
Andreas.