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)
        }
    }
}

Reply via email to