[ https://issues.apache.org/jira/browse/GROOVY-9742?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17943515#comment-17943515 ]
ASF GitHub Bot commented on GROOVY-9742: ---------------------------------------- paulk-asert opened a new pull request, #2185: URL: https://github.com/apache/groovy/pull/2185 …Put() hang (additional flexibility) > GroovyClassLoader.parseClass() StampedCommonCache.getAndPut() hang > ------------------------------------------------------------------ > > Key: GROOVY-9742 > URL: https://issues.apache.org/jira/browse/GROOVY-9742 > Project: Groovy > Issue Type: Bug > Components: groovy-runtime > Affects Versions: 3.0.5 > Environment: Java version AdoptOpenJDK (build 25.262-b10, mixed mode) > Gradle version 6.6.1 > Groovy version 3.0.5 > Reporter: Chiang Seng Chang > Assignee: Daniel Sun > Priority: Major > Fix For: 5.0.0-alpha-13 > > Attachments: g3cl.tar.gz > > > We have an IDE-like app which allows our coders to develop groovy scripts and > classes. > Essentially, the coders would write groovy sources and test them in the app. > We made a CustomClassLoader which is created and destroyed for each test run, > so that the app need no be restarted every time there is code change. > In Groovy 3.0.5, the GroovyClassLoader's cache is refactored to use > StampedCommonCache, which does not support recursion. > This is the distilled simplified version of our CustomClassLoader: > {noformat} > public class CustomGroovyClassLoader extends ClassLoader { > public CustomGroovyClassLoader(ClassLoader parent) { > super(parent); > groovyClassLoader = new GroovyClassLoader(this); > } > private final File srcDir = new File("./src/main/groovy"); > private final GroovyClassLoader groovyClassLoader; > @Override > protected Class<?> loadClass(String name, boolean resolve) > throws ClassNotFoundException { > synchronized (getClassLoadingLock(name)) { > Class<?> c = doFindClass(name); > if (c != null) { > if (resolve) { > resolveClass(c); > } > return c; > } > } > return super.loadClass(name, resolve); > } > private Class<?> doFindClass(String name) { > File classFile = new File(srcDir, name.replace('.', '/') + ".groovy"); > if (classFile.exists()) { > try { > System.out.println("PARSE\t: " + name); > Class<?> clz = groovyClassLoader.parseClass(classFile); > System.out.println("PARSED\t: " + clz); > return clz; > } > catch (IOException e) { > throw new RuntimeException(e); > } > } > return null; > } > } > {noformat} > Essentially, it uses the GroovyClassLoader.parseClass() for our test classes. > Here are the 2 classes to demonstrate the issue: > {noformat} > package foo > import groovy.transform.CompileStatic > @CompileStatic > interface Bar {} > {noformat} > {noformat} > package foo > import groovy.transform.CompileStatic > @CompileStatic > class Foo implements Bar {} > {noformat} > And the test harness: > {noformat} > package foo; > public class TestHarness { > public static void main(String[] args) throws Exception { > ClassLoader pcl = TestHarness.class.getClassLoader(); > CustomGroovyClassLoader ccl = new CustomGroovyClassLoader(pcl); > Class<?> clz = ccl.loadClass("foo.Foo"); > System.out.println("DONE\t: " + clz); > } > } > {noformat} > The harness attempt to load Foo.groovy. > The sequence of events would be: > # CustomClassLoader.loadClass(Foo) > # GroovyClassLoader.parseClass(Foo.groovy) > # sourceCache.getAndPut(Foo) > # Since Foo implements Bar, CustomClassLoader is called to load Bar > # which in turn calls GroovyClassLoader.parseClass(Bar.groovy) > # and sourceCache.getAndPut(Bar) > # Since StampedCommonCache does not support recursion, the loading hangs. > The attached project can be run using ./gradlew run to demonstrate the > hanging. > It seems to me that the GroovyClassLoader needs to support recursion for this > use case. > Or perhaps the CustomClassLoader is implemented wrongly? > Groovy 2.5.12 does not have this issue because its GroovyClassLoader uses > ConcurrentCommonCache. > > > -- This message was sent by Atlassian Jira (v8.20.10#820010)