Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tubeness Op throws NullPointerException #173

Closed
gselzer opened this issue May 31, 2023 · 7 comments
Closed

Tubeness Op throws NullPointerException #173

gselzer opened this issue May 31, 2023 · 7 comments
Labels
bug Something isn't working

Comments

@gselzer
Copy link

gselzer commented May 31, 2023

Describe the bug
Running the Tubeness Op throws a NullPointerException when run with ops.run. I originally saw this running in napari-imagej

To Reproduce

  1. Ensure Neuroanatomy is enabled within Fiji
  2. Open the Script Editor, and paste the following groovy script in:
#@ Img input
#@ output Img out
#@ OpService ops

out = ops.create().img(input)
spacing = [2.0, 2.0]
scale = [2.0, 2.0]
numThreads = 2

ops.run("filter.tubeness", out, input, spacing, scale, numThreads)
  1. Click Run
  2. See error

Note that when I run in napari-imagej, I actually see a more detailed error:

[java.lang.Enum.toString] [ERROR] Command errored: filter.tubeness
java.lang.NullPointerException
	at net.imagej.ops.DefaultOpMatchingService.createModule(DefaultOpMatchingService.java:571)
	at net.imagej.ops.DefaultOpMatchingService.moduleConforms(DefaultOpMatchingService.java:486)
	at net.imagej.ops.DefaultOpMatchingService.filterMatches(DefaultOpMatchingService.java:292)
	at net.imagej.ops.DefaultOpMatchingService.filterMatches(DefaultOpMatchingService.java:137)
	at net.imagej.ops.DefaultOpMatchingService.findMatch(DefaultOpMatchingService.java:94)
	at net.imagej.ops.DefaultOpMatchingService.findMatch(DefaultOpMatchingService.java:82)
	at net.imagej.ops.OpEnvironment.module(OpEnvironment.java:253)
	at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:136)
	at net.imagej.ops.OpListingModule.run(OpListingModule.java:68)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:165)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:750)
[ERROR] Cannot create module: sc.fiji.snt.filter.Tubeness
org.scijava.module.ModuleException: org.scijava.InstantiableException: java.lang.InstantiationException: sc.fiji.snt.filter.Tubeness
	at org.scijava.command.CommandModule.instantiateCommand(CommandModule.java:251)
	at org.scijava.command.CommandModule.<init>(CommandModule.java:98)
	at org.scijava.command.CommandInfo.createModule(CommandInfo.java:326)
	at org.scijava.module.DefaultModuleService.createModule(DefaultModuleService.java:167)
	at net.imagej.ops.DefaultOpMatchingService.createModule(DefaultOpMatchingService.java:565)
	at net.imagej.ops.DefaultOpMatchingService.moduleConforms(DefaultOpMatchingService.java:486)
	at net.imagej.ops.DefaultOpMatchingService.filterMatches(DefaultOpMatchingService.java:292)
	at net.imagej.ops.DefaultOpMatchingService.filterMatches(DefaultOpMatchingService.java:137)
	at net.imagej.ops.DefaultOpMatchingService.findMatch(DefaultOpMatchingService.java:94)
	at net.imagej.ops.DefaultOpMatchingService.findMatch(DefaultOpMatchingService.java:82)
	at net.imagej.ops.OpEnvironment.module(OpEnvironment.java:253)
	at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:136)
	at net.imagej.ops.OpListingModule.run(OpListingModule.java:68)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:165)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:750)
Caused by: org.scijava.InstantiableException: java.lang.InstantiationException: sc.fiji.snt.filter.Tubeness
	at org.scijava.plugin.PluginInfo.createInstance(PluginInfo.java:309)
	at org.scijava.command.CommandInfo.createInstance(CommandInfo.java:248)
	at org.scijava.command.CommandModule.instantiateCommand(CommandModule.java:248)
	... 20 more
Caused by: java.lang.InstantiationException: sc.fiji.snt.filter.Tubeness
	at java.lang.Class.newInstance(Class.java:427)
	at org.scijava.plugin.PluginInfo.createInstance(PluginInfo.java:304)
	... 22 more
Caused by: java.lang.NoSuchMethodException: sc.fiji.snt.filter.Tubeness.<init>()
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.newInstance(Class.java:412)
	... 23 more

Expected behavior

The Op should run without error

Screenshots

image

Additional context

Fiji details:
(Output too long, can provide via Gist if it would be helpful)
Running Fiji 2.9.0/1.53t, Java 1.8.0_322

@tferr
Copy link
Member

tferr commented Jun 1, 2023

Thanks for the report! @carshadi, do you have time to look into it?

@tferr
Copy link
Member

tferr commented Jun 1, 2023

@gselzer, actually I don't understand why this happens.
If I understand correctly DefaultOpMatchingService finds this OP, but fails to create a Command, presumably because OpCandidate#OpInfo() is null!? Is this correct? How can we have it so OpInfo is not null? How do we set it?

Also, BTW, this op (written by @carshadi) improves the original tubeness Op, by allowing multiple scales (as in the Frangi op). At the time we did not submit it to net.imagej.ops because we had not done enough testing, but now we can confirm that it works great, so maybe now that is the time!?

@carshadi
Copy link
Member

carshadi commented Jun 1, 2023

According to this stack overflow post https://stackoverflow.com/a/18024061 , this can happen if the class doesn't have a default (empty) constructor.

@tferr
Copy link
Member

tferr commented Jun 1, 2023

Wow. That seems to fix it! I had never seen this before!

@tferr
Copy link
Member

tferr commented Jun 1, 2023

So adding a dummy constructor works:

    public Tubeness() {
       // do nothing
    }

However, setting it to private does not work. It needs to be public. But now if someone tries to use that constructor, the computation will fail because the spacing and scales fields are not set. What is the recommendation:

  1. make the empty constructor define the required fields using some sensible defaults
  2. Mention in the javadocs that the constructor is dummy and not to be used?

But above all, why does this happen? Funny enough the IDE suggests removing the empty constructor as it does nothing :)

@carshadi
Copy link
Member

carshadi commented Jun 2, 2023

For 1) I'm not sure there will be sensible defaults since getting a decent result requires knowing the voxel size of the image. 2) makes more sense to me. I am also not too familiar with how Op parameters are populated. Does running it in this way call the empty constructor and populate the @Parameter annotated fields with the given arguments?

ops.run("filter.tubeness", out, input, spacing, scale, numThreads)

tferr added a commit that referenced this issue Jun 2, 2023
@tferr
Copy link
Member

tferr commented Jun 2, 2023

OK. I think the empty constructor is needed earlier on by the OpService, when looking up which Ops are available. The fix is now in place with 47a319d

@tferr tferr closed this as completed Jun 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants