Skip to content

Commit 71ad4d5

Browse files
committed
Merge pull request #230 from scijava/load-class-loudly
Do proper exception handling when loading classes
2 parents 837b9de + 7f9576d commit 71ad4d5

File tree

7 files changed

+93
-27
lines changed

7 files changed

+93
-27
lines changed

src/main/java/org/scijava/Context.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,7 @@ public <S extends Service> S service(final Class<S> c) {
320320
* service.
321321
*/
322322
public Service service(final String className) {
323-
final Class<?> c = ClassUtils.loadClass(className);
324-
if (c == null) {
325-
throw new IllegalArgumentException("No such class: " + className);
326-
}
323+
final Class<?> c = ClassUtils.loadClass(className, false);
327324
if (!Service.class.isAssignableFrom(c)) {
328325
throw new IllegalArgumentException("Not a service class: " + c.getName());
329326
}

src/main/java/org/scijava/main/DefaultMainService.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,13 @@ public String[] args() {
101101
@Override
102102
public void exec() {
103103
try {
104-
final Class<?> mainClass = ClassUtils.loadClass(className);
104+
final Class<?> mainClass = ClassUtils.loadClass(className, false);
105105
final Method main = mainClass.getMethod("main", String[].class);
106106
main.invoke(null, new Object[] { args });
107107
}
108+
catch (final IllegalArgumentException exc) {
109+
if (log != null) log.error(exc);
110+
}
108111
catch (final NoSuchMethodException exc) {
109112
if (log != null) {
110113
log.error("No main method for class: " + className, exc);

src/main/java/org/scijava/menu/ShadowMenu.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,20 @@ public URL getIconURL() {
231231
else return null;
232232
}
233233
final String className = moduleInfo.getDelegateClassName();
234-
final Class<?> c = ClassUtils.loadClass(className);
235-
if (c == null) return null;
236-
final URL iconURL = c.getResource(iconPath);
237-
if (iconURL == null) {
238-
if (log != null) log.error("Could not load icon: " + iconPath);
234+
try {
235+
final Class<?> c = ClassUtils.loadClass(className, false);
236+
final URL iconURL = c.getResource(iconPath);
237+
if (iconURL == null) {
238+
if (log != null) log.error("Could not load icon: " + iconPath);
239+
}
240+
return iconURL;
241+
}
242+
catch (final IllegalArgumentException exc) {
243+
final String message = "Could not load icon for class: " + className;
244+
if (log.isDebug()) log.debug(message, exc);
245+
else log.error(message);
246+
return null;
239247
}
240-
return iconURL;
241248
}
242249

243250
/**

src/main/java/org/scijava/plugin/PluginInfo.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,13 +280,15 @@ public String getClassName() {
280280
@Override
281281
public Class<? extends PT> loadClass() throws InstantiableException {
282282
if (pluginClass == null) {
283-
final Class<?> c = ClassUtils.loadClass(className, classLoader);
284-
if (c == null) {
285-
throw new InstantiableException("Class not found: " + className);
283+
try {
284+
final Class<?> c = ClassUtils.loadClass(className, classLoader, false);
285+
@SuppressWarnings("unchecked")
286+
final Class<? extends PT> typedClass = (Class<? extends PT>) c;
287+
pluginClass = typedClass;
288+
}
289+
catch (final IllegalArgumentException exc) {
290+
throw new InstantiableException("Class not found: " + className, exc);
286291
}
287-
@SuppressWarnings("unchecked")
288-
final Class<? extends PT> typedClass = (Class<? extends PT>) c;
289-
pluginClass = typedClass;
290292
}
291293

292294
return pluginClass;

src/main/java/org/scijava/script/DefaultScriptService.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,16 @@ public synchronized Class<?> lookupClass(final String alias)
255255
final Class<?> type = aliasMap().get(alias);
256256
if (type != null) return type;
257257

258-
final Class<?> c = ClassUtils.loadClass(alias);
259-
if (c != null) {
258+
try {
259+
final Class<?> c = ClassUtils.loadClass(alias, false);
260260
aliasMap().put(alias, c);
261261
return c;
262262
}
263-
264-
throw new ScriptException("Unknown type: " + alias);
263+
catch (final IllegalArgumentException exc) {
264+
final ScriptException se = new ScriptException("Unknown type: " + alias);
265+
se.initCause(exc);
266+
throw se;
267+
}
265268
}
266269

267270
// -- PTService methods --

src/main/java/org/scijava/util/ClassUtils.java

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,48 @@ private ClassUtils() {
9393
* Loads the class with the given name, using the current thread's context
9494
* class loader, or null if it cannot be loaded.
9595
*
96+
* @param name The name of the class to load.
9697
* @return The loaded class, or null if the class could not be loaded.
97-
* @see #loadClass(String, ClassLoader)
98+
* @see #loadClass(String, ClassLoader, boolean)
9899
*/
99-
public static Class<?> loadClass(final String className) {
100-
return loadClass(className, null);
100+
public static Class<?> loadClass(final String name) {
101+
return loadClass(name, null, true);
102+
}
103+
104+
/**
105+
* Loads the class with the given name, using the specified
106+
* {@link ClassLoader}, or null if it cannot be loaded.
107+
*
108+
* @param name The name of the class to load.
109+
* @param classLoader The class loader with which to load the class; if null,
110+
* the current thread's context class loader will be used.
111+
* @return The loaded class, or null if the class could not be loaded.
112+
* @see #loadClass(String, ClassLoader, boolean)
113+
*/
114+
public static Class<?> loadClass(final String name,
115+
final ClassLoader classLoader)
116+
{
117+
return loadClass(name, classLoader, true);
118+
}
119+
120+
/**
121+
* Loads the class with the given name, using the current thread's context
122+
* class loader.
123+
*
124+
* @param className the name of the class to load
125+
* @param quietly Whether to return {@code null} (rather than throwing
126+
* {@link IllegalArgumentException}) if something goes wrong loading
127+
* the class
128+
* @return The loaded class, or {@code null} if the class could not be loaded
129+
* and the {@code quietly} flag is set.
130+
* @see #loadClass(String, ClassLoader, boolean)
131+
* @throws IllegalArgumentException If the class cannot be loaded and the
132+
* {@code quietly} flag is not set.
133+
*/
134+
public static Class<?> loadClass(final String className,
135+
final boolean quietly)
136+
{
137+
return loadClass(className, null, quietly);
101138
}
102139

103140
/**
@@ -119,10 +156,16 @@ public static Class<?> loadClass(final String className) {
119156
* @param name The name of the class to load.
120157
* @param classLoader The class loader with which to load the class; if null,
121158
* the current thread's context class loader will be used.
122-
* @return The loaded class, or null if the class could not be loaded.
159+
* @param quietly Whether to return {@code null} (rather than throwing
160+
* {@link IllegalArgumentException}) if something goes wrong loading
161+
* the class
162+
* @return The loaded class, or {@code null} if the class could not be loaded
163+
* and the {@code quietly} flag is set.
164+
* @throws IllegalArgumentException If the class cannot be loaded and the
165+
* {@code quietly} flag is not set.
123166
*/
124167
public static Class<?> loadClass(final String name,
125-
final ClassLoader classLoader)
168+
final ClassLoader classLoader, final boolean quietly)
126169
{
127170
// handle primitive types
128171
if (name.equals("Z") || name.equals("boolean")) return boolean.class;
@@ -170,7 +213,8 @@ public static Class<?> loadClass(final String name,
170213
// Not ClassNotFoundException.
171214
// Not NoClassDefFoundError.
172215
// Not UnsupportedClassVersionError!
173-
return null;
216+
if (quietly) return null;
217+
throw new IllegalArgumentException("Cannot load class: " + className, t);
174218
}
175219
}
176220

src/test/java/org/scijava/util/ClassUtilsTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ public void testLoadClass() {
116116
assertLoaded(Number[][].class, "[[Ljava.lang.Number;");
117117
}
118118

119+
@Test
120+
public void testFailureQuiet() {
121+
assertNull(ClassUtils.loadClass("a.non.existent.class"));
122+
}
123+
124+
@Test(expected = IllegalArgumentException.class)
125+
public void testFailureLoud() {
126+
ClassUtils.loadClass("a.non.existent.class", false);
127+
}
128+
119129
@Test
120130
public void testGetArrayClass() {
121131
assertSame(boolean[].class, ClassUtils.getArrayClass(boolean.class));

0 commit comments

Comments
 (0)