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..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. * @@ -43,12 +45,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 = Context.getClassLoader().loadClass(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(); } } }