NanoContainer
  1. NanoContainer
  2. NANO-160

GroovyCompilationException can hide the real groovy errors.

    Details

    • Type: Bug Bug
    • Status: Resolved Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.0-RC2
    • Fix Version/s: 1.0
    • Component/s: groovy
    • Labels:
      None
    • Number of attachments :
      0

      Description

      Lets say we modify the testValidationTurnedOnThrowsExceptionForUnknownAttributes() test case to have an error in it like so. (Missing Import for NullNodeBuilderDecorationDelegate())

      public void testValidationTurnedOnThrowsExceptionForUnknownAttributes() {
      DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer();
      Reader script = new StringReader(
      "import org.nanocontainer.script.groovy.*\n" +
      "builder = new CustomGroovyNodeBuilder(new NullNodeBuilderDecorationDelegate(), CustomGroovyNodeBuilder.PERFORM_ATTRIBUTE_VALIDATION)\n" +
      "nano = builder.container

      {\n" + " component(key:'a', instance:'apple', badAttribute:'foo')\n" + "}

      ");

      try

      { buildContainer(script, parent, ASSEMBLY_SCOPE); fail("CustomGroovyNodeBuilder with validation should have thrown NanoContainerMarkupException"); } catch(GroovyCompilationException ex) { //Weed out the groovy compilation exceptions throw ex; } catch (NanoContainerMarkupException ex) { //a-ok }
      }

      Then we get a rather unhelpful error message from the GroovyCompilationException:

      public void testValidationTurnedOnThrowsExceptionForUnknownAttributes() {
      DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer();
      Reader script = new StringReader(
      "import org.nanocontainer.script.groovy.*\n" +
      "builder = new CustomGroovyNodeBuilder(new NullNodeBuilderDecorationDelegate(), CustomGroovyNodeBuilder.PERFORM_ATTRIBUTE_VALIDATION)\n" +
      "nano = builder.container {\n" + " component(key:'a', instance:'apple', badAttribute:'foo')\n" + "}");

      try { buildContainer(script, parent, ASSEMBLY_SCOPE); fail("CustomGroovyNodeBuilder with validation should have thrown NanoContainerMarkupException"); }

      catch(GroovyCompilationException ex)

      { //Weed out the groovy compilation exceptions throw ex; }

      catch (NanoContainerMarkupException ex)

      { //a-ok }

      }

      However, if I go into GroovyContainerBuilder.createGroovyScript() and modify it so I printStackTrace() on the compilation exception like so:

      private void createGroovyScript() {
      try

      { GroovyClassLoader loader = new GroovyClassLoader(getClassLoader()); InputStream scriptIs = getScriptInputStream(); GroovyCodeSource groovyCodeSource = new GroovyCodeSource(scriptIs,"nanocontainer.groovy","groovyGeneratedForNanoContainer"); Class scriptClass = loader.parseClass(groovyCodeSource); groovyScript = InvokerHelper.createScript(scriptClass, null); }

      catch (CompilationFailedException e)

      { e.printStackTrace(); throw new GroovyCompilationException("Compilation Failed '" + e.getMessage() + "'", e); }

      catch (IOException e)

      { throw new NanoContainerMarkupException(e); }

      }

      Then we get the nice error:

      General error during class generation: No such class: NullNodeBuilderDecorationDelegate in constructor call for class: nanocontainer. At [2:39] nanocontainer.groovy

      1 Error

      at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:325)

      at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:879)

      at org.codehaus.groovy.control.CompilationUnit.classgen(CompilationUnit.java:564)

      at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:469)

      at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:246)

      at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:209)

      at org.nanocontainer.script.groovy.GroovyContainerBuilder.createGroovyScript(GroovyContainerBuilder.java:92)

      at org.nanocontainer.script.groovy.GroovyContainerBuilder.createContainerFromScript(GroovyContainerBuilder.java:52)

      at org.nanocontainer.script.ScriptedContainerBuilder.createContainer(ScriptedContainerBuilder.java:60)

      at org.nanocontainer.integrationkit.LifecycleContainerBuilder.buildContainer(LifecycleContainerBuilder.java:26)

      at org.nanocontainer.script.AbstractScriptedContainerBuilderTestCase.buildContainer(AbstractScriptedContainerBuilderTestCase.java:27)

      at org.nanocontainer.script.groovy.CustomGroovyNodeBuilderTestCase.buildContainer(CustomGroovyNodeBuilderTestCase.java:604)

      at org.nanocontainer.script.groovy.CustomGroovyNodeBuilderTestCase.testValidationTurnedOnThrowsExceptionForUnknownAttributes(CustomGroovyNodeBuilderTestCase.java:575)

      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

      at java.lang.reflect.Method.invoke(Method.java:324)

      at junit.framework.TestCase.runTest(TestCase.java:154)

      at org.jmock.core.VerifyingTestCase.runBare(Unknown Source)

      at junit.framework.TestResult$1.protect(TestResult.java:106)

      at junit.framework.TestResult.runProtected(TestResult.java:124)

      at junit.framework.TestResult.run(TestResult.java:109)

      at junit.framework.TestCase.run(TestCase.java:118)

      at junit.framework.TestSuite.runTest(TestSuite.java:208)

      at junit.framework.TestSuite.run(TestSuite.java:203)

      at com.borland.jbuilder.unittest.JBTestRunner.a(Unknown Source)

      at com.borland.jbuilder.unittest.JBTestRunner.initiateTest(Unknown Source)

      at com.borland.jbuilder.unittest.JBTestRunner.main(Unknown Source)

      I've looked into it a bit and it appears there's no way for the Standard printStackTrace() to get at the cause because GroovyCompilationException's constructor is:

      public GroovyCompilationException(String message, CompilationFailedException e)

      { super(message); this.compilationFailedException = e; }

      So the compilation exception never gets passed up to the PicoException as a cause. I see special code for extracting the errors in GroovyCompilationException so I'm not sure what's expected here. For the record, if I modify the constructor to:

      public GroovyCompilationException(String message, CompilationFailedException e)

      { super(message,e); this.compilationFailedException = e; }

      Then GroovyCompilationException.printStackTrace() gives me what I would expect:

      org.nanocontainer.script.groovy.GroovyCompilationException: Compilation Failed 'startup failed'

      at org.nanocontainer.script.groovy.GroovyContainerBuilder.createGroovyScript(GroovyContainerBuilder.java:95)
      at org.nanocontainer.script.groovy.GroovyContainerBuilder.createContainerFromScript(GroovyContainerBuilder.java:52)
      at org.nanocontainer.script.ScriptedContainerBuilder.createContainer(ScriptedContainerBuilder.java:60)
      at org.nanocontainer.integrationkit.LifecycleContainerBuilder.buildContainer(LifecycleContainerBuilder.java:26)
      at org.nanocontainer.script.AbstractScriptedContainerBuilderTestCase.buildContainer(AbstractScriptedContainerBuilderTestCase.java:27)
      at org.nanocontainer.script.groovy.CustomGroovyNodeBuilderTestCase.buildContainer(CustomGroovyNodeBuilderTestCase.java:610)
      at org.nanocontainer.script.groovy.CustomGroovyNodeBuilderTestCase.testValidationTurnedOnThrowsExceptionForUnknownAttributes(CustomGroovyNodeBuilderTestCase.java:575)
      ...(Click for full stack trace)...
      at org.jmock.core.VerifyingTestCase.runBare(Unknown Source)
      ...
      Caused by: General error during class generation: No such class: NullNodeBuilderDecorationDelegate in constructor call for class: nanocontainer. At [2:39] nanocontainer.groovy

      1 Error

      at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:325)
      at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:879)
      at org.codehaus.groovy.control.CompilationUnit.classgen(CompilationUnit.java:564)
      at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:469)
      at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:246)
      at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:209)
      at org.nanocontainer.script.groovy.GroovyContainerBuilder.createGroovyScript(GroovyContainerBuilder.java:92)
      ... 21 more
      Caused by:

      General error during class generation: No such class: NullNodeBuilderDecorationDelegate in constructor call for class: nanocontainer. At [2:39] nanocontainer.groovy

      1 Error

      at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:325)
      at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:879)
      at org.codehaus.groovy.control.CompilationUnit.classgen(CompilationUnit.java:564)
      at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:469)
      at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:246)
      at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:209)
      at org.nanocontainer.script.groovy.GroovyContainerBuilder.createGroovyScript(GroovyContainerBuilder.java:92)
      at org.nanocontainer.script.groovy.GroovyContainerBuilder.createContainerFromScript(GroovyContainerBuilder.java:52)
      at org.nanocontainer.script.ScriptedContainerBuilder.createContainer(ScriptedContainerBuilder.java:60)
      at org.nanocontainer.integrationkit.LifecycleContainerBuilder.buildContainer(LifecycleContainerBuilder.java:26)
      at org.nanocontainer.script.AbstractScriptedContainerBuilderTestCase.buildContainer(AbstractScriptedContainerBuilderTestCase.java:27)
      at org.nanocontainer.script.groovy.CustomGroovyNodeBuilderTestCase.buildContainer(CustomGroovyNodeBuilderTestCase.java:610)
      at org.nanocontainer.script.groovy.CustomGroovyNodeBuilderTestCase.testValidationTurnedOnThrowsExceptionForUnknownAttributes(CustomGroovyNodeBuilderTestCase.java:575)
      ...
      at org.jmock.core.VerifyingTestCase.runBare(Unknown Source)
      ...

      But that appears to go against something already set there in the code.

      Any thoughts guys?

        Activity

        Hide
        Mauro Talevi added a comment -

        The CompilationFailedException used to originally encode the error information
        in a different way - it changed somewhere between jsr-01 and jsr-03.

        But yes - I think adding the exception to the super constructor is the right thing to do,
        and certainly does no harm!

        Why do you say it goes against something in the code?
        The idea of the getMessage() is to put into a human-readable form the
        errors contained in the exception without having to do a printStackTrace().

        Show
        Mauro Talevi added a comment - The CompilationFailedException used to originally encode the error information in a different way - it changed somewhere between jsr-01 and jsr-03. But yes - I think adding the exception to the super constructor is the right thing to do, and certainly does no harm! Why do you say it goes against something in the code? The idea of the getMessage() is to put into a human-readable form the errors contained in the exception without having to do a printStackTrace().
        Hide
        Michael Rimov added a comment -

        Ok. Checked in fix to call superclass(String,Throwable).

        Originally by "going against," I meant that what I was suggesting seemed to be contrary to what a lot of code in GroovyCompilationException already did – it explicitly DIDN'T call super(String,Throwable), and there was a whole lot of error extraction code there instead.

        But your history lesson I think explains to me why it was done that way. So I'm happy with the new results.

        -Mike

        Show
        Michael Rimov added a comment - Ok. Checked in fix to call superclass(String,Throwable). Originally by "going against," I meant that what I was suggesting seemed to be contrary to what a lot of code in GroovyCompilationException already did – it explicitly DIDN'T call super(String,Throwable), and there was a whole lot of error extraction code there instead. But your history lesson I think explains to me why it was done that way. So I'm happy with the new results. -Mike
        Michael Rimov made changes -
        Field Original Value New Value
        Fix Version/s 1.0 [ 10148 ]
        Resolution Fixed [ 1 ]
        Assignee Michael Rimov [ rimovm ]
        Status Open [ 1 ] Resolved [ 5 ]

          People

          • Assignee:
            Michael Rimov
            Reporter:
            Michael Rimov
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: