Skip to content

Commit de98b21

Browse files
committed
MYFACES-4639 - Implementation ClassUtils needs "newInstance" methods added to support OSGI runtimes
1 parent d272b39 commit de98b21

2 files changed

Lines changed: 94 additions & 41 deletions

File tree

api/src/main/java/org/apache/myfaces/core/api/shared/lang/ClassUtils.java

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -116,36 +116,49 @@ public class ClassUtils
116116
}
117117

118118
/**
119-
* Tries a Class.loadClass with the context class loader of the current thread first and automatically falls back to
120-
* the ClassUtils class loader (i.e. the loader of the myfaces.jar lib) if necessary.
121-
*
119+
* Tries {@link Class#forName(String, boolean, ClassLoader)} with the context class loader first, then
120+
* {@code fallbackLoader} (e.g. the ClassUtils defining module) if the type is not found.
121+
*
122122
* @param type
123123
* fully qualified name of a non-primitive non-array class
124+
* @param fallbackLoader
125+
* loader used when the context class loader cannot resolve {@code type}; if {@code null}, no fallback
124126
* @return the corresponding Class
125127
* @throws NullPointerException
126128
* if type is null
127129
* @throws ClassNotFoundException
130+
* if the type cannot be resolved
128131
*/
129-
public static <T> Class<T> classForName(String type) throws ClassNotFoundException
132+
public static <T> Class<T> classForName(String type, ClassLoader fallbackLoader) throws ClassNotFoundException
130133
{
131134
Assert.notNull(type, "type");
132-
135+
133136
try
134137
{
135-
// Try WebApp ClassLoader first
136138
return (Class<T>) Class.forName(type,
137-
false, // do not initialize for faster startup
139+
false,
138140
getContextClassLoader());
139141
}
140142
catch (ClassNotFoundException ignore)
141143
{
142-
// fallback: Try ClassLoader for ClassUtils (i.e. the myfaces.jar lib)
144+
if (fallbackLoader == null)
145+
{
146+
throw ignore;
147+
}
143148
return (Class<T>) Class.forName(type,
144-
false, // do not initialize for faster startup
145-
ClassUtils.class.getClassLoader());
149+
false,
150+
fallbackLoader);
146151
}
147152
}
148153

154+
/**
155+
* Same as {@link #classForName(String, ClassLoader)} using {@code ClassUtils.class.getClassLoader()} as fallback.
156+
*/
157+
public static <T> Class<T> classForName(String type) throws ClassNotFoundException
158+
{
159+
return classForName(type, ClassUtils.class.getClassLoader());
160+
}
161+
149162
/**
150163
* Same as {@link #classForName(String)}, but throws a RuntimeException (FacesException) instead of a
151164
* ClassNotFoundException.
@@ -367,22 +380,62 @@ public static Object newInstance(String type) throws FacesException
367380
{
368381
return null;
369382
}
370-
return newInstance(simpleClassForName(type));
383+
return newInstance(type, ClassUtils.class.getClassLoader());
384+
}
385+
386+
/**
387+
* Like {@link #newInstance(String)} but uses {@code fallbackLoader} when resolving the class name (MYFACES-4639).
388+
*/
389+
public static Object newInstance(String type, ClassLoader fallbackLoader) throws FacesException
390+
{
391+
if (type == null)
392+
{
393+
return null;
394+
}
395+
try
396+
{
397+
return newInstance(classForName(type, fallbackLoader));
398+
}
399+
catch (ClassNotFoundException e)
400+
{
401+
log.log(Level.SEVERE, "Class " + type + " not found", e);
402+
throw new FacesException(e);
403+
}
371404
}
372405

373406
public static Object newInstance(String type, Class<?> expectedType) throws FacesException
374407
{
375-
return newInstance(type, expectedType == null ? null : new Class[] { expectedType });
408+
return newInstance(type, expectedType, ClassUtils.class.getClassLoader());
409+
}
410+
411+
public static Object newInstance(String type, Class<?> expectedType, ClassLoader fallbackLoader)
412+
throws FacesException
413+
{
414+
return newInstance(type, expectedType == null ? null : new Class[] { expectedType }, fallbackLoader);
376415
}
377416

378417
public static Object newInstance(String type, Class<?>[] expectedTypes)
418+
{
419+
return newInstance(type, expectedTypes, ClassUtils.class.getClassLoader());
420+
}
421+
422+
public static Object newInstance(String type, Class<?>[] expectedTypes, ClassLoader fallbackLoader)
379423
{
380424
if (type == null)
381425
{
382426
return null;
383427
}
384428

385-
Class<?> clazzForName = simpleClassForName(type);
429+
Class<?> clazzForName;
430+
try
431+
{
432+
clazzForName = classForName(type, fallbackLoader);
433+
}
434+
catch (ClassNotFoundException e)
435+
{
436+
log.log(Level.SEVERE, "Class " + type + " not found", e);
437+
throw new FacesException(e);
438+
}
386439

387440
if (expectedTypes != null)
388441
{

impl/src/main/java/org/apache/myfaces/util/lang/ClassUtils.java

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import java.util.Collection;
2727
import java.util.logging.Level;
2828
import java.util.logging.Logger;
29-
import org.apache.myfaces.core.api.shared.lang.Assert;
3029

3130

3231

@@ -190,36 +189,13 @@ public static <T> T wrapBackwardCompatible(Class<T> interfaceClass, Class<? exte
190189
}
191190

192191
/**
193-
* Tries a Class.loadClass with the context class loader of the current thread first and automatically falls back to
194-
* the ClassUtils class loader (i.e. the loader of the myfaces.jar lib) if necessary.
195-
*
196-
* @param type
197-
* fully qualified name of a non-primitive non-array class
198-
* @return the corresponding Class
199-
* @throws NullPointerException
200-
* if type is null
201-
* @throws ClassNotFoundException
192+
* MYFACES-4449: Delegates to API {@code classForName(String, ClassLoader)} with this module's ClassLoader
193+
* as fallback (OSGi / split API–impl).
202194
*/
203-
// @Override MYFACES-4449: Methods that call ClassUtils.class.getClassLoader() need to be here
204-
// as well as in the API ClassUtils so that the correct ClassLoader is used.
205195
public static <T> Class<T> classForName(String type) throws ClassNotFoundException
206196
{
207-
Assert.notNull(type, "type");
208-
209-
try
210-
{
211-
// Try WebApp ClassLoader first
212-
return (Class<T>) Class.forName(type,
213-
false, // do not initialize for faster startup
214-
getContextClassLoader());
215-
}
216-
catch (ClassNotFoundException ignore)
217-
{
218-
// fallback: Try ClassLoader for ClassUtils (i.e. the myfaces.jar lib)
219-
return (Class<T>) Class.forName(type,
220-
false, // do not initialize for faster startup
221-
ClassUtils.class.getClassLoader());
222-
}
197+
return org.apache.myfaces.core.api.shared.lang.ClassUtils.classForName(type,
198+
ClassUtils.class.getClassLoader());
223199
}
224200

225201
/**
@@ -348,4 +324,28 @@ protected static final String paramString(Class<?>... types)
348324
return null;
349325
}
350326

327+
/**
328+
* MYFACES-4639: Delegates to API {@code newInstance(String, ClassLoader)} with the impl module ClassLoader.
329+
*/
330+
// @Override
331+
public static Object newInstance(String type) throws FacesException
332+
{
333+
return org.apache.myfaces.core.api.shared.lang.ClassUtils.newInstance(type,
334+
ClassUtils.class.getClassLoader());
335+
}
336+
337+
// @Override
338+
public static Object newInstance(String type, Class<?> expectedType) throws FacesException
339+
{
340+
return org.apache.myfaces.core.api.shared.lang.ClassUtils.newInstance(type, expectedType,
341+
ClassUtils.class.getClassLoader());
342+
}
343+
344+
// @Override
345+
public static Object newInstance(String type, Class<?>[] expectedTypes)
346+
{
347+
return org.apache.myfaces.core.api.shared.lang.ClassUtils.newInstance(type, expectedTypes,
348+
ClassUtils.class.getClassLoader());
349+
}
350+
351351
}

0 commit comments

Comments
 (0)