Gradle Shading Question

Hi all,

Does anyone have any experience using the GradleUp Shadow plugin in combination with the IA Gradle plugin? Recently, I discovered that one of our modules is running into the following error on 8.1.47:

BasicExecutionEngine	05May2025 15:41:00	One-shot task com.inductiveautomation.ignition.gateway.redundancy.RedundancyManagerImpl$ExecuteTask@4d8e047a threw uncaught exception.
 java.lang.IllegalAccessError: class io.netty.buffer.UnsafeDirectLittleEndian cannot access its superclass io.netty.buffer.WrappedByteBuf (io.netty.buffer.UnsafeDirectLittleEndian is in unnamed module of loader com.inductiveautomation.ignition.gateway.modules.ModuleClassLoader @4ca563c0; io.netty.buffer.WrappedByteBuf is in unnamed module of loader 'app')
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(Unknown Source)
at java.base/java.security.SecureClassLoader.defineClass(Unknown Source)
at java.base/java.net.URLClassLoader.defineClass(Unknown Source)
at java.base/java.net.URLClassLoader$1.run(Unknown Source)
at java.base/java.net.URLClassLoader$1.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
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)
at io.netty.buffer.PooledByteBufAllocatorL.(PooledByteBufAllocatorL.java:49)
at org.apache.arrow.memory.NettyAllocationManager.(NettyAllocationManager.java:51)
at org.apache.arrow.memory.DefaultAllocationManagerFactory.(DefaultAllocationManagerFactory.java:26)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Unknown Source)
at org.apache.arrow.memory.DefaultAllocationManagerOption.getFactory(DefaultAllocationManagerOption.java:108)
at org.apache.arrow.memory.DefaultAllocationManagerOption.getDefaultAllocationManagerFactory(DefaultAllocationManagerOption.java:98)
at org.apache.arrow.memory.BaseAllocator$Config.getAllocationManagerFactory(BaseAllocator.java:773)
at org.apache.arrow.memory.ImmutableConfig.access$801(ImmutableConfig.java:24)
at org.apache.arrow.memory.ImmutableConfig$InitShim.getAllocationManagerFactory(ImmutableConfig.java:83)
at org.apache.arrow.memory.ImmutableConfig.(ImmutableConfig.java:47)
at org.apache.arrow.memory.ImmutableConfig.(ImmutableConfig.java:24)
at org.apache.arrow.memory.ImmutableConfig$Builder.build(ImmutableConfig.java:485)
at org.apache.arrow.memory.BaseAllocator.(BaseAllocator.java:62)

I suspect this has something to do with the fact that the library we're using has transitive dependencies for io.netty. These packages were recently added to 8.1.47, and I think it's causing the issue I'm seeing now.

One of the things I've tried was using exclude on the modlImplementation configuration. The module that compiled didn't include the netty jars, but I still ran into the same issue as before. I found a post (Module class loading) referring to a similar problem, but I didn't see a solution. I've been trying to apply the shadowJar task to our project but haven't had any luck.

I don't have any answers or experience re: shadow + ignition plugins, but I can tell you that those new dependencies that landed in lib/core/gateway were a bit of an accident and we've got a ticket to correct that... they came in as transitive dependencies on the AWS SDK, which itself is only even need for Ignition Cloud Edition.

If you're not on Cloud Edition you could probably remove the AWS and Netty JARs from lib/core/gateway...

Hi Kevin,

Thanks for that, you were right, the error doesn't appear after I remove the netty jars from the install folder.

Thinking ahead, is there anyway for us to avoid this from happening again? Is shading the right way to go? Apart from just wanting our module to run in Ignition Cloud, I can see the possibility of other modules running into this issue again because of a popular library being incorporated into Ignition, not just in 8.1 but 8.3.

Can I request IA look into adding some kind of built in shading functionality into the Gradle plugin? Or is this something I'll have to try to resolve ourselves?

I don't think the plugin needs explicit support for it, I just think you need to be better at Gradle than I am to figure it out.

Defensively shading is probably the best approach right now. This is classic dependency hell.

One of the other developers has floated the idea of trying to isolate module class loaders completely from the platform, but given the way class loaders work by default I think that's going to be complicated and error prone, so it's just an idea right now.

I've used the following approach with the Maven plugin, and I imagine it would work just the same with the Gradle plugin.

Given a project layout like this:

.
├── config
├── msd-build
├── msd-gateway
└── msd-gateway-tests

You could add another module called e.g. msg-gateway-deps. This module would have no source code, just a gradle file with all your dependencies, and with the shadow plugin configured.

msd-gateway then just has a dependency on the msd-gateway-deps module.

Nothing else changes, except now when the build plugin picks up the msd-gateway module its only dependency is the already-shaded/shadowed msd-gateway-deps JAR.