Starting with PL/Java 1.6.3, within an SQL-declared PL/Java function, the
class loader returned by Thread.currentThread().getContextClassLoader
is the one that corresponds to the per-schema classpath that has been set
with SQLJ.SET_CLASSPATH
for the schema where the function is
declared (assuming no Java code uses setContextClassLoader
to change it).
Many available Java libraries, as well as built-in Java facilities using the
ServiceLoader
, refer to the context class loader, so this behavior
ensures they will see the classes that are available on the classpath that was
set up for the PL/Java function. In versions where PL/Java did not set the
context loader, awkward arrangements could be needed in user code for the
desired classes or services to be found.
To set this loader with minimal overhead on function entry, PL/Java uses native
access to a Thread
field. It is possible that some Java runtimes can exist
where the expected field is not present, and PL/Java will fall back (with a
warning) to not managing the context loader. The warning can be suppressed
by explicitly configuring PL/Java not to manage the context loader, as described
below.
It is also possible for an application or library to create subclasses
of Thread
that override the behavior of getContextClassLoader
so that
the value set by PL/Java will have no effect. PL/Java does not detect or work
around such a case. A clear sign of code that does subclass Thread
in this way is that it will need the enableContextClassLoaderOverride
RuntimePermission
to be granted in
the policy.
With this change as of PL/Java 1.6.3, application or library code that uses
the ServiceLoader
, or otherwise refers to the context class loader,
will find services or resources available on the class path that was set up
for the function. Typically, this behavior is wanted. In prior PL/Java versions,
services and resources might be found only if they were available to the
system class loader.
For example, a call like javax.xml.transform.TransformerFactory.newInstance()
might return Java's built-in XSLT 1.0 implementation if there is nothing else
on the class path, but return an XSLT 3.0 implementation if the configured
PL/Java class path includes a Saxon jar.
If there are cases where an application intends to use a built-in Java
implementation regardless of the class path, there may be a method available
that specifies that behavior. For example,
TransformerFactory.newDefaultInstance()
will always return Java's
own Transformer
implementation.
If an application misbehaves as a result of finding implementations on the
class path it was not finding before, and cannot be conveniently fixed by
adjusting the class path or changing to newDefaultInstance
-like methods
in the code, PL/Java can be configured for its old behavior of not setting
the context class loader, as described below.
User-defined types implemented in PL/Java have support methods that are
transparently invoked to convert database values to Java values and back.
This can happen within a PL/Java function, when it gets or sets values in
ResultSet
, PreparedStatement
, SQLInput
, or SQLOutput
objects, and
also conceptually “before” or “after” the function proper, to convert its
incoming parameters and its return value(s). In all such contexts, the UDT
methods are considered to act on behalf of that target PL/Java function,
and the context class loader they see is the one for the schema where the
target function is declared.
A BaseUDT
implemented in PL/Java has support methods that are
declared to PostgreSQL as SQL functions in their own right. In addition to being
transparently called on behalf of another PL/Java function, with the behavior
described above, they can be called directly by PostgreSQL like any other
SQL function. When that happens, like any other declared function, they will
have the context class loader set according to the schema containing the
declaration.
Some circumstances may call for keeping the pre-1.6.3 behavior where no management of the context class loader was done. That could be to avoid unplanned effects on applications as described above, or to suppress the warning message if running on a JVM where PL/Java's technique doesn't work.
To suppress the loader management, add
-Dorg.postgresql.pljava.context.loader=unmanaged
in the pljava.vmoptions
setting.