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