Author: hlship
Date: Wed Oct 13 19:28:53 2010
New Revision: 1022252
URL: http://svn.apache.org/viewvc?rev=1022252&view=rev
Log:
TAP5-1304: When using PropertyShadowBuilder to build a service, if the property
is null, an immediate exception is needed (rather than a NullPointerException)
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/PropertyShadowBuilderImplTest.java
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java?rev=1022252&r1=1022251&r2=1022252&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
Wed Oct 13 19:28:53 2010
@@ -1,10 +1,10 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2010 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,6 +15,7 @@
package org.apache.tapestry5.ioc.internal.services;
import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.ioc.util.BodyBuilder;
import static java.lang.String.format;
import java.lang.reflect.Constructor;
@@ -29,7 +30,7 @@ public class PropertyShadowBuilderImpl i
public PropertyShadowBuilderImpl(@Builtin
ClassFactory classFactory,
- PropertyAccess propertyAccess)
+ PropertyAccess propertyAccess)
{
this.classFactory = classFactory;
this.propertyAccess = propertyAccess;
@@ -38,8 +39,7 @@ public class PropertyShadowBuilderImpl i
public <T> T build(Object source, String propertyName, Class<T>
propertyType)
{
Class sourceClass = source.getClass();
- PropertyAdapter adapter =
propertyAccess.getAdapter(sourceClass).getPropertyAdapter(
- propertyName);
+ PropertyAdapter adapter =
propertyAccess.getAdapter(sourceClass).getPropertyAdapter(propertyName);
// TODO: Perhaps extend ClassPropertyAdapter to do these checks?
@@ -50,23 +50,33 @@ public class PropertyShadowBuilderImpl i
throw new
RuntimeException(ServiceMessages.readNotSupported(source, propertyName));
if (!propertyType.isAssignableFrom(adapter.getType()))
- throw new RuntimeException(ServiceMessages.propertyTypeMismatch(
- propertyName,
- sourceClass,
- adapter.getType(),
- propertyType));
+ throw new
RuntimeException(ServiceMessages.propertyTypeMismatch(propertyName, sourceClass,
+ adapter.getType(), propertyType));
ClassFab cf = classFactory.newClass(propertyType);
cf.addField("_source", Modifier.PRIVATE | Modifier.FINAL, sourceClass);
cf.addConstructor(new Class[]
- { sourceClass }, null, "_source = $1;");
+ { sourceClass }, null, "_source = $1;");
+
+ BodyBuilder body = new BodyBuilder();
+ body.begin();
+
+ body.addln("%s result = _source.%s();", sourceClass.getName(),
adapter.getReadMethod().getName());
+
+ body.addln("if (result == null)");
+ body.begin();
+ body.addln("throw new NullPointerException(%s.buildMessage(_source,
\"%s\"));", getClass().getName(),
+ propertyName);
+ body.end();
+
+ body.addln("return result;");
- String body = format("return _source.%s();",
adapter.getReadMethod().getName());
+ body.end();
MethodSignature sig = new MethodSignature(propertyType, "_delegate",
null, null);
- cf.addMethod(Modifier.PRIVATE, sig, body);
+ cf.addMethod(Modifier.PRIVATE, sig, body.toString());
String toString = format("<Shadow: property %s of %s>", propertyName,
source);
@@ -90,4 +100,8 @@ public class PropertyShadowBuilderImpl i
}
+ public static final String buildMessage(Object source, String propertyName)
+ {
+ return String.format("Unable to delegate method invocation to property
'%s' of %s, because the property is null.", propertyName, source);
+ }
}
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/PropertyShadowBuilderImplTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/PropertyShadowBuilderImplTest.java?rev=1022252&r1=1022251&r2=1022252&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/PropertyShadowBuilderImplTest.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/PropertyShadowBuilderImplTest.java
Wed Oct 13 19:28:53 2010
@@ -1,10 +1,10 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2010 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -113,6 +113,25 @@ public class PropertyShadowBuilderImplTe
}
@Test
+ public void property_is_null()
+ {
+ FooHolder holder = new FooHolder();
+
+ Foo shadow = builder.build(holder, "foo", Foo.class);
+
+ try
+ {
+ shadow.foo();
+ unreachable();
+ }
+ catch (NullPointerException ex)
+ {
+ assertEquals(ex.getMessage(),
+ "Unable to delegate method invocation to property 'foo' of
[FooHolder], because the property is null.");
+ }
+ }
+
+ @Test
public void property_does_not_exist()
{
FooHolder holder = new FooHolder();
@@ -124,8 +143,7 @@ public class PropertyShadowBuilderImplTe
}
catch (RuntimeException ex)
{
- assertEquals(ex.getMessage(),
- "Class " + CLASS_NAME + "$FooHolder does not contain
a property named 'bar'.");
+ assertEquals(ex.getMessage(), "Class " + CLASS_NAME + "$FooHolder
does not contain a property named 'bar'.");
}
}
@@ -141,8 +159,8 @@ public class PropertyShadowBuilderImplTe
}
catch (RuntimeException ex)
{
- assertEquals(ex.getMessage(),
- "Property 'count' of class " + CLASS_NAME +
"$FooHolder is of type int, which is not assignable to type java.util.Map.");
+ assertEquals(ex.getMessage(), "Property 'count' of class " +
CLASS_NAME
+ + "$FooHolder is of type int, which is not assignable to
type java.util.Map.");
}
}
@@ -158,8 +176,8 @@ public class PropertyShadowBuilderImplTe
}
catch (RuntimeException ex)
{
- assertEquals(ex.getMessage(),
- "Class " + CLASS_NAME + "$FooHolder does not provide
an accessor ('getter') method for property 'writeOnly'.");
+ assertEquals(ex.getMessage(), "Class " + CLASS_NAME
+ + "$FooHolder does not provide an accessor ('getter')
method for property 'writeOnly'.");
}
}
}