Why does using the Java Attach API fail on linux? (even though maven build completes)
Asked Answered
D

1

4

I've been using the Java Attach API (part of tools.jar) to attach to a running java process, and shut it down from within.

It works perfectly on Windows. However when trying to actually execute the attach code when running on linux I get a java.lang.NoClassDefFoundError with the following stack trace for the cause...

java.lang.ClassNotFoundException:com.sun.tools.attach.VirtualMachine...
    java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    java.security.AccessController.doPrivileged(Native Method)
    java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    java.lang.ClassLoader.loadClass(ClassLoader.java:247)

I'm using Maven and so far I have this section, in order to include tools.jar.

<dependency>
    <groupId>com.sun</groupId>
    <artifactId>tools</artifactId>
    <version>1.4.2</version>
    <scope>system</scope>
    <systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>

Notably the ${java.home} evaluates to the jre but even if I change it to a direct path to the jdk, the issue is the same.

I'm pretty stumped...

Denotative answered 4/5, 2013 at 21:37 Comment(3)
What was the exception (and why did you not post that as part of the stack trace)?Holliholliday
Apologies, modified the post to add the Exception type (java.lang.ClassNotFoundException)Denotative
This is not a linux issue actually, it affects all instances run from command line (i.e. not eclipse). The system scope implies the jar will be provided by the container (which happens in eclipse, but not when simply running via java -jar). Experimenting with install:install-file goal so that the required jar is placed in the repo at build time.Denotative
D
5

Turns out this was an issue with the maven build. The system scope requires the container to pass tools.jar on the classpath at launch. A simple java -jar does not do this (and I don't want to add an explicit classpath argument).

The solution I put together to solve this issue is to have the maven build choose the location using profiles, then pre-install the jar in the local repo before the package phase (allowing the dependancy to just be normal dependancy).

PROFILES SECTION...

<profiles>
    <profile>
        <id>default-profile</id>
        <activation>
            <activeByDefault>true</activeByDefault>
            <file>
                <exists>${java.home}/../lib/tools.jar</exists>
            </file>
        </activation>
        <properties>
            <toolsjar>${java.home}/../lib/tools.jar</toolsjar>
        </properties>
    </profile>
    <profile>
        <id>osx_profile</id>
        <activation>
            <activeByDefault>false</activeByDefault>
            <os>
                <family>mac</family>
            </os>
        </activation>
        <properties>
            <toolsjar>${java.home}/../Classes/classes.jar</toolsjar>
        </properties>
    </profile>
</profiles> 

INSTALL-FILE SECTION...

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-install-plugin</artifactId>
    <executions>
        <execution>
            <id>jdk_tools</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>install-file</goal>
            </goals>
            <configuration>
                <groupId>com.sun</groupId>
                <artifactId>tools</artifactId>
                <version>1.4.2</version>
                <packaging>jar</packaging>
                <file>${toolsjar}</file>
            </configuration>
        </execution>
    </executions>
</plugin>

DEPENDANCY

<dependency>
    <groupId>com.sun</groupId>
    <artifactId>tools</artifactId>
    <version>1.4.2</version>
</dependency>
Denotative answered 8/5, 2013 at 16:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.