Author: mbenson
Date: Sat Dec  3 17:11:44 2011
New Revision: 1209953

URL: http://svn.apache.org/viewvc?rev=1209953&view=rev
Log:
[DIGESTER-153] Add constructor support to ObjectCreateRule - even when the 
constructor args come from nested elements

Added:
    
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/RecordedInvocation.java
      - copied, changed from r1209949, 
commons/proper/proxy/branches/version-2.0-work/core/src/main/java/org/apache/commons/proxy2/invoker/RecordedInvocation.java
    
commons/proper/digester/trunk/src/test/resources/org/apache/commons/digester3/ConstructorWithAttributeAndElement.xml
   (with props)
Modified:
    
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRule.java
    
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/Digester153TestCase.java

Modified: 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRule.java
URL: 
http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRule.java?rev=1209953&r1=1209952&r2=1209953&view=diff
==============================================================================
--- 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRule.java
 (original)
+++ 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRule.java
 Sat Dec  3 17:11:44 2011
@@ -21,16 +21,18 @@ package org.apache.commons.digester3;
 
 import static java.lang.String.format;
 import static java.util.Arrays.fill;
-import static net.sf.cglib.proxy.Enhancer.isEnhanced;
 import static 
org.apache.commons.beanutils.ConstructorUtils.getAccessibleConstructor;
+import static org.apache.commons.beanutils.ConvertUtils.convert;
 
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.Arrays;
 
-import net.sf.cglib.proxy.Callback;
 import net.sf.cglib.proxy.Enhancer;
 import net.sf.cglib.proxy.Factory;
-import net.sf.cglib.proxy.LazyLoader;
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.MethodProxy;
 
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
@@ -42,6 +44,68 @@ import org.xml.sax.SAXException;
 public class ObjectCreateRule
     extends Rule
 {
+    private interface DeferredConstructionProxy
+    {
+        void finish();
+    }
+
+    private static class DeferredConstructionCallback implements 
MethodInterceptor
+    {
+        Constructor<?> constructor;
+        Object[] constructorArgs;
+        ArrayList<RecordedInvocation> invocations = new 
ArrayList<RecordedInvocation>();
+        Object delegate;
+
+        DeferredConstructionCallback(Constructor<?> constructor, Object[] 
constructorArgs)
+        {
+            super();
+            this.constructor = constructor;
+            this.constructorArgs = constructorArgs;
+        }
+
+        public Object intercept(Object obj, Method method, Object[] args, 
MethodProxy proxy) throws Throwable
+        {
+            boolean hasDelegate;
+            synchronized ( this ) {
+                hasDelegate = delegate != null;
+                if ( method.getDeclaringClass().equals( 
DeferredConstructionProxy.class ) )
+                {
+                    if ( !hasDelegate )
+                    {
+                        establishDelegate();
+                        hasDelegate = true;
+                    }
+                    return null;
+                }
+            }
+            if ( hasDelegate ) {
+                return proxy.invoke( delegate, args );
+            }
+            invocations.add( new RecordedInvocation( method, args ) );
+            return proxy.invokeSuper( obj, args );
+        }
+
+        private void establishDelegate() throws Exception {
+            // this piece of code is adapted from CallMethodRule
+            for ( int i = 0; i < constructorArgs.length; i++ )
+            {
+                // convert nulls and convert stringy parameters for 
non-stringy param types
+                if ( constructorArgs[i] == null
+                        || ( constructorArgs[i] instanceof String && 
!String.class.isAssignableFrom( constructor.getParameterTypes()[i] ) ) )
+                {
+                    constructorArgs[i] = convert( (String) constructorArgs[i], 
constructor.getParameterTypes()[i] );
+                }
+            }
+            delegate = constructor.newInstance( constructorArgs );
+            for ( RecordedInvocation invocation : invocations )
+            {
+                invocation.getInvokedMethod().invoke( delegate, 
invocation.getArguments() );
+            }
+            constructor = null;
+            constructorArgs = null;
+            invocations = null;
+        }
+    }
 
     // ----------------------------------------------------------- Constructors
 
@@ -205,16 +269,16 @@ public class ObjectCreateRule
         fill( constructorArguments, null );
         getDigester().pushParams( constructorArguments );
 
-        ObjectCreateRuleLazyLoader lazyLoader = new 
ObjectCreateRuleLazyLoader( constructor,
-                                                                               
 constructorArgumentsTypes,
-                                                                               
 constructorArguments );
+        DeferredConstructionCallback callback = new 
DeferredConstructionCallback(constructor, constructorArguments);
+
         if ( proxyFactory == null ) {
             synchronized ( this ) {
                 // check again for null now that we're in the synchronized 
block:
                 if ( proxyFactory == null ) {
                     Enhancer enhancer = new Enhancer();
                     enhancer.setSuperclass( clazz );
-                    enhancer.setCallback( lazyLoader );
+                    enhancer.setInterfaces(new Class[] { 
DeferredConstructionProxy.class });
+                    enhancer.setCallback( callback );
                     enhancer.setClassLoader( getDigester().getClassLoader() );
                     Object result = enhancer.create();
                     proxyFactory = (Factory) result;
@@ -222,7 +286,7 @@ public class ObjectCreateRule
                 }
             }
         }
-        return proxyFactory.newInstance( lazyLoader );
+        return proxyFactory.newInstance( callback );
     }
 
     /**
@@ -234,10 +298,10 @@ public class ObjectCreateRule
     {
         Object top = getDigester().pop();
 
-        if ( isEnhanced( top.getClass() ) )
+        if (top instanceof DeferredConstructionProxy)
         {
-            // do lazy load?!?
             getDigester().popParams();
+            ((DeferredConstructionProxy) top).finish();
         }
 
         if ( getDigester().getLogger().isDebugEnabled() )

Copied: 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/RecordedInvocation.java
 (from r1209949, 
commons/proper/proxy/branches/version-2.0-work/core/src/main/java/org/apache/commons/proxy2/invoker/RecordedInvocation.java)
URL: 
http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/RecordedInvocation.java?p2=commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/RecordedInvocation.java&p1=commons/proper/proxy/branches/version-2.0-work/core/src/main/java/org/apache/commons/proxy2/invoker/RecordedInvocation.java&r1=1209949&r2=1209953&rev=1209953&view=diff
==============================================================================
--- 
commons/proper/proxy/branches/version-2.0-work/core/src/main/java/org/apache/commons/proxy2/invoker/RecordedInvocation.java
 (original)
+++ 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/RecordedInvocation.java
 Sat Dec  3 17:11:44 2011
@@ -15,14 +15,13 @@
  * limitations under the License.
  */
 
-package org.apache.commons.proxy2.invoker;
-
-import org.apache.commons.proxy2.ProxyUtils;
+package org.apache.commons.digester3;
 
 import java.lang.reflect.Method;
 
 /**
  * Detached representation of a method invocation.
+ * From Commons [proxy] v2 branch.
  * @author James Carman
  */
 public class RecordedInvocation
@@ -116,7 +115,7 @@ public class RecordedInvocation
         else
         {
             buffer.append("(");
-            buffer.append(ProxyUtils.getJavaClassName(input.getClass()));
+            buffer.append(input.getClass().getSimpleName());
             buffer.append("){");
             Object[] array = ( Object[] ) input;
             int count = array.length;

Modified: 
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/Digester153TestCase.java
URL: 
http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/Digester153TestCase.java?rev=1209953&r1=1209952&r2=1209953&view=diff
==============================================================================
--- 
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/Digester153TestCase.java
 (original)
+++ 
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/Digester153TestCase.java
 Sat Dec  3 17:11:44 2011
@@ -62,6 +62,33 @@ public final class Digester153TestCase
         assertEquals( 9.99D, bean.getDoubleProperty(), 0 );
     }
 
+    @Test
+    public void constructorWithAttributeAndElement()
+        throws Exception
+    {
+        ObjectCreateRule createRule = new ObjectCreateRule( TestBean.class );
+        createRule.setConstructorArguments( boolean.class, double.class );
+
+        Digester digester = new Digester();
+        digester.addRule( "toplevel/bean", createRule );
+        digester.addCallParam( "toplevel/bean", 0, "boolean" );
+        digester.addCallParam( "toplevel/bean/double", 1 );
+        digester.addBeanPropertySetter("toplevel/bean/float", "floatProperty");
+
+        TestBean bean = digester.parse( getClass().getResourceAsStream( 
"ConstructorWithAttributeAndElement.xml" ) );
+
+        assertTrue( bean.getBooleanProperty() );
+        assertEquals( 9.99D, bean.getDoubleProperty(), 0 );
+        assertEquals( Float.valueOf( 5.5f ), Float.valueOf( 
bean.getFloatProperty() ) );
+
+        // do it again to exercise the cglib Factory:
+        bean = digester.parse( getClass().getResourceAsStream( 
"ConstructorWithAttributeAndElement.xml" ) );
+
+        assertTrue( bean.getBooleanProperty() );
+        assertEquals( 9.99D, bean.getDoubleProperty(), 0 );
+        assertEquals( Float.valueOf( 5.5f ), Float.valueOf( 
bean.getFloatProperty() ) );
+    }
+
     /*
     @Test
     public void basicConstructorViaBinder()

Added: 
commons/proper/digester/trunk/src/test/resources/org/apache/commons/digester3/ConstructorWithAttributeAndElement.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/test/resources/org/apache/commons/digester3/ConstructorWithAttributeAndElement.xml?rev=1209953&view=auto
==============================================================================
--- 
commons/proper/digester/trunk/src/test/resources/org/apache/commons/digester3/ConstructorWithAttributeAndElement.xml
 (added)
+++ 
commons/proper/digester/trunk/src/test/resources/org/apache/commons/digester3/ConstructorWithAttributeAndElement.xml
 Sat Dec  3 17:11:44 2011
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<toplevel>
+  <bean boolean="true">
+       <double>9.99</double>
+       <float>5.5</float>
+  </bean>
+</toplevel>

Propchange: 
commons/proper/digester/trunk/src/test/resources/org/apache/commons/digester3/ConstructorWithAttributeAndElement.xml
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to