Uploaded image for project: 'Magnolia'
  1. Magnolia
  2. MAGNOLIA-6378

Allow yaml based configuration to make use of groovy

    XMLWordPrintable

Details

    • Improvement
    • Resolution: Fixed
    • Major
    • 5.4.5
    • 5.4.2
    • configuration
    • Basel 28
    • 5

    Description

      I am not able to use groovy model classes in yaml based templates definitions.

      2015-09-15 12:31:42,701 WARN  agnolia.config.source.yaml.YamlConfigurationSource: Problem while registering TEMPLATE from LayeredResource{path='/workshop-module/templates/pages/hello.yaml', layeredResources=[FileSystemResource{origin=filesystem,path=/workshop-module/templates/pages/hello.yaml,file}]}: Conversion: Error converting from 'String' to 'Class' info.magnolia.groovy.models.HelloModel
      org.apache.commons.beanutils.ConversionException: Error converting from 'String' to 'Class' info.magnolia.groovy.models.HelloModel
      	at org.apache.commons.beanutils.converters.AbstractConverter.handleError(AbstractConverter.java:282)
      	at org.apache.commons.beanutils.converters.AbstractConverter.convert(AbstractConverter.java:177)
      	at org.apache.commons.beanutils.converters.ConverterFacade.convert(ConverterFacade.java:61)
      	at org.apache.commons.beanutils.ConvertUtilsBean.convert(ConvertUtilsBean.java:491)
      	at org.apache.commons.beanutils.BeanUtilsBean.setProperty(BeanUtilsBean.java:1000)
      	at info.magnolia.config.map2bean.Map2BeanTransformer.readOutObject(Map2BeanTransformer.java:184)
      	at info.magnolia.config.map2bean.Map2BeanTransformer.readComplexValue(Map2BeanTransformer.java:151)
      	at info.magnolia.config.map2bean.Map2BeanTransformer.readValue(Map2BeanTransformer.java:114)
      	at info.magnolia.config.map2bean.Map2BeanTransformer.toBean(Map2BeanTransformer.java:101)
      	at info.magnolia.config.source.yaml.YamlConfigurationSource.loadAndRegister(YamlConfigurationSource.java:94)
      	at info.magnolia.config.source.yaml.AbstractFileResourceConfigurationSource$LoadAndRegisterFunction.doWith(AbstractFileResourceConfigurationSource.java:132)
      	at info.magnolia.config.source.yaml.AbstractFileResourceConfigurationSource$LoadAndRegisterFunction.doWith(AbstractFileResourceConfigurationSource.java:113)
      	at info.magnolia.resourceloader.util.VoidFunction.apply(VoidFunction.java:49)
      	at info.magnolia.resourceloader.util.VoidFunction.apply(VoidFunction.java:46)
      	at info.magnolia.resourceloader.util.PredicatedResourceVisitor.visitFile(PredicatedResourceVisitor.java:117)
      	at info.magnolia.resourceloader.layered.RelayerResourceVisitor.visitFile(RelayerResourceVisitor.java:61)
      	at info.magnolia.resourceloader.file.VisitorFunction.apply(VisitorFunction.java:58)
      	at info.magnolia.resourceloader.file.VisitorFunction.apply(VisitorFunction.java:46)
      	at info.magnolia.resourceloader.file.FileWatcherCallback.doIt(FileWatcherCallback.java:78)
      	at info.magnolia.resourceloader.file.FileWatcherCallback.modified(FileWatcherCallback.java:66)
      	at info.magnolia.dirwatch.DirectoryWatcher.processEvent(DirectoryWatcher.java:247)
      	at info.magnolia.dirwatch.DirectoryWatcher.run(DirectoryWatcher.java:199)
      	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
      	at java.lang.Thread.run(Thread.java:745)
      Caused by: java.lang.ClassNotFoundException: info.magnolia.groovy.models.HelloModel
      	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1858)
      	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1709)
      	at org.apache.commons.beanutils.converters.ClassConverter.convertToType(ClassConverter.java:104)
      	at org.apache.commons.beanutils.converters.AbstractConverter.convert(AbstractConverter.java:169)
      	... 25 more
      

      CAUSE AND PROPOSED SOLUTION

      Basically in Map2Bean resolving model classes is delegated to BeanUtils which uses its default class converter org.apache.commons.beanutils.converters.ClassConverter. Code eventually ends up at ClassConverter.convertToType(..) where the context class loader for the current thread is not aware of Groovy classes and thus fails. One way to fix this could be adding a check at Map2BeanTransformer.readSimpleValue(Object, TypeDescriptor)

       private <T> T readSimpleValue(Object source, TypeDescriptor defaultTargetTypeDescriptor) throws ClassNotFoundException {
              // we need to convert classes here else org.apache.commons.beanutils.converters.ClassConverter (which isn't aware of Groovy classes) would be used and an exception thrown, e.g. in case of a Groovy class model. Basically we need to do here something similar to what is done at Node2BeanTransformerImpl.convertPropertyValue(..)  
              if (defaultTargetTypeDescriptor.getType().isAssignableFrom(Class.class)) {
                  return (T) Classes.getClassFactory().forName((String) source);
              }
              return (T) source;
          }
      

      One problem I see with this approach is that we throw CNFE which eventually must be thrown by the public API method Map2BeanTransformer.toBean(..) meaning not being binary compatible (unless we catch the exception and just log it or rethrow it wrapped in some exception already thrown by toBean(..))

      Checklists

        Acceptance criteria

        Attachments

          Issue Links

            Activity

              People

                fgrilli Federico Grilli
                rgange Richard Gange
                Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved:

                  Checklists

                    Task DoD

                    Time Tracking

                      Estimated:
                      Original Estimate - Not Specified
                      Not Specified
                      Remaining:
                      Remaining Estimate - 0d
                      0d
                      Logged:
                      Time Spent - 0.5d
                      0.5d