From bbd91e9b2f47612b1ba6f4ac3f0d8cedd547bac6 Mon Sep 17 00:00:00 2001 From: Jan Eglinger Date: Sun, 20 Jun 2021 17:21:42 +0200 Subject: [PATCH] Add NameService and NameProvider This change allows to define a way to derive names from objects of third party libraries, e.g. for use in ObjectService, where objects are registered with a name and can be provided e.g. in a drop-down choice in the UI. --- .../java/org/scijava/names/NameProvider.java | 12 ++++ .../java/org/scijava/names/NameService.java | 27 +++++++ .../org/scijava/object/ObjectService.java | 6 ++ .../java/org/scijava/ContextCreationTest.java | 1 + .../org/scijava/names/NameProviderTest.java | 70 +++++++++++++++++++ .../org/scijava/object/ObjectServiceTest.java | 13 +++- 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/scijava/names/NameProvider.java create mode 100644 src/main/java/org/scijava/names/NameService.java create mode 100644 src/test/java/org/scijava/names/NameProviderTest.java diff --git a/src/main/java/org/scijava/names/NameProvider.java b/src/main/java/org/scijava/names/NameProvider.java new file mode 100644 index 000000000..e358ea74c --- /dev/null +++ b/src/main/java/org/scijava/names/NameProvider.java @@ -0,0 +1,12 @@ +package org.scijava.names; + +import org.scijava.plugin.HandlerPlugin; + +public interface NameProvider extends HandlerPlugin { + public String getName(Object thing); + + @Override + default Class getType() { + return Object.class; + } +} diff --git a/src/main/java/org/scijava/names/NameService.java b/src/main/java/org/scijava/names/NameService.java new file mode 100644 index 000000000..f46b64370 --- /dev/null +++ b/src/main/java/org/scijava/names/NameService.java @@ -0,0 +1,27 @@ +package org.scijava.names; + +import org.scijava.plugin.AbstractHandlerService; +import org.scijava.plugin.HandlerService; +import org.scijava.plugin.Plugin; +import org.scijava.service.SciJavaService; +import org.scijava.service.Service; + +@Plugin(type=Service.class) +public class NameService extends AbstractHandlerService implements HandlerService, SciJavaService { + + @Override + public Class getPluginType() { + return NameProvider.class; + } + + @Override + public Class getType() { + return Object.class; + } + + public String getName(Object thing) { + NameProvider handler = getHandler(thing); + if (handler == null) return null; + return handler.getName(thing); + } +} diff --git a/src/main/java/org/scijava/object/ObjectService.java b/src/main/java/org/scijava/object/ObjectService.java index e68eaf1c4..37b81fe6e 100644 --- a/src/main/java/org/scijava/object/ObjectService.java +++ b/src/main/java/org/scijava/object/ObjectService.java @@ -33,6 +33,7 @@ import org.scijava.Named; import org.scijava.event.EventService; +import org.scijava.names.NameService; import org.scijava.object.event.ObjectsAddedEvent; import org.scijava.object.event.ObjectsRemovedEvent; import org.scijava.service.SciJavaService; @@ -72,10 +73,15 @@ default String getName(final Object obj) { if (obj == null) throw new NullPointerException(); final String name = getIndex().getName(obj); if (name != null) return name; + // Instances of Named if (obj instanceof Named) { final String n = ((Named) obj).getName(); if (n != null) return n; } + // Objects for which a NameProvider exists + final String name2 = context().service(NameService.class).getName(obj); + if (name2 != null) return name2; + // Fallback final String s = obj.toString(); if (s != null) return s; return obj.getClass().getName() + "@" + Integer.toHexString(obj.hashCode()); diff --git a/src/test/java/org/scijava/ContextCreationTest.java b/src/test/java/org/scijava/ContextCreationTest.java index ccf76e426..192499ebe 100644 --- a/src/test/java/org/scijava/ContextCreationTest.java +++ b/src/test/java/org/scijava/ContextCreationTest.java @@ -101,6 +101,7 @@ public void testFull() { org.scijava.main.DefaultMainService.class, org.scijava.menu.DefaultMenuService.class, org.scijava.module.DefaultModuleService.class, + org.scijava.names.NameService.class, org.scijava.object.DefaultObjectService.class, org.scijava.options.DefaultOptionsService.class, org.scijava.parse.DefaultParseService.class, diff --git a/src/test/java/org/scijava/names/NameProviderTest.java b/src/test/java/org/scijava/names/NameProviderTest.java new file mode 100644 index 000000000..92ff4ce8a --- /dev/null +++ b/src/test/java/org/scijava/names/NameProviderTest.java @@ -0,0 +1,70 @@ +package org.scijava.names; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.plugin.AbstractHandlerPlugin; +import org.scijava.plugin.Plugin; +import org.scijava.plugin.PluginInfo; +import org.scijava.plugin.PluginService; + +public class NameProviderTest { + + private Context context; + + @Before + public void setUp() throws Exception { + context = new Context(); + context.service(PluginService.class).addPlugin(PluginInfo.create(ThirdPartyObjectNameProvider.class, NameProvider.class)); + } + + @After + public void tearDown() throws Exception { + context.dispose(); + } + + @Test + public void test() { + String expected = "foo"; + ThirdPartyObject foo = new ThirdPartyObject(expected); + NameProvider handler = context.service(NameService.class).getHandler(foo); + assertNotNull(handler); + assertEquals(expected, handler.getName(foo)); + } + + public static class ThirdPartyObjectNameProvider extends AbstractHandlerPlugin implements NameProvider { + + @Override + public String getName(Object thing) { + return ((ThirdPartyObject) thing).someNonStandardMethod(); + } + + @Override + public boolean supports(Object thing) { + //System.err.println("NameProvider queried with " + thing + " of class " + thing.getClass()); + return ThirdPartyObject.class.isAssignableFrom(thing.getClass()); + } + + } + + public static class ThirdPartyObject { + private String name; + + public ThirdPartyObject (String name) { + this.name = name; + } + + public String someNonStandardMethod() { + return name; + } + + @Override + public String toString() { + return null; + } + } +} diff --git a/src/test/java/org/scijava/object/ObjectServiceTest.java b/src/test/java/org/scijava/object/ObjectServiceTest.java index 0a473a3ba..e080c2a48 100644 --- a/src/test/java/org/scijava/object/ObjectServiceTest.java +++ b/src/test/java/org/scijava/object/ObjectServiceTest.java @@ -37,7 +37,12 @@ import org.junit.Before; import org.junit.Test; import org.scijava.Context; +import org.scijava.names.NameProviderTest.ThirdPartyObject; +import org.scijava.names.NameProviderTest.ThirdPartyObjectNameProvider; +import org.scijava.names.NameProvider; +import org.scijava.names.NameService; import org.scijava.plugin.PluginInfo; +import org.scijava.plugin.PluginService; import org.scijava.plugin.SciJavaPlugin; public class ObjectServiceTest { @@ -47,7 +52,7 @@ public class ObjectServiceTest { @Before public void setUp() { - context = new Context(ObjectService.class); + context = new Context(ObjectService.class, NameService.class, PluginService.class); objectService = context.getService(ObjectService.class); } @@ -64,6 +69,8 @@ public void testAddRemoveObjects() { Object obj3 = new Double(0.3); PluginInfo obj4 = PluginInfo.create(TestPlugin.class, SciJavaPlugin.class); obj4.setName("TestPlugin name"); + String name5 = "Third-party object"; + ThirdPartyObject obj5 = new ThirdPartyObject(name5); objectService.addObject(obj1, name1); assertEquals("Name of object 1", name1, objectService.getName(obj1)); @@ -74,6 +81,10 @@ public void testAddRemoveObjects() { objectService.addObject(obj4); assertNotNull(objectService.getName(obj4)); assertEquals("Name of object 4", obj4.getName(), objectService.getName(obj4)); + assertNotNull(objectService.getName(obj5)); + assertEquals("Name of object 5 before adding NameProvider", obj5.getClass().getName() + "@" + Integer.toHexString(obj5.hashCode()), objectService.getName(obj5)); + context.service(PluginService.class).addPlugin(PluginInfo.create(ThirdPartyObjectNameProvider.class, NameProvider.class)); + assertEquals("Name of object 5 after adding NameProvider", obj5.someNonStandardMethod(), objectService.getName(obj5)); assertTrue("Object 1 registered", objectService.getObjects(Object.class).contains(obj1)); assertTrue("Object 2 registered", objectService.getObjects(Object.class).contains(obj2));