From 1e70db29dc461d25ce2c887e83c7851b12506d93 Mon Sep 17 00:00:00 2001 From: Matthias Arzt Date: Thu, 3 Dec 2020 15:47:10 +0100 Subject: [PATCH 1/8] LogService: Make getLevel() more robust against ClassNotFoundException --- .../org/scijava/log/AbstractLogService.java | 2 +- .../org/scijava/log/CallingClassUtils.java | 32 +++++++++++++++++++ .../org/scijava/log/IgnoreAsCallingClass.java | 2 +- .../scijava/log/CallingClassUtilsTest.java | 18 ++++++----- 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/scijava/log/AbstractLogService.java b/src/main/java/org/scijava/log/AbstractLogService.java index e813e10e3..e749bf59a 100644 --- a/src/main/java/org/scijava/log/AbstractLogService.java +++ b/src/main/java/org/scijava/log/AbstractLogService.java @@ -104,7 +104,7 @@ public LogSource getSource() { @Override public int getLevel() { if (classAndPackageLevels.isEmpty()) return currentLevel; - return getLevelForClass(CallingClassUtils.getCallingClass().getName(), + return getLevelForClass(CallingClassUtils.getCallingClassName(), currentLevel); } diff --git a/src/main/java/org/scijava/log/CallingClassUtils.java b/src/main/java/org/scijava/log/CallingClassUtils.java index 5bcf98460..bbe5357ed 100644 --- a/src/main/java/org/scijava/log/CallingClassUtils.java +++ b/src/main/java/org/scijava/log/CallingClassUtils.java @@ -43,12 +43,44 @@ private CallingClassUtils() { } /** + * Inspects the stack trace to return the name of the class that calls + * this method, but ignores every class annotated with @IgnoreAsCallingClass. + *

+ * If every class on the stack trace is annotated, then the class at the + * root of the stack trace is returned. + */ + public static String getCallingClassName() { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + for (int i = 1; i < stackTrace.length - 2; i++) { + String className = stackTrace[i].getClassName(); + if (!hasIgnoreAsCallingClassAnnotation(className)) return className; + } + return stackTrace[stackTrace.length - 1].getClassName(); + } + + private static boolean hasIgnoreAsCallingClassAnnotation(String className) { + try { + Class< ? > clazz = Class.forName(className); + return clazz.isAnnotationPresent(IgnoreAsCallingClass.class); + } + catch (ClassNotFoundException ignore) { + return false; + } + } + + /** + * @deprecated Use {@link #getCallingClassName()} instead. + * + * Warning: This method throws a IllegalStateException as soon as it comes + * across a class that can't be loaded with the default class loader. + * * Inspects the stack trace to return the class that calls this method, but * ignores every class annotated with @IgnoreAsCallingClass. * * @throws IllegalStateException if every method on the stack, is in a class * annotated with @IgnoreAsCallingClass. */ + @Deprecated public static Class getCallingClass() { try { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); diff --git a/src/main/java/org/scijava/log/IgnoreAsCallingClass.java b/src/main/java/org/scijava/log/IgnoreAsCallingClass.java index d6ff175f1..62aefe2db 100644 --- a/src/main/java/org/scijava/log/IgnoreAsCallingClass.java +++ b/src/main/java/org/scijava/log/IgnoreAsCallingClass.java @@ -34,7 +34,7 @@ /** * Classes annotated with {@link IgnoreAsCallingClass} are ignored by - * {@link CallingClassUtils#getCallingClass()}. + * {@link CallingClassUtils#getCallingClassName()}. * * @author Matthias Arzt */ diff --git a/src/test/java/org/scijava/log/CallingClassUtilsTest.java b/src/test/java/org/scijava/log/CallingClassUtilsTest.java index a23f8fee0..ff6d3df24 100644 --- a/src/test/java/org/scijava/log/CallingClassUtilsTest.java +++ b/src/test/java/org/scijava/log/CallingClassUtilsTest.java @@ -31,6 +31,8 @@ import org.junit.Test; +import java.util.function.Supplier; + import static org.junit.Assert.assertEquals; /** @@ -41,26 +43,26 @@ public class CallingClassUtilsTest { @Test public void testGetCallingClass() { - Class callingClass = CallingClassUtils.getCallingClass(); - assertEquals(this.getClass(), callingClass); + String callingClass = CallingClassUtils.getCallingClassName(); + assertEquals(this.getClass().getName(), callingClass); } @Test public void testIgnoreAsCallingClass() { - assertEquals(ClassA.class, ClassA.returnGetCallingClass()); - assertEquals(this.getClass(), ClassB.returnGetCallingClass()); + assertEquals(ClassA.class.getName(), ClassA.returnGetCallingClass()); + assertEquals(this.getClass().getName(), ClassB.returnGetCallingClass()); } public static class ClassA { - static Class returnGetCallingClass() { - return CallingClassUtils.getCallingClass(); + static String returnGetCallingClass() { + return CallingClassUtils.getCallingClassName(); } } @IgnoreAsCallingClass private static class ClassB { - static Class returnGetCallingClass() { - return CallingClassUtils.getCallingClass(); + static String returnGetCallingClass() { + return CallingClassUtils.getCallingClassName(); } } } From 2231238f85072c2460ed3148edeeb7fd13fe079c Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Wed, 25 Nov 2020 18:04:30 +0100 Subject: [PATCH 2/8] ScriptREPL: Add language parameter to constructor to indicate preference for a scripting language --- .../java/org/scijava/script/ScriptREPL.java | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/scijava/script/ScriptREPL.java b/src/main/java/org/scijava/script/ScriptREPL.java index d6c10adfd..edfafa538 100644 --- a/src/main/java/org/scijava/script/ScriptREPL.java +++ b/src/main/java/org/scijava/script/ScriptREPL.java @@ -69,6 +69,8 @@ public class ScriptREPL { private final PrintStream out; + private String languagePreference = null; + /** List of interpreter-friendly script languages. */ private List languages; @@ -88,6 +90,15 @@ public ScriptREPL(final Context context, final OutputStream out) { (PrintStream) out : new PrintStream(out); } + public ScriptREPL(final Context context, final String language) { + this(context, language, System.out); + } + + public ScriptREPL(final Context context, final String language, final OutputStream out) { + this(context, out); + languagePreference = language; + } + /** * Gets the list of languages compatible with the REPL. *

@@ -162,12 +173,35 @@ public void initialize(final boolean verbose) { } out.println("Have fun!"); out.println(); - lang(langs.get(0).getLanguageName()); + + if(languagePreference != null) { + selectPreferredLanguage(langs); + } else { + lang(langs.get(0).getLanguageName()); + } } - else if (!langs.isEmpty()) lang(langs.get(0)); + else if (!langs.isEmpty()) { + if(languagePreference != null) { + selectPreferredLanguage(langs); + } else { + lang(langs.get(0)); + } + } + populateBindings(interpreter.getBindings()); } + private void selectPreferredLanguage(List langs) { + final ScriptLanguage preference = langs + .stream().filter(lang -> languagePreference.equals(lang.getLanguageName())) + .findAny().orElse(null); + if(preference != null) { + lang(preference); + } else { + lang(langs.get(0).getLanguageName()); + } + } + /** Outputs the prompt. */ public void prompt() { out.print(interpreter == null || interpreter.isReady() ? "> " : "\\ "); @@ -310,8 +344,15 @@ public static void main(final String... args) throws Exception { // make a SciJava application context final Context context = new Context(); - // create the script interpreter - final ScriptREPL scriptCLI = new ScriptREPL(context); + // see if we have a preferred language + // and create the script interpreter + final ScriptREPL scriptCLI; + if(args.length > 0) { + final String preference = args[0]; + scriptCLI = new ScriptREPL(context, preference); + } else { + scriptCLI = new ScriptREPL(context); + } // start the REPL scriptCLI.loop(); From 5c3c7b74b09852b4430df183483a78d6a603ca1a Mon Sep 17 00:00:00 2001 From: Mark Hiner Date: Mon, 7 Dec 2020 11:08:53 -0600 Subject: [PATCH 3/8] Bump minor version Public API added in 2231238f85072c2460ed3148edeeb7fd13fe079c. --- pom.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 893a968ca..b2f1fe541 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ scijava-common - 2.85.1-SNAPSHOT + 2.86.0-SNAPSHOT SciJava Common SciJava Common is a shared library for SciJava software. It provides a plugin framework, with an extensible mechanism for service discovery, backed by its own annotation processor, so that plugins can be loaded dynamically. It is used by downstream projects in the SciJava ecosystem, such as ImageJ and SCIFIO. @@ -154,6 +154,8 @@ + 11 + 8 org.scijava bsd_2 From 509ff2b16613096f872a66c8a09475b8ec9d2d4a Mon Sep 17 00:00:00 2001 From: Mark Hiner Date: Mon, 7 Dec 2020 11:21:06 -0600 Subject: [PATCH 4/8] Remove accidental maven.compiler config --- pom.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pom.xml b/pom.xml index b2f1fe541..af0a9af81 100644 --- a/pom.xml +++ b/pom.xml @@ -154,8 +154,6 @@ - 11 - 8 org.scijava bsd_2 From 0aa57e4779b4e0ff4cd2627b5b4e8a24db86bd65 Mon Sep 17 00:00:00 2001 From: Mark Hiner Date: Mon, 7 Dec 2020 11:26:29 -0600 Subject: [PATCH 5/8] DataEventTest: make cross-platform Remove *nix-style path. --- .../java/org/scijava/io/event/DataEventTest.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/scijava/io/event/DataEventTest.java b/src/test/java/org/scijava/io/event/DataEventTest.java index 45568b12e..e2d9457cd 100644 --- a/src/test/java/org/scijava/io/event/DataEventTest.java +++ b/src/test/java/org/scijava/io/event/DataEventTest.java @@ -28,15 +28,20 @@ */ package org.scijava.io.event; -import org.junit.Test; - import static org.junit.Assert.assertEquals; +import java.io.File; +import java.io.IOException; + +import org.junit.Test; + public class DataEventTest { @Test - public void testDeprecatedMethods() { - String localPath = "/local/absolute/path.txt"; + public void testDeprecatedMethods() throws IOException { + File tmpFile = File.createTempFile("path", "txt"); + tmpFile.deleteOnExit(); + String localPath = tmpFile.getAbsolutePath(); Object obj = null; DataOpenedEvent openedEvent = new DataOpenedEvent(localPath, obj); DataSavedEvent savedEvent = new DataSavedEvent(localPath, obj); From 13c1763f0dcd06dfe4625798f644921ed4269b48 Mon Sep 17 00:00:00 2001 From: Mark Hiner Date: Mon, 7 Dec 2020 11:33:59 -0600 Subject: [PATCH 6/8] Bump to next development cycle Signed-off-by: Mark Hiner --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index af0a9af81..8065fba5a 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ scijava-common - 2.86.0-SNAPSHOT + 2.86.1-SNAPSHOT SciJava Common SciJava Common is a shared library for SciJava software. It provides a plugin framework, with an extensible mechanism for service discovery, backed by its own annotation processor, so that plugins can be loaded dynamically. It is used by downstream projects in the SciJava ecosystem, such as ImageJ and SCIFIO. From b80f6fe18be696716c2545a43440c14534e92115 Mon Sep 17 00:00:00 2001 From: Matthias Arzt Date: Wed, 9 Dec 2020 14:24:03 +0100 Subject: [PATCH 7/8] CallingClassUtils: replace Class.forName() with Context.getClassLoader() Class.forName() will fail if the threads class loader is not set. --- src/main/java/org/scijava/log/CallingClassUtils.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/scijava/log/CallingClassUtils.java b/src/main/java/org/scijava/log/CallingClassUtils.java index bbe5357ed..66bef3263 100644 --- a/src/main/java/org/scijava/log/CallingClassUtils.java +++ b/src/main/java/org/scijava/log/CallingClassUtils.java @@ -29,6 +29,8 @@ package org.scijava.log; +import org.scijava.Context; + /** * Utility class for getting the calling class of a method. * @@ -60,7 +62,7 @@ public static String getCallingClassName() { private static boolean hasIgnoreAsCallingClassAnnotation(String className) { try { - Class< ? > clazz = Class.forName(className); + Class< ? > clazz = Context.getClassLoader().loadClass(className); return clazz.isAnnotationPresent(IgnoreAsCallingClass.class); } catch (ClassNotFoundException ignore) { From 06b9c28ee4380ebf59e00770cc6a51c1f43d95b3 Mon Sep 17 00:00:00 2001 From: Jan Eglinger Date: Fri, 30 Oct 2020 16:28:35 +0100 Subject: [PATCH 8/8] AbstractConverter: make deprecated API consistent The canConvert(Class, Class) signature is deprecated in the Converter interface, so let's deprecate the overridden method as well, as it's the case for canConvert(Class, Type) already. --- .../scijava/convert/AbstractConverter.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/scijava/convert/AbstractConverter.java b/src/main/java/org/scijava/convert/AbstractConverter.java index 08699df4f..1fb2cade1 100644 --- a/src/main/java/org/scijava/convert/AbstractConverter.java +++ b/src/main/java/org/scijava/convert/AbstractConverter.java @@ -98,19 +98,9 @@ public boolean canConvert(final Object src, final Type dest) { public boolean canConvert(final Object src, final Class dest) { if (src == null) return false; final Class srcClass = src.getClass(); - return canConvert(srcClass, dest); } - @Override - public boolean canConvert(final Class src, final Class dest) { - if (src == null) return false; - final Class saneSrc = Types.box(src); - final Class saneDest = Types.box(dest); - return Types.isAssignable(saneSrc, getInputType()) && - Types.isAssignable(getOutputType(), saneDest); - } - @Override public Object convert(final Object src, final Type dest) { final Class destClass = Types.raw(dest); @@ -148,6 +138,16 @@ public Class getType() { // -- Deprecated API -- + @Override + @Deprecated + public boolean canConvert(final Class src, final Class dest) { + if (src == null) return false; + final Class saneSrc = Types.box(src); + final Class saneDest = Types.box(dest); + return Types.isAssignable(saneSrc, getInputType()) && + Types.isAssignable(getOutputType(), saneDest); + } + @Override @Deprecated public boolean canConvert(final Class src, final Type dest) {