-
Improvement
-
Resolution: Fixed
-
Major
-
5.4.2
-
-
Empty show more show less
-
Basel 28
-
5
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(..))
- is related to
-
MGNLGROOVY-68 Changes to a Groovy class in config aren't picked up
- Closed
- relates to
-
MGNLRES-210 Groovy as resources: Allow groovy in light modules as model classes
- Closed