Skip to content

ClassNotFoundException using PL/Java 1.6.8 on Postgres 17.2 #523

@daddeo

Description

@daddeo

We have been using PL/Java for a couple of years now and created our extension initially with 1.5.6 on Postgres 13. Over the years we have migrated to Postgres 15 then 16 and now 17.2. Until recently, we haven't had any serious issues. Our extension is fairly simple and provides XML and JSON validation services to SQL for generated data from business processes. We use install_jar to create entries in SQLJ for our extension JAR and GSON 2.10.1. We run set_classpath for each of our client schemas.

This has all worked well until 17.2 (using PL/Java 1.6.8). Now we are getting ClassNotFoundException on a static class deep within the extension inner workings.

Our SQL calls runPublishValidation(3 parameters) which uses PL/Java to call Publish.validatte(...). Within the extension Publish.validate creates an instance of the non-static class Validation and calls it's run() method. The run() method performs 10 distinct validation checks, think of them as steps. There are several static helper classes for XML and JSON handling, think of them as utility classes. These static utility classes are used extensively in each of the 10 steps.

What we are seeing is that on the 10th step, PL/Java is reporting ClassNotFoundException on Helpers.processSubstitution(). Again, this class method will have been called dozens of times prior to the 10th step invocation.

This is the call stack I get:

25 Mar 25 14:28:16 org.postgresql.pljava.sqlj.Loader Failed to load class
java.sql.SQLException: An attempt was made to call a PostgreSQL backend function after an elog(ERROR) had been issued
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.Oid._forSqlType(Native Method)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.Oid.lambda$forSqlType$1(Oid.java:68)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.Backend.doInPG(Backend.java:89)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.Oid.forSqlType(Oid.java:68)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.jdbc.SPIPreparedStatement.setObject(SPIPreparedStatement.java:238)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.jdbc.SPIPreparedStatement.setObject(SPIPreparedStatement.java:223)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.jdbc.SPIPreparedStatement.setInt(SPIPreparedStatement.java:124)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.sqlj.Loader.lambda$findClass$5(Loader.java:462)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.sqlj.Loader.findClass(Loader.java:464)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:592)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
	at schema:dimbuild_sprvl//com.iri.udb.pljava.publish.Validation.checkAttrSpecMeta(Validation.java:211)
	at schema:dimbuild_sprvl//com.iri.udb.pljava.publish.Validation.run(Validation.java:159)
	at schema:dimbuild_sprvl//com.iri.udb.pljava.Publish.validate(Publish.java:75)
	at schema:dimbuild_sprvl//com.iri.udb.pljava.Publish.validate(Publish.java:48)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.EntryPoints.lambda$invocable$0(EntryPoints.java:130)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.EntryPoints.doPrivilegedAndUnwrap(EntryPoints.java:312)
	at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.EntryPoints.invoke(EntryPoints.java:158)

Exception mv_spec_extract_data ERROR: java.lang.NoClassDefFoundError: com/iri/udb/pljava/common/Helpers

We have tried many different approaches to narrow down what is happening from pljava setting changes in the postgresql.conf file to flatten away the static class into the Validation class implementation to use Class.forName to dynamically load the class. Nothing helped. Then we decided to add -Djava.class.path={our jars} to pljava.vmoptions and this seems to have corrected the problem, although introduces another problem for us. We run in many different environments, on many database servers and this will be a maintenance and setup nightmare for us. We like using the SQLJ tables to manage the distribution of the extension.

As this point, I will stop typing and let you digest (and/or figure out) what I've said and ask questions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions