Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-41896

Static nested classes in global libraries can not be used from other classes in same package

      Baseline global Library code:

      Here is the base code for the example.
      I will add to each example where I change the code.

      jenkins.mkobit.example.FirstClass

      package jenkins.mkobit.example
      
      class FirstClass {
        FirstClass() {
        }
      }
      

      jenkins.mkobit.example.SiblingClass

      package jenkins.mkobit.example
      
      class SiblingClass {
        static class SiblingInner {
        }
      }
      

      Jenkinsfile examples:

      FirstClass creates an instance of sibling class

      jenkins.mkobit.example.FirstClass

      package jenkins.mkobit.example
      
      class FirstClass {
        FirstClass() {
          new SiblingClass()
        }
      }
      

      Jenkinsfile

      @Library('pipelineUtilities@mkobit-global-cps-test')
      import jenkins.mkobit.example.FirstClass
      
      def firstClass = new FirstClass()
      

      Result: SUCCESS

      FirstClass creates an instance of sibling static nested class in constructor

      jenkins.mkobit.example.FirstClass

      package jenkins.mkobit.example
      
      class FirstClass {
        FirstClass() {
          new SiblingClass.SiblingInner()
        }
      }
      

      Jenkinsfile

      @Library('pipelineUtilities@mkobit-global-cps-test')
      import jenkins.mkobit.example.FirstClass
      
      def firstClass = new FirstClass()
      

      Result: FAILURE - I expect this to work similarly to how normal Groovy code works. Instead, I get a failed compilation issue.

      BUG! exception in phase 'semantic analysis' in source unit 'WorkflowScript' The lookup for jenkins.mkobit.example.FirstClass caused a failed compilaton. There should not have been any compilation from this call.
      	at org.codehaus.groovy.control.ClassNodeResolver.tryAsLoaderClassOrScript(ClassNodeResolver.java:190)
      	at org.codehaus.groovy.control.ClassNodeResolver.findClassNode(ClassNodeResolver.java:170)
      	at org.codehaus.groovy.control.ClassNodeResolver.resolveName(ClassNodeResolver.java:126)
      	at org.codehaus.groovy.control.ResolveVisitor.resolveToOuter(ResolveVisitor.java:676)
      	at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:308)
      	at org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:1218)
      	at org.codehaus.groovy.control.ResolveVisitor.startResolving(ResolveVisitor.java:176)
      	at org.codehaus.groovy.control.CompilationUnit$11.call(CompilationUnit.java:651)
      	at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:931)
      	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:593)
      	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:542)
      	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
      	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
      	at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
      	at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
      	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:67)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:429)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:392)
      	at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:221)
      	at hudson.model.ResourceController.execute(ResourceController.java:98)
      	at hudson.model.Executor.run(Executor.java:405)
      Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
      /var/jenkins_home/jobs/ff/builds/29/libs/pipelineUtilities/src/jenkins/mkobit/example/FirstClass.groovy: 5: unable to resolve class SiblingClass.SiblingInner
       @ line 5, column 5.
             new SiblingClass.SiblingInner()
      

      FirstClass creates an instance of sibling static nested class when full classname imported in classfile

      jenkins.mkobit.example.FirstClass

      package jenkins.mkobit.example
      
      import jenkins.mkobit.example.SiblingClass.SiblingInner
      
      class FirstClass {
        FirstClass() {
          new SiblingInner()
        }
      }
      

      Jenkinsfile

      @Library('pipelineUtilities@mkobit-global-cps-test')
      import jenkins.mkobit.example.FirstClass
      
      def firstClass = new FirstClass()
      

      Result: FAILURE - I thought this might help out by forcing compilation.

      BUG! exception in phase 'semantic analysis' in source unit 'WorkflowScript' The lookup for jenkins.mkobit.example.FirstClass caused a failed compilaton. There should not have been any compilation from this call.
      	at org.codehaus.groovy.control.ClassNodeResolver.tryAsLoaderClassOrScript(ClassNodeResolver.java:190)
      	at org.codehaus.groovy.control.ClassNodeResolver.findClassNode(ClassNodeResolver.java:170)
      	at org.codehaus.groovy.control.ClassNodeResolver.resolveName(ClassNodeResolver.java:126)
      	at org.codehaus.groovy.control.ResolveVisitor.resolveToOuter(ResolveVisitor.java:676)
      	at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:308)
      	at org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:1218)
      	at org.codehaus.groovy.control.ResolveVisitor.startResolving(ResolveVisitor.java:176)
      	at org.codehaus.groovy.control.CompilationUnit$11.call(CompilationUnit.java:651)
      	at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:931)
      	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:593)
      	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:542)
      	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
      	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
      	at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
      	at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
      	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:67)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:429)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:392)
      	at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:221)
      	at hudson.model.ResourceController.execute(ResourceController.java:98)
      	at hudson.model.Executor.run(Executor.java:405)
      Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
      /var/jenkins_home/jobs/ff/builds/30/libs/pipelineUtilities/src/jenkins/mkobit/example/FirstClass.groovy: 3: unable to resolve class jenkins.mkobit.example.SiblingClass.SiblingInner
       @ line 3, column 1.
         import jenkins.mkobit.example.SiblingClass.SiblingInner
      

      FirstClass creates an instance of sibling static nested class when class is imported in Jenkinsfile

      jenkins.mkobit.example.FirstClass

      package jenkins.mkobit.example
      
      class FirstClass {
        FirstClass() {
          new SiblingClass.SiblingInner()
        }
      }
      

      Jenkinsfile

      @Library('pipelineUtilities@mkobit-global-cps-test')
      import jenkins.mkobit.example.SiblingClass
      import jenkins.mkobit.example.FirstClass
      
      def firstClass = new FirstClass()
      

      Result: FAILURE This also fails

      BUG! exception in phase 'semantic analysis' in source unit 'WorkflowScript' The lookup for jenkins.mkobit.example.FirstClass caused a failed compilaton. There should not have been any compilation from this call.
      	at org.codehaus.groovy.control.ClassNodeResolver.tryAsLoaderClassOrScript(ClassNodeResolver.java:190)
      	at org.codehaus.groovy.control.ClassNodeResolver.findClassNode(ClassNodeResolver.java:170)
      	at org.codehaus.groovy.control.ClassNodeResolver.resolveName(ClassNodeResolver.java:126)
      	at org.codehaus.groovy.control.ResolveVisitor.resolveToOuter(ResolveVisitor.java:676)
      	at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:308)
      	at org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:1218)
      	at org.codehaus.groovy.control.ResolveVisitor.startResolving(ResolveVisitor.java:176)
      	at org.codehaus.groovy.control.CompilationUnit$11.call(CompilationUnit.java:651)
      	at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:931)
      	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:593)
      	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:542)
      	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
      	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
      	at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
      	at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
      	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:67)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:429)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:392)
      	at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:221)
      	at hudson.model.ResourceController.execute(ResourceController.java:98)
      	at hudson.model.Executor.run(Executor.java:405)
      Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
      /var/jenkins_home/jobs/ff/builds/37/libs/pipelineUtilities/src/jenkins/mkobit/example/FirstClass.groovy: 5: unable to resolve class SiblingClass.SiblingInner
       @ line 5, column 5.
             new SiblingClass.SiblingInner()
             ^
      
      1 error
      
      	at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
      	at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:946)
      	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:593)
      	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:542)
      	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
      	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
      	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:254)
      	at groovy.lang.GroovyClassLoader.recompile(GroovyClassLoader.java:761)
      	at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:718)
      	at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:787)
      	at java.lang.ClassLoader.loadClass(ClassLoader.java:411)
      	at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:677)
      	at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:545)
      	at org.codehaus.groovy.control.ClassNodeResolver.tryAsLoaderClassOrScript(ClassNodeResolver.java:185)
      	... 20 more
      Finished: FAILURE
      

          [JENKINS-41896] Static nested classes in global libraries can not be used from other classes in same package

          Jesse Glick added a comment -

          No idea offhand. Will try to reproduce & investigate some day. No time now.

          Jesse Glick added a comment - No idea offhand. Will try to reproduce & investigate some day. No time now.

          Viktor added a comment - - edited

          I went after this and found a very short reproducible scenario that works/doesn't work jglick, it seems to depend on the identifier of the Class that references the SiblingInner (FirstClass in the code above)

          commenting/swapping out between 2 lines in Jenkinsfile in the code below gives a working and a failing scenario

          //// jenkins-shared/src/sterr/SiblingClass.groovy
          package sterr
          
          class SiblingClass {
                  static class SiblingInner {}
          }
          
          //// jenkins-shared/src/sterr/ZirstClass.groovy
          package sterr
          
          class ZirstClass {
              sterr.SiblingClass.SiblingInner si = new sterr.SiblingClass.SiblingInner()
          }
          
          
          //// jenkins-shared/src/sterr/XirstClass.groovy
          package sterr
          
          class XirstClass {
              sterr.SiblingClass.SiblingInner si = new sterr.SiblingClass.SiblingInner()
          }
          
          
          //// Jenkinsfile
          @Library('jenkins-shared@main') _
          
          /// this is required or else `sterr.SiblingClass.SiblingInner` can never be found
          import sterr.SiblingClass
          
          /// SUCCESS
          import sterr.ZirstClass
          sterr.ZirstClass cles = new sterr.ZirstClass()
          
          /// Uncomment to fail with:
          ///  XirstClass.groovy: unable to resolve class sterr.SiblingClass.SiblingInner
          // import sterr.XirstClass
          // sterr.XirstClass cles = new sterr.XirstClass()
          
          echo cles.getClass().name
          echo cles.dump()
          

          The only difference here is in the name/identifier, XirstClass doesn't seem to work, ZirstClass seems to work.
          I absolutely can't explain it, but it seems to make a difference. Hopefully this helps.

          All the best.

          Viktor added a comment - - edited I went after this and found a very short reproducible scenario that works/doesn't work jglick , it seems to depend on the identifier of the Class that references the SiblingInner ( FirstClass in the code above) commenting/swapping out between 2 lines in Jenkinsfile in the code below gives a working and a failing scenario //// jenkins-shared/src/sterr/SiblingClass.groovy package sterr class SiblingClass { static class SiblingInner {} } //// jenkins-shared/src/sterr/ZirstClass.groovy package sterr class ZirstClass { sterr.SiblingClass.SiblingInner si = new sterr.SiblingClass.SiblingInner() } //// jenkins-shared/src/sterr/XirstClass.groovy package sterr class XirstClass { sterr.SiblingClass.SiblingInner si = new sterr.SiblingClass.SiblingInner() } //// Jenkinsfile @Library( 'jenkins-shared@main' ) _ /// this is required or else `sterr.SiblingClass.SiblingInner` can never be found import sterr.SiblingClass /// SUCCESS import sterr.ZirstClass sterr.ZirstClass cles = new sterr.ZirstClass() /// Uncomment to fail with: /// XirstClass.groovy: unable to resolve class sterr.SiblingClass.SiblingInner // import sterr.XirstClass // sterr.XirstClass cles = new sterr.XirstClass() echo cles.getClass().name echo cles.dump() The only difference here is in the name/identifier, XirstClass doesn't seem to work, ZirstClass seems to work. I absolutely can't explain it, but it seems to make a difference. Hopefully this helps. All the best.

          Rich Schumacher added a comment - - edited

          I'm running into this as well. I found another workaround, though it's not as clean as I'd hope. The idea is to create a method on the parent class that returns an instance of the inner class. So using the above example we'd have:

          class SiblingClass {
              static class SiblingInner {}
          
              def SiblingInner() {
                  return new SiblingInner()
              } 
          }
          

          and then usage is

          def sc = new SiblingClass()
          def si = sc.SiblingInner()
          

          Hope that helps someone else!

          Rich Schumacher added a comment - - edited I'm running into this as well. I found another workaround, though it's not as clean as I'd hope. The idea is to create a method on the parent class that returns an instance of the inner class. So using the above example we'd have: class SiblingClass {     static class SiblingInner {}     def  SiblingInner() {         return new  SiblingInner()     } } and then usage is def sc = new SiblingClass() def si = sc.SiblingInner() Hope that helps someone else!

            Unassigned Unassigned
            mkobit Mike Kobit
            Votes:
            9 Vote for this issue
            Watchers:
            11 Start watching this issue

              Created:
              Updated: