Hello
I have an extension of GroovyClassLoader that I use as follows
a) I override loadClass to make sure I decide where to load from
b) I first call loadClass on my parent class loader to make sure the class is
not loaded there (I assert if it is. This code is not shown below)
c) I then call loadClass after turning off all script loading on myclassloader
to make sure this class is not already loaded. If it is, I just use that
d) If I get a class not found exception, I know this class is not already
loaded and so I look up a local repository to fetch a string based script and
call parseClass (I do all of this in the context of loadClass)
This used to work with 2.5.x but when I upgrade to 3.0.5, it sits in a blocked
state (not sure if it is blocked on some mutex because of a recursion some
where). When I use my debugger , when it gets to this state, I am not able to
read any of my variable values in the debugger (which seems to indicate some
threading read lock somewhere)
Question :- Am I doing this the right way? Why does it block and not load the
class? It locks up in the parseClass invocation (inside a validate call that
validates the sourceCode object
My code looks like this
class MyClassLoader constructor(
private val repository: FlowsRepository,
private val configuration: CompilerConfiguration,
parentClassLoader: ClassLoader
) : GroovyClassLoader(parentClassLoader, configuration) {
/** Load class [name] either from repository or class path */
override fun loadClass(
name: String,
lookupScriptFiles: Boolean,
preferClassOverScript: Boolean,
resolve: Boolean
): Class<*> {
return try {
// Never try to load from script files, always parse from repository
super.loadClass(name, false, true, resolve)
} catch (e: ClassNotFoundException) {
// Try fetching it from the repository
parseFromRepository(name)
}
}
/** Parse [name] from the flow repository and cache it */
private fun parseFromRepository(name: String): Class<*> {
// Fetch flow source
val flow = repository.fetchFlow(name) ?: throw
ClassNotFoundException("Unable to find flow $name")
// Parse the class if found
try {
// If parseClass yields a class whose name does not match
(typically when we are trying to find an inner
// class (A.B) by parsing the outer class source file (A.groovy),
throw class not found. The compiler will
// attempt to then find A$B which is how inner classes are stored
in the class loader. This find will
// succeed (this process is repeated for inner classes inside inner
classes)
super.parseClass(flow.sourceCode, true)
// The class parsed may not be the class you are looking for, but
it may be an inner class, so
// use the cache to get it
return getClassCacheEntry(name) ?: throw
ClassNotFoundException("Unable to find flow $name")
} catch (e: CompilationFailedException) {
throw CodeQualityException("Compile error", e)
}
}
}