groovy
  1. groovy
  2. GROOVY-3793

unable to resolve class when multiple classes in the same script

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Not A Bug
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None
    • Environment:
      Linux 2.6.9-78.0.0.0.1.ELsmp #1 SMP Fri Jul 25 14:41:56 EDT 2008 i686 i686 i386 GNU/Linux
    • Number of attachments :
      0

      Description

      Sdklib.groovy :

      package odilib
      public class Sdklib extends Framework {
      def test() {
      throw new ObjectAlreadyExists ('some text')
      }
      }
      public class ObjectAlreadyExists extends Exception {}
      =========================================

      my_script.groovy :

      import odilib.*
      def x = new Sdklib ()
      try

      { x.test() }

      catch (ObjectAlreadyExists e) {}

      Run as :

      groovy my_script.groovy

      Error :

      org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, my_script.groovy: xx: unable to resolve class ObjectAlreadyExists
      @ line xx, column 5.
      } catch (ObjectAlreadyExists e) {
      ^

      1 error

      As you could see, Sdklib.groovy has 2 classes that belong to package odilib, the second one defines exception.
      From the outside script the first class named after the script Sdklib is visible, but not the second one corresponding to the exception.

        Issue Links

          Activity

          Hide
          blackdrag blackdrag added a comment -

          You cannot expect Groovy to have the second sight. when you refer to a class ObjectAlreadyExists, then Groovy expects this either as ready class known by the loader (in your case as .class file) or as .groovy somewhere in the classpath. But Groovy would look for a ObjectAlreadyExists.groovy, it cannot know that Sdklib.groovy actually contains the class. You have a slight achnce by referencing Sdklib, but the compiler will first go through with your file and then see what is actually in Sdklib.groovy.

          Show
          blackdrag blackdrag added a comment - You cannot expect Groovy to have the second sight. when you refer to a class ObjectAlreadyExists, then Groovy expects this either as ready class known by the loader (in your case as .class file) or as .groovy somewhere in the classpath. But Groovy would look for a ObjectAlreadyExists.groovy, it cannot know that Sdklib.groovy actually contains the class. You have a slight achnce by referencing Sdklib, but the compiler will first go through with your file and then see what is actually in Sdklib.groovy.
          Hide
          Bobo added a comment -

          The book "Groovy in Action" by Dierk König , page 189 says :

          When not compiling explicitly, Groovy finds a class by matching its name to a corresponding *.groovy source file.
          At this point, naming becomes important. Groovy only finds classes where the class name matches the source filename.
          When such a file is found, all declared classes in that file are parsed and become known to Groovy.

          In my case new Sdklib() works, meaning the class is found, but the other classes are not being parsed and are not becoming known,
          as the description suggests.
          So either the statement in the book is wrong or there is a bug.

          Show
          Bobo added a comment - The book "Groovy in Action" by Dierk König , page 189 says : When not compiling explicitly, Groovy finds a class by matching its name to a corresponding *.groovy source file. At this point, naming becomes important. Groovy only finds classes where the class name matches the source filename. When such a file is found, all declared classes in that file are parsed and become known to Groovy. In my case new Sdklib() works, meaning the class is found, but the other classes are not being parsed and are not becoming known, as the description suggests. So either the statement in the book is wrong or there is a bug.
          Hide
          blackdrag blackdrag added a comment -

          I would say neither nor. Known to Groovy or not is not the important part, the important part is being known by the compiler. The compiler is devided into several phases. Now, when during compilation the compiler collects a file, then all the classes inside are known only at a later phase for sure. The class corresponding to the file name works only, because the check if that class really exists is delayed to a later step. Since you reference a class, that is not corresponding to the file name the compiler cannot assume something. Also the compiler does not yet know the class exists. The compiler knows later, but too late.

          So the reason why the class is not seen is because of how the compiler is designed.

          Show
          blackdrag blackdrag added a comment - I would say neither nor. Known to Groovy or not is not the important part, the important part is being known by the compiler. The compiler is devided into several phases. Now, when during compilation the compiler collects a file, then all the classes inside are known only at a later phase for sure. The class corresponding to the file name works only, because the check if that class really exists is delayed to a later step. Since you reference a class, that is not corresponding to the file name the compiler cannot assume something. Also the compiler does not yet know the class exists. The compiler knows later, but too late. So the reason why the class is not seen is because of how the compiler is designed.
          Hide
          Bobo added a comment -

          I'm not using compiled groovy scripts, but I believe you are talking about the undercover compilation that occurs when groovy script is run.
          So basically you are saying that on the first pass the compiler will go through all the types referenced in the script and see
          if there is a file .class or .groovy with the same name on the classpath. If no such file is found then "unable to resolve class" exception is thrown.
          Then later on, if first compilation pass is successful, it will go further in look into the contents of referenced groovy files.
          This is too bad, because, additional classes will never be referable from an outside script, and hence the multi-class file feature
          becomes truly limited.

          My use case is very simple. I have a library with common methods and would like declare some specific exceptions inside the same file.
          Don't really like the idea of having a separate file for each exception. Then all the user scripts that use the library could catch the these specific
          exception when needed.
          Is there any way to make this work?
          The book really makes you believe that this is possible.

          Show
          Bobo added a comment - I'm not using compiled groovy scripts, but I believe you are talking about the undercover compilation that occurs when groovy script is run. So basically you are saying that on the first pass the compiler will go through all the types referenced in the script and see if there is a file .class or .groovy with the same name on the classpath. If no such file is found then "unable to resolve class" exception is thrown. Then later on, if first compilation pass is successful, it will go further in look into the contents of referenced groovy files. This is too bad, because, additional classes will never be referable from an outside script, and hence the multi-class file feature becomes truly limited. My use case is very simple. I have a library with common methods and would like declare some specific exceptions inside the same file. Don't really like the idea of having a separate file for each exception. Then all the user scripts that use the library could catch the these specific exception when needed. Is there any way to make this work? The book really makes you believe that this is possible.
          Hide
          blackdrag blackdrag added a comment -

          If you compile all files using groovyc then it is possible, but well, that is another thing. Imagine you reference ObjectAlreadyExists before you reference Sdklib, then it would fail even if it would work the other way around. Would that be ok with you? And it is worse, because sometimes we don't know if it is a PropertyExpression or a ClassExpression (like when you use new) and if such an expression is for example ObjectAlreadyExists and Sdklib had not been referenced before, then Groovy will think it is a PropertyExpression and not even throw an error at compile time. At runtime you will then get a strange PropertyMissingException

          Also if people handle for example only the exception and don't do anything with SdkLib, they would not get the file resolved. The usage of multiple classes in the script file is more or less intended for usage through that script, or the main class of that script. The intention was not to provide something for external use.

          Show
          blackdrag blackdrag added a comment - If you compile all files using groovyc then it is possible, but well, that is another thing. Imagine you reference ObjectAlreadyExists before you reference Sdklib, then it would fail even if it would work the other way around. Would that be ok with you? And it is worse, because sometimes we don't know if it is a PropertyExpression or a ClassExpression (like when you use new) and if such an expression is for example ObjectAlreadyExists and Sdklib had not been referenced before, then Groovy will think it is a PropertyExpression and not even throw an error at compile time. At runtime you will then get a strange PropertyMissingException Also if people handle for example only the exception and don't do anything with SdkLib, they would not get the file resolved. The usage of multiple classes in the script file is more or less intended for usage through that script, or the main class of that script. The intention was not to provide something for external use.
          Hide
          Pascal Schumacher added a comment -

          Considering blackdrag blackdrag last comment I'm closing this.

          Show
          Pascal Schumacher added a comment - Considering blackdrag blackdrag last comment I'm closing this.

            People

            • Assignee:
              blackdrag blackdrag
              Reporter:
              Bobo
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: