Skip to content

Commit afe795a

Browse files
authored
Merge pull request #411 from scijava/fix-logservice-calling-class
LogService: Make getLevel() more robust against ClassNotFoundException
2 parents 13c1763 + b80f6fe commit afe795a

File tree

4 files changed

+46
-10
lines changed

4 files changed

+46
-10
lines changed

src/main/java/org/scijava/log/AbstractLogService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public LogSource getSource() {
104104
@Override
105105
public int getLevel() {
106106
if (classAndPackageLevels.isEmpty()) return currentLevel;
107-
return getLevelForClass(CallingClassUtils.getCallingClass().getName(),
107+
return getLevelForClass(CallingClassUtils.getCallingClassName(),
108108
currentLevel);
109109
}
110110

src/main/java/org/scijava/log/CallingClassUtils.java

+34
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
package org.scijava.log;
3131

32+
import org.scijava.Context;
33+
3234
/**
3335
* Utility class for getting the calling class of a method.
3436
*
@@ -43,12 +45,44 @@ private CallingClassUtils() {
4345
}
4446

4547
/**
48+
* Inspects the stack trace to return the name of the class that calls
49+
* this method, but ignores every class annotated with @IgnoreAsCallingClass.
50+
* <p>
51+
* If every class on the stack trace is annotated, then the class at the
52+
* root of the stack trace is returned.
53+
*/
54+
public static String getCallingClassName() {
55+
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
56+
for (int i = 1; i < stackTrace.length - 2; i++) {
57+
String className = stackTrace[i].getClassName();
58+
if (!hasIgnoreAsCallingClassAnnotation(className)) return className;
59+
}
60+
return stackTrace[stackTrace.length - 1].getClassName();
61+
}
62+
63+
private static boolean hasIgnoreAsCallingClassAnnotation(String className) {
64+
try {
65+
Class< ? > clazz = Context.getClassLoader().loadClass(className);
66+
return clazz.isAnnotationPresent(IgnoreAsCallingClass.class);
67+
}
68+
catch (ClassNotFoundException ignore) {
69+
return false;
70+
}
71+
}
72+
73+
/**
74+
* @deprecated Use {@link #getCallingClassName()} instead.
75+
*
76+
* Warning: This method throws a IllegalStateException as soon as it comes
77+
* across a class that can't be loaded with the default class loader.
78+
*
4679
* Inspects the stack trace to return the class that calls this method, but
4780
* ignores every class annotated with @IgnoreAsCallingClass.
4881
*
4982
* @throws IllegalStateException if every method on the stack, is in a class
5083
* annotated with @IgnoreAsCallingClass.
5184
*/
85+
@Deprecated
5286
public static Class<?> getCallingClass() {
5387
try {
5488
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

src/main/java/org/scijava/log/IgnoreAsCallingClass.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
/**
3636
* Classes annotated with {@link IgnoreAsCallingClass} are ignored by
37-
* {@link CallingClassUtils#getCallingClass()}.
37+
* {@link CallingClassUtils#getCallingClassName()}.
3838
*
3939
* @author Matthias Arzt
4040
*/

src/test/java/org/scijava/log/CallingClassUtilsTest.java

+10-8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
import org.junit.Test;
3333

34+
import java.util.function.Supplier;
35+
3436
import static org.junit.Assert.assertEquals;
3537

3638
/**
@@ -41,26 +43,26 @@
4143
public class CallingClassUtilsTest {
4244
@Test
4345
public void testGetCallingClass() {
44-
Class<?> callingClass = CallingClassUtils.getCallingClass();
45-
assertEquals(this.getClass(), callingClass);
46+
String callingClass = CallingClassUtils.getCallingClassName();
47+
assertEquals(this.getClass().getName(), callingClass);
4648
}
4749

4850
@Test
4951
public void testIgnoreAsCallingClass() {
50-
assertEquals(ClassA.class, ClassA.returnGetCallingClass());
51-
assertEquals(this.getClass(), ClassB.returnGetCallingClass());
52+
assertEquals(ClassA.class.getName(), ClassA.returnGetCallingClass());
53+
assertEquals(this.getClass().getName(), ClassB.returnGetCallingClass());
5254
}
5355

5456
public static class ClassA {
55-
static Class<?> returnGetCallingClass() {
56-
return CallingClassUtils.getCallingClass();
57+
static String returnGetCallingClass() {
58+
return CallingClassUtils.getCallingClassName();
5759
}
5860
}
5961

6062
@IgnoreAsCallingClass
6163
private static class ClassB {
62-
static Class<?> returnGetCallingClass() {
63-
return CallingClassUtils.getCallingClass();
64+
static String returnGetCallingClass() {
65+
return CallingClassUtils.getCallingClassName();
6466
}
6567
}
6668
}

0 commit comments

Comments
 (0)