LegacyService and Groovy

Hi!

I am developing an ImageJ2 command in Groovy. I am running into classloader issues with the LegacyService:

Caught: java.lang.ExceptionInInitializerError
java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: Found incompatible ij.IJ class
	at net.imagej.patcher.LegacyEnvironment.initialize(LegacyEnvironment.java:113)
	at net.imagej.patcher.LegacyEnvironment.applyPatches(LegacyEnvironment.java:495)
	at net.imagej.patcher.LegacyInjector.preinit(LegacyInjector.java:397)
	at net.imagej.patcher.LegacyInjector.preinit(LegacyInjector.java:376)
	at net.imagej.patcher.LegacyInjector$preinit.call(Unknown Source)
	at PreProcessing.<clinit>(PreProcessing.groovy:523)
Caused by: java.lang.RuntimeException: Cannot load class: ij.ImagePlus (loader: org.codehaus.groovy.tools.RootLoader@6b884d57)
It appears that this class was already defined in the class loader!
Please make sure that you initialize the LegacyService before using
any ImageJ 1.x class. You can do that by adding this static initializer:

	static {
		LegacyInjector.preinit();
	}

To debug this issue, start the JVM with the option:

	-javaagent:/Users/radoslaw.ejsmont/.m2/repository/net/imagej/ij1-patcher/0.12.8/ij1-patcher-0.12.8.jar

To enforce pre-initialization, start the JVM with the option:

	-javaagent:/Users/radoslaw.ejsmont/.m2/repository/net/imagej/ij1-patcher/0.12.8/ij1-patcher-0.12.8.jar=init

	at net.imagej.patcher.CodeHacker.javaAgentHint(CodeHacker.java:828)
	at net.imagej.patcher.CodeHacker.loadClass(CodeHacker.java:807)
	at net.imagej.patcher.CodeHacker.loadClasses(CodeHacker.java:855)
	at net.imagej.patcher.LegacyInjector.injectHooks(LegacyInjector.java:116)
	at net.imagej.patcher.LegacyEnvironment.initialize(LegacyEnvironment.java:101)
	... 5 more
Caused by: java.lang.LinkageError: loader (instance of  org/codehaus/groovy/tools/RootLoader): attempted  duplicate class definition for name: "ij/ImagePlus"
	at javassist.util.proxy.DefineClassHelper.toClass3(DefineClassHelper.java:152)
	at javassist.util.proxy.DefineClassHelper.toClass2(DefineClassHelper.java:134)
	at javassist.util.proxy.DefineClassHelper.toClass(DefineClassHelper.java:95)
	at javassist.ClassPool.toClass(ClassPool.java:1143)
	at javassist.CtClass.toClass(CtClass.java:1316)
	at net.imagej.patcher.CodeHacker.loadClass(CodeHacker.java:801)
	... 8 more

Process finished with exit code 1

I have tried adding LegacyInjector to main command class, but the error persists.

    static void main(String... args) {
        setLoggingLevel(Level.INFO)
        final ImageJ ij = new ImageJ()
        ij.launch(args)
        ij.command().run(PreProcessing.class, true)
    }

    static {
        LegacyInjector.preinit()
    }

Running java with -javaagent:/Users/radoslaw.ejsmont/.m2/repository/net/imagej/ij1-patcher/0.12.8/ij1-patcher-0.12.8.jar also does not work.

Here is my pom.xml for reference:

    <parent>
        <groupId>org.scijava</groupId>
        <artifactId>pom-scijava</artifactId>
        <version>19.2.0</version>
        <relativePath />
    </parent>
    <dependencies>
        <dependency>
            <groupId>sc.fiji</groupId>
            <artifactId>HDF5_Vibez</artifactId>
            <version>0.2.99-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.13</version>
        </dependency>
        <dependency>
            <groupId>io.scif</groupId>
            <artifactId>scifio</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>net.imagej</groupId>
            <artifactId>imagej-legacy</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>io.scif</groupId>
            <artifactId>scifio-bf-compat</artifactId>
        </dependency>
        <dependency>
            <groupId>ome</groupId>
            <artifactId>formats-bsd</artifactId>
            <version>5.8.2</version>
        </dependency>
        <dependency>
            <groupId>ome</groupId>
            <artifactId>formats-gpl</artifactId>
            <version>5.8.2</version>
        </dependency>
    </dependencies>

Do you gals and guys have an idea?

Best,

R.

1 Like

When the main() method is implemented in a Java class, things work fine. So I guess it’s a Groovy classloader issue.

1 Like

@radoslaw.ejsmont are you running your Groovy command from the script editor?

In that case, I suppose the SciJava Context is already injected, and you shouldn’t call new ImageJ() in your main method.

So I’d suspect that the problem is not in your Command per se, but in the main method. Could you instead try to run your command using a context (or directly the CommandService) that you get via script parameters?

Something along these lines:

#@ CommandService commands

class PreProcessing implements Command {
    ...
}

commands.run(PreProcessing.class, true).get()

For further troubleshooting, it’ll help if you share the full source code of your command :wink:

Hi Jan,

I am running the command from the IDE. It runs perfectly from ImageJ. The problem occurs only when I try to supply my own main method. AFAIK the legacyService is fiddling with Java classloader, but somehow groovy classloader gets in its way. You can grab the code here:

I moved the main function to a separate java class so I can run it directly, but if you copy&paste this method to groovy file, it fails as described above.

Cheers and thanks!

R.