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.