You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/02/13 18:48:14 UTC
svn commit: r507118 - in /tapestry/tapestry5/tapestry-core/trunk/src:
main/java/org/apache/tapestry/corelib/components/
main/java/org/apache/tapestry/internal/services/ site/apt/guide/
test/java/org/apache/tapestry/internal/services/
Author: hlship
Date: Tue Feb 13 09:48:13 2007
New Revision: 507118
URL: http://svn.apache.org/viewvc?view=rev&rev=507118
Log:
Add support for "?." separator inside property expressions, which will abort the read or write if the indicated term is null.
Remove logging decorators from built-in services.
Switch the Grid component back to using an inner class for its computed model binding.
Added:
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PropertyConduitSourceImplTest.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Grid.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PropertyConduitSourceImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Grid.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Grid.java?view=diff&rev=507118&r1=507117&r2=507118
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Grid.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Grid.java Tue Feb 13 09:48:13 2007
@@ -82,60 +82,39 @@
{ "source=dataSource", "rowsPerPage=rowsPerPage", "currentPage=currentPage" })
private GridPager _pager;
- /**
- * Dynamically computes the model based on the row type (determined from the
- * {@link GridDataSource#getRowType() data model).
- */
- static class ModelBinding extends AbstractBinding
+ Binding defaultModel()
{
- private final Grid _grid;
-
- private final BeanModelSource _modelSource;
-
- private final ComponentResources _containerResources;
-
- public ModelBinding(final Grid grid, final BeanModelSource modelSource,
- final ComponentResources containerResources)
- {
- _grid = grid;
- _modelSource = modelSource;
- _containerResources = containerResources;
- }
-
- public Object get()
- {
- // Get the default row type from the data source
+ final ComponentResources containerResources = _resources.getContainerResources();
- Class rowType = _grid.getDataSource().getRowType();
-
- if (rowType == null)
- throw new RuntimeException("xxx -- no source to determine list type from");
-
- // Properties do not have to be read/write
-
- return _modelSource.create(rowType, false, _containerResources);
- }
-
- /**
- * Returns false. This may be overkill, but it basically exists because the model is
- * inherently mutable and therefore may contain client-specific state and needs to be
- * discard at the end of the request. If the model were immutable, then we could leave
- * invariant as true.
- */
- @Override
- public boolean isInvariant()
+ return new AbstractBinding()
{
- return false;
- }
-
- }
-
- Binding defaultModel()
- {
- // This should be done as an inner class, but Javassist has been barfing on that
- // for some reason. This could be a problem!
- return new ModelBinding(this, _modelSource, _resources.getContainerResources());
+ public Object get()
+ {
+ // Get the default row type from the data source
+
+ Class rowType = _dataSource.getRowType();
+
+ if (rowType == null)
+ throw new RuntimeException("xxx -- no source to determine list type from");
+
+ // Properties do not have to be read/write
+
+ return _modelSource.create(rowType, false, containerResources);
+ }
+
+ /**
+ * Returns false. This may be overkill, but it basically exists because the model is
+ * inherently mutable and therefore may contain client-specific state and needs to be
+ * discarded at the end of the request. If the model were immutable, then we could leave
+ * invariant as true.
+ */
+ @Override
+ public boolean isInvariant()
+ {
+ return false;
+ }
+ };
}
Object setupRender()
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=507118&r1=507117&r2=507118
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java Tue Feb 13 09:48:13 2007
@@ -40,11 +40,8 @@
import org.apache.tapestry.ioc.annotations.Inject;
import org.apache.tapestry.ioc.annotations.InjectService;
import org.apache.tapestry.ioc.annotations.Lifecycle;
-import org.apache.tapestry.ioc.annotations.Match;
-import org.apache.tapestry.ioc.annotations.Order;
import org.apache.tapestry.ioc.services.ChainBuilder;
import org.apache.tapestry.ioc.services.ClassFactory;
-import org.apache.tapestry.ioc.services.LoggingDecorator;
import org.apache.tapestry.ioc.services.PropertyAccess;
import org.apache.tapestry.ioc.services.ThreadCleanupHub;
import org.apache.tapestry.ioc.services.ThreadLocale;
@@ -224,21 +221,6 @@
public static UpdateListenerHub buildUpdateListenerHub()
{
return new UpdateListenerHubImpl();
- }
-
- /**
- * All public services in the tapestry module, and in any sub-module of tapestry will get
- * logging. This doesn't include the tapesry.ioc module since services of that module can not be
- * decorated.
- */
- @Match(
- { "tapestry.*", "tapestry.*.*" })
- @Order("before:*.*")
- public static <T> T decorateWithLogging(Class<T> serviceInterface, T delegate,
- String serviceId, Log log, @InjectService("tapestry.ioc.LoggingDecorator")
- LoggingDecorator loggingDecorator)
- {
- return loggingDecorator.build(serviceInterface, delegate, serviceId, log);
}
@Lifecycle("perthread")
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PropertyConduitSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PropertyConduitSourceImpl.java?view=diff&rev=507118&r1=507117&r2=507118
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PropertyConduitSourceImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PropertyConduitSourceImpl.java Tue Feb 13 09:48:13 2007
@@ -173,6 +173,10 @@
String thisStep = "step" + (i + 1);
String term = terms[i];
+ boolean nullable = term.endsWith("?");
+ if (nullable)
+ term = term.substring(0, term.length() - 1);
+
Method readMethod = readMethodForTerm(
activeType,
expression,
@@ -198,6 +202,9 @@
previousStep,
readMethod.getName());
+ if (nullable)
+ builder.addln("if (%s == null) return null;", thisStep);
+
activeType = termType;
result = readMethod;
previousStep = thisStep;
@@ -237,6 +244,10 @@
String thisStep = "step" + (i + 1);
String term = terms[i];
+ boolean nullable = term.endsWith("?");
+ if (nullable)
+ term = term.substring(0, term.length() - 1);
+
Method readMethod = readMethodForTerm(activeType, expression, term, true);
// If a primitive type, convert to wrapper type
@@ -251,6 +262,9 @@
thisStep,
previousStep,
readMethod.getName());
+
+ if (nullable)
+ builder.addln("if (%s == null) return;", thisStep);
activeType = termType;
previousStep = thisStep;
Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt?view=diff&rev=507118&r1=507117&r2=507118
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt Tue Feb 13 09:48:13 2007
@@ -151,6 +151,11 @@
This feature is most useful for accessing a couple of propertys of standard collection classes
that aren't named as proper properties, such as Collection.size(), or Map.keySet().
+ Ever get frustrated, tripping over null pointers inside such an expression? You may use
+ "?." instead of "." as the separator. This adds a null check and aborts the expression
+ if the term is null. Thus "foo?.bar?.baz" will return null if either foo or bar are null.
+ Likewise, updating "foo?.bar?.baz" will turn into a no-op if foo or bar is null.
+
In addition, a few special cases are also supported.
In most cases, these special values save you the trouble of adding a "literal:" prefix to
the value. These special cases are <alternatives> to property expressions.
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PropertyConduitSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PropertyConduitSourceImplTest.java?view=auto&rev=507118
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PropertyConduitSourceImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PropertyConduitSourceImplTest.java Tue Feb 13 09:48:13 2007
@@ -0,0 +1,79 @@
+// Copyright 2007 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.services;
+
+import org.apache.tapestry.PropertyConduit;
+import org.apache.tapestry.internal.bindings.PropBindingFactoryTest;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.services.PropertyConduitSource;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Most of the testing occurs inside {@link PropBindingFactoryTest} (due to historical reasons).
+ */
+public class PropertyConduitSourceImplTest extends InternalBaseTestCase
+{
+ private PropertyConduitSource _source;
+
+ @BeforeClass
+ public void setup()
+ {
+ _source = getObject("infrastructure:PropertyConduitSource", PropertyConduitSource.class);
+ }
+
+ @AfterClass
+ public void cleanup()
+ {
+ _source = null;
+ }
+
+ @Test
+ public void question_dot_operator_for_object_type()
+ {
+ PropertyConduit normal = _source.create(CompositeBean.class, "simple.firstName");
+ PropertyConduit smart = _source.create(CompositeBean.class, "simple?.firstName");
+
+ CompositeBean bean = new CompositeBean();
+ bean.setSimple(null);
+
+ try
+ {
+ normal.get(bean);
+ unreachable();
+ }
+ catch (NullPointerException ex)
+ {
+ // Expected.
+ }
+
+ assertNull(smart.get(bean));
+
+ try
+ {
+ normal.set(bean, "Howard");
+ unreachable();
+ }
+ catch (NullPointerException ex)
+ {
+ // Expected.
+ }
+
+ // This will be a no-op due to the null property in the expression
+
+ smart.set(bean, "Howard");
+ }
+}