Index: src/test/java/info/magnolia/content2bean/SimpleBeanThrowingExceptionOnInstantiation.java =================================================================== --- src/test/java/info/magnolia/content2bean/SimpleBeanThrowingExceptionOnInstantiation.java (revision 0) +++ src/test/java/info/magnolia/content2bean/SimpleBeanThrowingExceptionOnInstantiation.java (revision 0) @@ -0,0 +1,45 @@ +/** + * This file Copyright (c) 2009 Magnolia International + * Ltd. (http://www.magnolia.info). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia.info/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.content2bean; + +/** + * @author pbaerfuss + * @version $Id$ + */ +public class SimpleBeanThrowingExceptionOnInstantiation extends SimpleBean { + + public SimpleBeanThrowingExceptionOnInstantiation() { + throw new RuntimeException("This bean throws an exception when instantiated"); + } +} Index: src/test/java/info/magnolia/content2bean/BeanWithSubBean.java =================================================================== --- src/test/java/info/magnolia/content2bean/BeanWithSubBean.java (revision 30170) +++ src/test/java/info/magnolia/content2bean/BeanWithSubBean.java (working copy) @@ -33,10 +33,6 @@ */ package info.magnolia.content2bean; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - /** * @author philipp * @version $Id$ @@ -47,12 +43,6 @@ private SimpleBean sub; /** - * Logger. - */ - private static Logger log = LoggerFactory.getLogger(BeanWithSubBean.class); - - - /** * @return the sub */ public SimpleBean getSub() { Index: src/test/java/info/magnolia/content2bean/SimpleBeanThrowingExceptionOnSettingProperties.java =================================================================== --- src/test/java/info/magnolia/content2bean/SimpleBeanThrowingExceptionOnSettingProperties.java (revision 0) +++ src/test/java/info/magnolia/content2bean/SimpleBeanThrowingExceptionOnSettingProperties.java (revision 0) @@ -0,0 +1,54 @@ +/** + * This file Copyright (c) 2009 Magnolia International + * Ltd. (http://www.magnolia.info). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia.info/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.content2bean; + + +/** + * @author pbaerfuss + * @version $Id$ + * + */ +public class SimpleBeanThrowingExceptionOnSettingProperties extends SimpleBean { + + @Override + public void setProp1(String prop1) { + throw new RuntimeException("Setting a property throws an exception"); + } + + @Override + public void setProp2(String prop2) { + throw new RuntimeException("Setting a property throws an exception"); + } + +} Index: src/test/java/info/magnolia/content2bean/Content2BeanTest.java =================================================================== --- src/test/java/info/magnolia/content2bean/Content2BeanTest.java (revision 30170) +++ src/test/java/info/magnolia/content2bean/Content2BeanTest.java (working copy) @@ -34,6 +34,8 @@ package info.magnolia.content2bean; import info.magnolia.cms.core.Content; +import info.magnolia.content2bean.impl.Content2BeanProcessorImpl; +import info.magnolia.content2bean.impl.Content2BeanTransformerImpl; import info.magnolia.test.MgnlTestCase; import info.magnolia.test.mock.MockUtil; @@ -47,6 +49,7 @@ * @version $Id$ */ public class Content2BeanTest extends MgnlTestCase { + public void testContentToBeanWithClassDefined() throws RepositoryException, Content2BeanException{ Content node = MockUtil.createNode("node", new Object[][]{ {"class", "info.magnolia.content2bean.SimpleBean"}, @@ -89,15 +92,7 @@ } public void testContentToBeanWithSubBeanAndAutoTypeResolving() throws RepositoryException, Content2BeanException { - Content node = MockUtil.createContent("parent", new String[][]{ - {"class", "info.magnolia.content2bean.BeanWithSubBean"}, - {"prop1", "propParent1Value"}, - {"prop2", "propParent2Value"}}, - new Content[]{MockUtil.createNode("sub", new String[][]{ - {"prop1", "propSub1Value"}, - {"prop2", "propSub2Value"}})}); - - BeanWithSubBean bean = (BeanWithSubBean) Content2BeanUtil.toBean(node, true); + BeanWithSubBean bean = (BeanWithSubBean) Content2BeanUtil.toBean(createConficForBeanWithSubBean(null), true); SimpleBean sub = bean.getSub(); assertNotNull(sub); @@ -310,4 +305,94 @@ assertEquals(SampleEnum.two, result.getSample()); } + + public void testExceptionIsNotThrownIfForceFlagIsSetToTrueAndWrongClassNameIsUsed() throws RepositoryException, Content2BeanException { + BeanWithSubBean bean = (BeanWithSubBean) Content2BeanUtil.toBean(createConficForBeanWithSubBean("test.WrongClass"), true); + + assertNull(bean.getSub()); + assertEquals("propParent1Value", bean.getProp1()); + assertEquals("propParent2Value", bean.getProp2()); + } + + public void testExceptionIsThrownIfForceFlagIsSetToFalseAndWrongClassNameIsUsed() throws RepositoryException { + Content2BeanProcessorImpl processor = new Content2BeanProcessorImpl(); + processor.setForceCreation(false); + Content2BeanTransformerImpl transformer = new Content2BeanTransformerImpl(); + + try{ + processor.toBean(createConficForBeanWithSubBean("test.WrongClass"), true, transformer); + } + catch(Content2BeanException e){ + return; + } + fail("Exception should be thrown if force flag is false"); + } + + public void testExceptionIsNotThrownIfForceFlagIsSetToTrueAndInstantiationFails() throws RepositoryException, Content2BeanException { + Content beanConfig = createConficForBeanWithSubBean(SimpleBeanThrowingExceptionOnInstantiation.class.getName()); + BeanWithSubBean bean = (BeanWithSubBean) Content2BeanUtil.toBean(beanConfig, true); + + assertNull(bean.getSub()); + assertEquals("propParent1Value", bean.getProp1()); + assertEquals("propParent2Value", bean.getProp2()); + } + + public void testExceptionIsThrownIfForceFlagIsSetToFalseAndInstantiationFails() throws RepositoryException { + Content2BeanProcessorImpl processor = new Content2BeanProcessorImpl(); + processor.setForceCreation(false); + Content2BeanTransformerImpl transformer = new Content2BeanTransformerImpl(); + + Content beanConfig = createConficForBeanWithSubBean(SimpleBeanThrowingExceptionOnInstantiation.class.getName()); + + try{ + processor.toBean(beanConfig, true, transformer); + } + catch(Content2BeanException e){ + return; + } + fail("Exception should be thrown if force flag is false"); + } + + public void testExceptionIsNotThrownIfForceFlagIsSetToTrueAndSettingPropertiesFails() throws RepositoryException, Content2BeanException { + Content beanConfig = createConficForBeanWithSubBean(SimpleBeanThrowingExceptionOnSettingProperties.class.getName()); + BeanWithSubBean bean = (BeanWithSubBean) Content2BeanUtil.toBean(beanConfig, true); + + assertNotNull(bean.getSub()); + assertEquals("propParent1Value", bean.getProp1()); + assertEquals("propParent2Value", bean.getProp2()); + } + + public void testExceptionIsThrownIfForceFlagIsSetToFalseAndSettingPropertiesFails() throws RepositoryException { + Content2BeanProcessorImpl processor = new Content2BeanProcessorImpl(); + processor.setForceCreation(false); + Content2BeanTransformerImpl transformer = new Content2BeanTransformerImpl(); + + Content beanConfig = createConficForBeanWithSubBean(SimpleBeanThrowingExceptionOnSettingProperties.class.getName()); + + try{ + processor.toBean(beanConfig, true, transformer); + } + catch(Content2BeanException e){ + return; + } + fail("Exception should be thrown if force flag is false"); + } + private Content createConficForBeanWithSubBean(String subBeanClass) throws RepositoryException { + Content subBean = MockUtil.createNode("sub", new String[][]{ + {"prop1", "propSub1Value"}, + {"prop2", "propSub2Value"}}); + + if(subBeanClass != null){ + subBean.createNodeData("class", subBeanClass); + } + + Content parentBean = MockUtil.createContent("parent", new String[][]{ + {"class", "info.magnolia.content2bean.BeanWithSubBean"}, + {"prop1", "propParent1Value"}, + {"prop2", "propParent2Value"}}, + new Content[]{subBean}); + return parentBean; + } + + //Add test with a subbean class trhowing an exception in the constructor } Index: src/main/java/info/magnolia/content2bean/Content2BeanTransformer.java =================================================================== --- src/main/java/info/magnolia/content2bean/Content2BeanTransformer.java (revision 30170) +++ src/main/java/info/magnolia/content2bean/Content2BeanTransformer.java (working copy) @@ -74,7 +74,7 @@ /** * Set this property on that bean. Allows excluding of properties */ - public void setProperty(TransformationState state, PropertyTypeDescriptor descriptor, Map values); + public void setProperty(TransformationState state, PropertyTypeDescriptor descriptor, Map values) throws Content2BeanException; /** * Transforms the simple basic jcr property value objects to complexer properties Index: src/main/java/info/magnolia/content2bean/impl/CollectionPropertyHidingTransformer.java =================================================================== --- src/main/java/info/magnolia/content2bean/impl/CollectionPropertyHidingTransformer.java (revision 30170) +++ src/main/java/info/magnolia/content2bean/impl/CollectionPropertyHidingTransformer.java (working copy) @@ -33,6 +33,7 @@ */ package info.magnolia.content2bean.impl; +import info.magnolia.content2bean.Content2BeanException; import info.magnolia.content2bean.PropertyTypeDescriptor; import info.magnolia.content2bean.TransformationState; import info.magnolia.content2bean.TypeDescriptor; @@ -88,7 +89,7 @@ return resolvedType; } - public void setProperty(TransformationState state, PropertyTypeDescriptor descriptor, Map values) { + public void setProperty(TransformationState state, PropertyTypeDescriptor descriptor, Map values) throws Content2BeanException { if(descriptor.getName().equals(collectionName)){ Object bean = state.getCurrentBean(); Index: src/main/java/info/magnolia/content2bean/impl/Content2BeanProcessorImpl.java =================================================================== --- src/main/java/info/magnolia/content2bean/impl/Content2BeanProcessorImpl.java (revision 30170) +++ src/main/java/info/magnolia/content2bean/impl/Content2BeanProcessorImpl.java (working copy) @@ -35,6 +35,7 @@ import info.magnolia.cms.core.Content; import info.magnolia.cms.core.NodeData; +import info.magnolia.cms.util.ExceptionUtil; import info.magnolia.cms.util.NodeDataUtil; import info.magnolia.content2bean.Content2BeanException; import info.magnolia.content2bean.Content2BeanProcessor; @@ -78,11 +79,12 @@ type = transformer.resolveType(state); } catch (Throwable e) { + String msg = "can't resolve class for node " + node.getHandle(); if(isForceCreation()){ - log.warn("can't resolve class for node " + node.getHandle(), e); + log.warn(msg + ": " + ExceptionUtil.getFullMessage(e)); } else{ - throw new Content2BeanException("can't resolve class for node " + node.getHandle(), e); + throw new Content2BeanException(msg, e); } } @@ -98,11 +100,12 @@ bean = transformer.newBeanInstance(state, values); } catch (Throwable e) { + String msg = "can't instantiate bean of type " + type.getType().getName() + " for node " + node.getHandle(); if(isForceCreation()){ - log.warn("Can't instantiate bean for " + node.getHandle(), e); + log.warn(msg + ": " + ExceptionUtil.getFullMessage(e)); } else{ - throw new Content2BeanException("Can't instantiate bean for " + node.getHandle(), e); + throw new Content2BeanException(msg, e); } } @@ -115,14 +118,6 @@ state.popBean(); } - else{ - if(forceCreation){ - log.warn("can't instantiate bean of type " + type.getType().getName() + " for node " + node.getHandle()); - } - else{ - throw new Content2BeanException("can't instantiate bean of type " + type.getType().getName()); - } - } state.popType(); } @@ -200,7 +195,7 @@ * @todo in case the bean is a map / collection the transfomer.setProperty() method should be called too * @todo if the bean has not a certain property but a value is present, transformer.setProperty() should be called with a fake property descriptor */ - protected void setProperties(Map values, final Content2BeanTransformer transformer, TransformationState state) throws Content2BeanException { + protected void setProperties(Map values, final Content2BeanTransformer transformer, TransformationState state) throws Content2BeanException{ Object bean = state.getCurrentBean(); log.debug("will populate bean {} with the values {}", bean.getClass().getName(), values); @@ -218,7 +213,18 @@ for (Iterator iter = dscrs.iterator(); iter.hasNext();) { PropertyTypeDescriptor descriptor = (PropertyTypeDescriptor) iter.next(); - transformer.setProperty(state, descriptor, values); + try { + transformer.setProperty(state, descriptor, values); + } + catch (Throwable e) { + String msg = "can't set property [" + descriptor.getName() + "] on the bean build for " + state.getCurrentContent().getHandle(); + if(isForceCreation()){ + log.warn(msg + ": " + ExceptionUtil.getFullMessage(e)); + } + else{ + throw new Content2BeanException(msg, e); + } + } } } } Index: src/main/java/info/magnolia/content2bean/impl/Content2BeanTransformerImpl.java =================================================================== --- src/main/java/info/magnolia/content2bean/impl/Content2BeanTransformerImpl.java (revision 30170) +++ src/main/java/info/magnolia/content2bean/impl/Content2BeanTransformerImpl.java (working copy) @@ -189,7 +189,7 @@ /** * Do not set class property. In case of a map/collection try to use adder method. */ - public void setProperty(TransformationState state, PropertyTypeDescriptor descriptor, Map values) { + public void setProperty(TransformationState state, PropertyTypeDescriptor descriptor, Map values) throws Content2BeanException { TypeMapping mapping = getTypeMapping(); String propertyName = descriptor.getName(); @@ -219,9 +219,9 @@ log.debug("try to set {}.{} with value {}", new Object[]{bean, propertyName, value}); - // if the parent bean is a map, we can't guess the types. - if (!(bean instanceof Map)) { - try { + try { + // if the parent bean is a map, we can't guess the types. + if (!(bean instanceof Map)) { PropertyTypeDescriptor dscr = mapping.getPropertyTypeDescriptor(bean.getClass(), propertyName); if (dscr.getType() != null) { @@ -275,21 +275,12 @@ } } } - catch (Exception e) { - // do it better - log.error("can't set property [" + propertyName + "] to value [" + value + "] in bean [" + bean.getClass().getName() + "]"); - } - } - - try{ // this does some conversions like string to class. Performance of PropertyUtils.setProperty() would be better beanUtilsBean.setProperty(bean, propertyName, value); //PropertyUtils.setProperty(bean, propertyName, value); } catch (Exception e) { - // do it better - log.error("can't set property [" + propertyName + "] to value [" + value + "] in bean [" + bean.getClass().getName() + "]"); - log.debug("stacktrace", e); + throw new Content2BeanException("can't set property [" + propertyName + "] to value [" + value + "] in bean [" + bean.getClass().getName() + "]", e); } } Index: src/main/java/info/magnolia/commands/CommandsManager.java =================================================================== --- src/main/java/info/magnolia/commands/CommandsManager.java (revision 30170) +++ src/main/java/info/magnolia/commands/CommandsManager.java (working copy) @@ -241,7 +241,7 @@ super.initBean(state, values); } - public void setProperty(TransformationState state, PropertyTypeDescriptor descriptor, Map values) { + public void setProperty(TransformationState state, PropertyTypeDescriptor descriptor, Map values) throws Content2BeanException { Object bean = state.getCurrentBean(); if(bean instanceof MgnlCatalog){ MgnlCatalog catalog = (MgnlCatalog) bean; Index: src/main/java/info/magnolia/cms/util/ExceptionUtil.java =================================================================== --- src/main/java/info/magnolia/cms/util/ExceptionUtil.java (revision 30170) +++ src/main/java/info/magnolia/cms/util/ExceptionUtil.java (working copy) @@ -33,6 +33,10 @@ */ package info.magnolia.cms.util; +import java.util.List; + +import org.apache.commons.lang.exception.ExceptionUtils; + /** * * @author gjoseph @@ -56,5 +60,17 @@ throw e; } } + + public static String getFullMessage(Throwable th){ + String msg = ""; + List throwableList = ExceptionUtils.getThrowableList(th); + for(Throwable nested : throwableList){ + if(msg.length()>0){ + msg += " -> "; + } + msg += ExceptionUtils.getMessage(nested); + } + return msg; + } } Index: src/main/java/info/magnolia/cms/util/FactoryUtil.java =================================================================== --- src/main/java/info/magnolia/cms/util/FactoryUtil.java (revision 30170) +++ src/main/java/info/magnolia/cms/util/FactoryUtil.java (working copy) @@ -53,7 +53,6 @@ import org.apache.commons.beanutils.ConstructorUtils; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -121,7 +120,7 @@ } } catch (Exception e) { - throw new IllegalStateException("Can't instantiate an implementation of this class [" + interf.getName() + "]: " + ExceptionUtils.getMessage(e), e); + throw new IllegalStateException("Can't instantiate an implementation of this class [" + interf.getName() + "]", e); } } Index: src/main/java/info/magnolia/cms/security/IPSecurityManagerImpl.java =================================================================== --- src/main/java/info/magnolia/cms/security/IPSecurityManagerImpl.java (revision 30170) +++ src/main/java/info/magnolia/cms/security/IPSecurityManagerImpl.java (working copy) @@ -35,6 +35,7 @@ import info.magnolia.cms.beans.config.ContentRepository; import info.magnolia.cms.util.FactoryUtil; +import info.magnolia.content2bean.Content2BeanException; import info.magnolia.content2bean.PropertyTypeDescriptor; import info.magnolia.content2bean.TransformationState; import info.magnolia.content2bean.TypeDescriptor; @@ -103,7 +104,7 @@ public static final class Content2BeanTransformer extends Content2BeanTransformerImpl { - public void setProperty(TransformationState state, PropertyTypeDescriptor descriptor, Map values) { + public void setProperty(TransformationState state, PropertyTypeDescriptor descriptor, Map values) throws Content2BeanException { final Object currentBean = state.getCurrentBean(); if (currentBean instanceof IPSecurityManagerImpl) { final IPSecurityManagerImpl ipSecMan = (IPSecurityManagerImpl) currentBean;