2

I've got a multi-project application where we use a library, oshi, that depends on version 4.2.2 of JNA. In our project itself, we use 4.3.0, which hasn't been released yet. We made a contribution that will be in 4.3.0 when it ever gets released, but we need it right now, so we currently use a forked version that we build ourselves.

We package everything up using the maven shade plugin. Currently, the shade plugin uses 4.3.0 in the uberjar.

The problem is that oshi uses a function in 4.2.2 that doesn't seem to be in 4.3.0. The interface we are using was changed, and now we get NoSuchMethodError exception. The exception we get looks like this:

org.quartz.JobExecutionException: org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.NoSuchMethodError: com.sun.jna.platform.win32.OleAuto.VariantClear(Lcom/sun/jna/Pointer;)Lcom/sun/jna/platform/win32/WinNT$HRESULT;]
at org.quartz.core.JobRunShell.run(JobRunShell.java:218) [quartz-2.2.3.jar:?] 
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [quartz-2.2.3.jar:?]

Caused by: org.quartz.SchedulerException: Job threw an unhandled exception.
at org.quartz.core.JobRunShell.run(JobRunShell.java:213) [quartz-2.2.3.jar:?]
... 1 more
Caused by: java.lang.NoSuchMethodError: com.sun.jna.platform.win32.OleAuto.VariantClear(Lcom/sun/jna/Pointer;)Lcom/sun/jna/platform/win32/WinNT$HRESULT;
at oshi.util.platform.windows.WmiUtil.enumerateProperties(WmiUtil.java:504) ~[oshi-core-3.2.jar:3.2]
at oshi.util.platform.windows.WmiUtil.queryWMI(WmiUtil.java:304) ~[oshi-core-3.2.jar:3.2]
at oshi.util.platform.windows.WmiUtil.selectUint32sFrom(WmiUtil.java:112) ~[oshi-core-3.2.jar:3.2]
at oshi.hardware.platform.windows.WindowsGlobalMemory.updateSwap(WindowsGlobalMemory.java:74) ~[oshi-core-3.2.jar:3.2]
at oshi.hardware.common.AbstractGlobalMemory.getSwapTotal(AbstractGlobalMemory.java:82) ~[oshi-core-3.2.jar:3.2] 

So what I need to do is figure out how to have both versions in the uberjar.

I've tried relocating the 4.3.0 version, but it didn't seem to work (the classes weren't in the uberjar anywhere). Further I swear I read earlier today (but of course can't find it now) that the pattern in the relocation field is groupId:artifactId[:type][:classifier] with no option for version.

The relevant portion of my dependency tree looks like this:

myproject
+-oshi-core
|   +- jna 4.2.2
+-jna 4.3.0-CUSTOM

Can anyone give me any suggestions on how to resolve this? Thanks!

Kevin Milner
  • 821
  • 2
  • 14
  • 30
  • By relocating do you mean moving the jar from one module to another? Or what exactly does that mean? Also could you share the bare minimum dependencies that you finally end up in your pom with both `oshi` and customized `JNA` please. – Naman Dec 07 '16 at 19:42
  • I updated the question in response. – Kevin Milner Dec 07 '16 at 20:27
  • If both these implementation conflicts with each other, why would you want to use both the dependencies in that case? – Naman Dec 07 '16 at 20:36
  • Also *oshi uses a function in 4.2.2 that doesn't seem to be in 4.3.0 (no idea why)* ....its a custom build, correct? – Naman Dec 07 '16 at 20:37
  • no, oshi uses 4.2.2 and is expecting a specific function to have a given interface. What we did was make a submission for a fix or feature (it was my boss who did it so I'm not sure on the details) to be pulled in to the next version of jna, which will be 4.3.0. Unfortunately, someone else in the opensource world changed the interface of that specific function, and so now we get a NoSuchMethodError exception. – Kevin Milner Dec 07 '16 at 20:49
  • 1
    what we ended up doing was forking oshi, giving it a new version and having oshi depend on our jna artifact. Then we reference our custom version of Oshi. This is a pain in the butt from a maintenance standpoint, but it get us working. At least we have our own nexus repo. – Kevin Milner Dec 08 '16 at 20:51
  • I am having the same issue.https://github.com/Vatuu/discord-rpc/pull/35 tried shading the library itself but that seems to be difficult – Alex May 04 '19 at 16:34

1 Answers1

0

What you are looking for is probably <includes> implementation of the maven-shade-plugin as documented here

Of course, <includes> can be used as well to specify a white list of artifacts. Artifacts are denoted by a composite idenitifer of the form groupId:artifactId[[:type]:classifier]. Since plugin version 1.3, the wildcard characters '*' and '?' can be used to do glob-like pattern matching.

For fine-grained control of which classes from the selected dependencies are included, artifact filters can be used:

e.g

<configuration>
     <filters>
         <filter>
            <artifact>com.github.dblock:oshi-core</artifact>
            <includes>
                <include><!--some package you want to include here--></include>
            </includes>
         </filter>
         <filter>
            <artifact>net.java.dev.jna:jna</artifact>
            <includes>
                <include><!--the package from 4.2.0 you want to keep--></include>
            </includes>
          </filter>
      </filters>
</configuration>
Naman
  • 27,789
  • 26
  • 218
  • 353
  • the problem isn't so much including the dependency, but that the dependency class files, in the uberjar, is stored in a directory ./net/java/dev/jna/. Since there's no way to specify the version and the class files have the same name name, whichever writes last wins. For what its worth, the change that breaks everything appears to be here: https://github.com/java-native-access/jna/commit/61bd36b0d05d18008377cd9d011be0c794f86296 – Kevin Milner Dec 07 '16 at 20:23