Author: britter Date: Tue Feb 12 20:22:00 2013 New Revision: 1445335 URL: http://svn.apache.org/r1445335 Log: [SANDBOX-441] - Handling of types that can not be instantiated in DefaultClassAccessor should be improved to give users better feedback
Modified: commons/sandbox/beanutils2/trunk/src/changes/changes.xml commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanInstantiationException.java commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultClassAccessor.java commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/ConstructorsTestCase.java Modified: commons/sandbox/beanutils2/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/changes/changes.xml?rev=1445335&r1=1445334&r2=1445335&view=diff ============================================================================== --- commons/sandbox/beanutils2/trunk/src/changes/changes.xml (original) +++ commons/sandbox/beanutils2/trunk/src/changes/changes.xml Tue Feb 12 20:22:00 2013 @@ -23,6 +23,10 @@ </properties> <body> <release version="0.1" date="201?-??-??" description="First release."> + <action dev="britter" type="update" issue="SANDBOX-441"> + Handling of types that can not be instantiated in DefaultClassAccessor should + be improved to give users better feedback + </action> <action dev="britter" type="update" issue="SANDBOX-439"> Rename ClassLoaderBuilder.loadWithClassLoader to loadWith </action> Modified: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanInstantiationException.java URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanInstantiationException.java?rev=1445335&r1=1445334&r2=1445335&view=diff ============================================================================== --- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanInstantiationException.java (original) +++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanInstantiationException.java Tue Feb 12 20:22:00 2013 @@ -27,7 +27,12 @@ public class BeanInstantiationException public BeanInstantiationException( Class<?> beanType, Throwable cause ) { - super( cause, beanType, "Could not create a new instance of type '%s'.", beanType ); + super( cause, beanType, "Cannot not create a new instance of type '%s'.", beanType ); + } + + BeanInstantiationException( Class<?> beanType, String reason ) + { + super( null, beanType, "Cannot not create a new instance of type '%s'. Reason: " + reason, beanType ); } } Modified: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultClassAccessor.java URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultClassAccessor.java?rev=1445335&r1=1445334&r2=1445335&view=diff ============================================================================== --- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultClassAccessor.java (original) +++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultClassAccessor.java Tue Feb 12 20:22:00 2013 @@ -23,6 +23,8 @@ import static org.apache.commons.beanuti import static org.apache.commons.beanutils2.Assertions.checkNoneIsNull; import static org.apache.commons.beanutils2.Assertions.checkNotNull; +import static java.lang.reflect.Modifier.isAbstract; + import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -50,19 +52,7 @@ final class DefaultClassAccessor<B> */ public BeanAccessor<B> newInstance() { - try - { - B bean = beanClass.newInstance(); - return new DefaultBeanAccessor<B>( bean ); - } - catch ( InstantiationException e ) - { - throw new BeanInstantiationException( beanClass, e ); - } - catch ( IllegalAccessException e ) - { - throw new ConstructorNotAccessibleException( beanClass, e ); - } + return invokeConstructor(); } // constructors @@ -104,6 +94,7 @@ final class DefaultClassAccessor<B> */ private BeanAccessor<B> invokeConstructor( boolean exact, Argument<?>... arguments ) { + checkInstantiable(); @SuppressWarnings( "unchecked" ) // type driven by beanClass Constructor<B> constructor = (Constructor<B>) constructorRegistry.get( exact, beanClass, @@ -125,6 +116,35 @@ final class DefaultClassAccessor<B> return new DefaultBeanAccessor<B>( bean ); } + /** + * Checks if {@code beanClass} is instantiable and throws a {@link BeanInstantiationException} with an appropriate + * message otherwise. + */ + private void checkInstantiable() + { + if ( beanClass.isInterface() ) + { + throw new BeanInstantiationException( beanClass, "Type is an interface." ); + } + if ( beanClass.isArray() ) + { + throw new BeanInstantiationException( beanClass, "Type is an array class." ); + } + if ( beanClass.isPrimitive() ) + { + throw new BeanInstantiationException( beanClass, "Type is primitive." ); + } + if ( beanClass.equals( Void.TYPE ) ) + { + throw new BeanInstantiationException( beanClass, "Type represents void." ); + } + // has to be the last check because primitives and array types are also abstract + if ( isAbstract( beanClass.getModifiers() ) ) + { + throw new BeanInstantiationException( beanClass, "Type is abstract." ); + } + } + private B doInvokeConstructor( Constructor<B> constructor, Object[] parameterObjects ) { try Modified: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/ConstructorsTestCase.java URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/ConstructorsTestCase.java?rev=1445335&r1=1445334&r2=1445335&view=diff ============================================================================== --- commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/ConstructorsTestCase.java (original) +++ commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/ConstructorsTestCase.java Tue Feb 12 20:22:00 2013 @@ -27,7 +27,9 @@ import static org.junit.Assert.assertNot import org.apache.commons.beanutils2.testbeans.AbstractTestBean; import org.apache.commons.beanutils2.testbeans.TestBean; import org.apache.commons.beanutils2.testbeans.ThrowingExceptionBean; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; /** * <p> @@ -36,6 +38,10 @@ import org.junit.Test; */ public class ConstructorsTestCase { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + // ------------------------------------------------ Individual Test Methods @Test @@ -250,11 +256,64 @@ public class ConstructorsTestCase on( ThrowingExceptionBean.class ).invokeConstructor( argument( Byte.class, Byte.valueOf( (byte) 4711 ) ) ); } - @Test( expected = BeanInstantiationException.class ) + @Test public void invokeConstructorOnAbstract() throws Exception { + thrown.expect( BeanInstantiationException.class ); + thrown.expectMessage( "abstract" ); on( AbstractTestBean.class ).invokeConstructor(); } + @Test + public void invokeConstructorOnInterface() + throws Exception + { + thrown.expect( BeanInstantiationException.class ); + thrown.expectMessage( "interface" ); + on( ClassAccessor.class ).invokeConstructor(); + } + + @Test + public void invokeConstructorOnArray() + throws Exception + { + thrown.expect( BeanInstantiationException.class ); + thrown.expectMessage( "array" ); + on( String[].class ).invokeConstructor(); + } + + @Test + public void invokeConstructorOnPrimitive() + throws Exception + { + thrown.expect( BeanInstantiationException.class ); + thrown.expectMessage( "primitive" ); + on( int.class ).invokeConstructor(); + } + + @Test + public void invokeConstructorOnVoid() + throws Exception + { + thrown.expect( BeanInstantiationException.class ); + thrown.expectMessage( "void" ); + on( void.class ).invokeConstructor(); + } + + @Test( expected = NoSuchConstructorException.class ) + public void newInstanceWithoutDefaultConstructor() + { + on( NoDefaultConstructor.class ).newInstance(); + } + + public static class NoDefaultConstructor + { + + NoDefaultConstructor( int i ) + { + // do nothing here + } + } + }