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