Regressions from gcj 4.2 to 4.3 involving XML

Andrew Haley
Fri Mar 9 17:23:00 GMT 2007

I've been mystified why Xerces suddenly stopped working with this
release of gcj.  I think I've found the root cause that triggered

In sumary: in gcj 4.2 and previous releases, the handling of "core"
URLs was broken.  As a result of this, we never found
"/META-INF/services/javax.xml.parsers.DocumentBuilderFactory" in
libgcj, so we used Xerces' DocumentBuilderFactory instead.  This
worked perfectly.

Now, the handling of "core" URLs is fixed, so we do find
"/META-INF/services/javax.xml.parsers.DocumentBuilderFactory" in
libgcj, which is incompatible with Xerces.

The reason Xerces worked for us in the past is this bug.  We have
*never* used gnu.xml.dom.DomDocumentBuilderFactory in gcj before now.

The bug:

In gcj 4.2, getFactoryClassName() returns
"org.apache.xerces.jaxp.DocumentBuilderFactoryImpl" when invoked with
xerces in the classpath, but gcj 4.3 returns

This happens because in gcj 4.3,
"/META-INF/services/javax.xml.parsers.DocumentBuilderFactory" is found
in as a "core" resource, whereas in gcj 4.2
"file:/usr/share/java/xerces-j2.jar!/META-INF/services/javax.xml.parsers.DocumentBuilderFactory" is found as a "jar" resource.

So, why does gcj 4.2 not find
"/META-INF/services/javax.xml.parsers.DocumentBuilderFactory" as a
"core" resource?

Because the string passed to _Jv_FindCore is

Note the two slashes: "//"

Why does this happen in gcj 4.2?  It's because we do this in

    /** get resource with the name "name" in the core url */
    Resource getResource(String name)
      Core core = Core.find (dir + name);
      if (core != null)
        return new CoreResource(this, name, core);
      return null;

where dir is "/" and name is

We don't do this in gcj 4.3: instead we do

   * Get a remote resource.
   * Returns null if no such resource exists.
  public Resource getResource(String name)
        URL url = new URL(baseURL, name, cache.get(factory, protocol));
        URLConnection connection = url.openConnection();

        // Open the connection and check the stream
        // just to be sure it exists.
        int length = connection.getContentLength();
        InputStream stream = connection.getInputStream();

        // We can do some extra checking if it is a http request
        if (connection instanceof HttpURLConnection)
            int response =
              ((HttpURLConnection) connection).getResponseCode();
            if (response / 100 != 2)
              return null;

        if (stream != null)
          return new RemoteResource(this, name, url, stream, length);
          return null;
    catch (IOException ioe)
        return null;

which eventually finds its way down to

    // If not connected, then file needs to be opened.
    core = Core.create (url.getFile());

so the error of adding another "/" to the start of the filename never


More information about the Java mailing list