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

Allow yaml based configuration to make use of groovy

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 5.4.2
    • Fix Version/s: 5.4.5
    • Component/s: configuration
    • Labels:

      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(..))

        Attachments

          Issue Links

            Activity

              People

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

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Date of First Response:

                  Time Tracking

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