ClassNotFound Exception when Registering Reporting Component

I'm trying to register a new reporting component that I've built, and the GatewayHook class loader doesn't seem to be able to find the "AbstractJ2DShape" class. Do I need to force it to use a specific class loader?

I'm using the following dependency in my common pom.xml:

        <dependency>
            <groupId>com.inductiveautomation.ignitionsdk</groupId>
            <artifactId>reporting-common</artifactId>
            <version>8.1.14</version>
            <type>pom</type>
            <scope>provided</scope>
        </dependency>

The exception I'm getting is:

java.lang.NoClassDefFoundError: com/inductiveautomation/rm/shape/j2dshapes/AbstractJ2DShape
.........................
Caused by: java.lang.ClassNotFoundException: com.inductiveautomation.rm.shape.j2dshapes.AbstractJ2DShape
at java.base/java.net.URLClassLoader.findClass(Unknown Source)
at com.inductiveautomation.ignition.gateway.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:37)
at com.inductiveautomation.ignition.gateway.modules.ModuleClassLoader.loadClass(ModuleClassLoader.java:104)
at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
... 26 common frames omitted

I've run mvn clean install and restarted my Gateway just in case that's the problem...

Is your module itself marked as depending on the reporting module, in the module.xml?

1 Like

That was it... I knew it was going to be something simple like that.

I do have a related question though - if I don't want my module to depend on the reporting module, is there a way I can configure that? So for instance, my module is mostly providing a back-end service on the gateway and I'm creating a few perspective/reporting components as additional "bonus" features. I don't want the module installation to fail if the end user doesn't have Reporting or Perspective installed just for these "niceties", I'd rather just add a try/catch somewhere, log a warning and move on.

1 Like

Module dependencies are "soft", it will log a warning but load your module anyway.

You do need to place a conditional guard around your code that loads/accesses classes from the report module, though. Something like:

if (context.getModuleManager().getModule("reporting-module-id") != null) {
  // .. do stuff to register your component here.. 
}

might be enough. If not you'll have to do some reflection trickery.

2 Likes

The trickery is usually factoring out the reporting-specific initialization (or anything in the lifecycle) into a separate class, so that the gateway hook itself doesn't have any binary reference to the reporting module or to that separate class file. Where needed, you load that special class by name and skip if it fails.

Same idea for Perspective or any other soft dependency.

2 Likes