Regressions from gcj 4.2 to 4.3 involving XML

Andrew Haley aph@redhat.com
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
this.

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
"gnu.xml.dom.DomDocumentBuilderFactory".

This happens because in gcj 4.3,
"/META-INF/services/javax.xml.parsers.DocumentBuilderFactory" is found
in libgcj.so 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
"//META-INF/services/javax.xml.parsers.DocumentBuilderFactory"

Note the two slashes: "//"

Why does this happen in gcj 4.2?  It's because we do this in
RemoteURLLoader.getResource:

    /** 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
"/META-INF/services/javax.xml.parsers.DocumentBuilderFactory"

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)
  {
    try
      {
        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);
        else
          return null;
      }
    catch (IOException ioe)
      {
        return null;
      }
  }

which eventually finds its way down to

gnu.java.net.protocol.core.Connection.connect():

    // 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
occurs.

Andrew.



More information about the Java mailing list