You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mb...@apache.org on 2011/11/11 00:32:23 UTC
svn commit: r1200623 - in /commons/proper/digester/trunk: ./
src/main/java/org/apache/commons/digester3/
src/main/java/org/apache/commons/digester3/annotations/handlers/
src/main/java/org/apache/commons/digester3/annotations/rules/
src/main/java/org/ap...
Author: mbenson
Date: Thu Nov 10 23:32:22 2011
New Revision: 1200623
URL: http://svn.apache.org/viewvc?rev=1200623&view=rev
Log:
[DIGESTER-153] Add Constructor support to ObjectCreateRule ; cooperative work between Simo Tripodi & Matt Benson
Added:
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRuleLazyLoader.java (with props)
Removed:
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/annotations/rules/Attribute.java
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/ConstructorArgumentTypeBinder.java
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/xmlrules/ConstructorArgumentRule.java
Modified:
commons/proper/digester/trunk/pom.xml
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRule.java
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/annotations/handlers/ObjectCreateHandler.java
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/ObjectCreateBuilder.java
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/xmlrules/XmlRulesModule.java
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/Digester153TestCase.java
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/TestBean.java
Modified: commons/proper/digester/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/digester/trunk/pom.xml?rev=1200623&r1=1200622&r2=1200623&view=diff
==============================================================================
--- commons/proper/digester/trunk/pom.xml (original)
+++ commons/proper/digester/trunk/pom.xml Thu Nov 10 23:32:22 2011
@@ -89,6 +89,11 @@
<id>simonetripodi</id>
<email>simonetripodi AT apache DOT org</email>
</developer>
+ <developer>
+ <name>Matt Benson</name>
+ <id>mbenson</id>
+ <email>mbenson AT apache DOT org</email>
+ </developer>
</developers>
<contributors>
<contributor>
@@ -167,6 +172,11 @@
<dependencies>
<dependency>
+ <groupId>cglib</groupId>
+ <artifactId>cglib</artifactId>
+ <version>2.2.2</version>
+ </dependency>
+ <dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
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=1200623&r1=1200622&r2=1200623&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 Thu Nov 10 23:32:22 2011
@@ -19,19 +19,21 @@ package org.apache.commons.digester3;
* under the License.
*/
-import static java.util.Arrays.asList;
import static java.lang.String.format;
-
-import static org.apache.commons.beanutils.ConvertUtils.convert;
+import static java.util.Arrays.fill;
+import static net.sf.cglib.proxy.Enhancer.isEnhanced;
import static org.apache.commons.beanutils.ConstructorUtils.getAccessibleConstructor;
import java.lang.reflect.Constructor;
-import java.util.Formatter;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
+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 org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
/**
* Rule implementation that creates a new object and pushes it onto the object stack. When the element is complete, the
@@ -111,27 +113,31 @@ public class ObjectCreateRule
*
* @since 3.2
*/
- private final Map<String, Class<?>> constructorArguments = new LinkedHashMap<String, Class<?>>();
+ private Class<?>[] constructorArgumentsTypes;
+
+ /**
+ * cglib Factory for lazily-loaded instances after the first.
+ * Only used in the presence of constructor args.
+ *
+ * @since 3.2
+ */
+ private Factory proxyFactory;
// --------------------------------------------------------- Public Methods
/**
- * Allows users specify constructor arguments <b>from attributes only</b>.
+ * Allows users specify constructor arguments.
*
* @since 3.2
*/
- public void addConstructorArgument( String attibuteName, Class<?> type )
+ public void setConstructorArguments( Class<?>...constructorArgumentsTypes )
{
- if ( attibuteName == null )
+ if ( constructorArgumentsTypes == null )
{
- throw new IllegalArgumentException( "Parameter 'attibuteName' must not be null" );
- }
- if ( type == null )
- {
- throw new IllegalArgumentException( "Parameter 'type' must not be null" );
+ throw new IllegalArgumentException( "Parameter 'constructorArgumentsTypes' must not be null" );
}
- constructorArguments.put( attibuteName, type );
+ this.constructorArgumentsTypes = constructorArgumentsTypes;
}
/**
@@ -166,7 +172,7 @@ public class ObjectCreateRule
clazz = getDigester().getClassLoader().loadClass( realClassName );
}
Object instance;
- if ( constructorArguments.isEmpty() )
+ if ( constructorArgumentsTypes == null || constructorArgumentsTypes.length == 0 )
{
if ( getDigester().getLogger().isDebugEnabled() )
{
@@ -179,50 +185,44 @@ public class ObjectCreateRule
}
else
{
- Class<?>[] parameterTypes = new Class<?>[constructorArguments.size()];
- Object[] initargs = new Object[constructorArguments.size()];
-
- int counter = 0;
-
- // prepare the arguments types with related values
- for ( Entry<String, Class<?>> argEntry : constructorArguments.entrySet() )
- {
- parameterTypes[counter] = argEntry.getValue();
-
- String argumentValueAsString = attributes.getValue( argEntry.getKey() );
- // ConvertUtils manages null values as well
- initargs[counter] = convert( argumentValueAsString, parameterTypes[counter] );
-
- counter++;
- }
-
- Constructor<?> constructor = getAccessibleConstructor( clazz, parameterTypes );
+ Constructor<?> constructor = getAccessibleConstructor( clazz, constructorArgumentsTypes );
if ( constructor == null )
{
- throw new IllegalArgumentException( format( "[ObjectCreateRule]{%s} class '%s' doesn't have a Contructor with params %s",
- getDigester().getMatch(),
- clazz.getName(),
- asList( parameterTypes ) ) );
+ throw new SAXException( format( "[ObjectCreateRule]{%s} Class '%s' does not have a construcor with types",
+ getDigester().getMatch(),
+ clazz.getName(),
+ Arrays.toString( constructorArgumentsTypes ) ) );
}
- // print out constructor debug
- if ( getDigester().getLogger().isDebugEnabled() )
- {
- Formatter formatter = new Formatter().format( "[ObjectCreateRule]{%s} New '%s' using constructor( ",
- getDigester().getMatch(),
- clazz.getName() );
- for ( int i = 0; i < initargs.length; i++ )
- {
- formatter.format( "%s%s/%s", ( i > 0 ? ", " : "" ), initargs[i], parameterTypes[i].getName() );
+ instance = createLazyProxy( constructor );
+ }
+ getDigester().push( instance );
+ }
+
+ private Object createLazyProxy( Constructor<?> constructor ) {
+ Object[] constructorArguments = new Object[constructorArgumentsTypes.length];
+ fill( constructorArguments, null );
+ getDigester().pushParams( constructorArguments );
+
+ ObjectCreateRuleLazyLoader lazyLoader = new ObjectCreateRuleLazyLoader( constructor,
+ constructorArgumentsTypes,
+ 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.setClassLoader( getDigester().getClassLoader() );
+ Object result = enhancer.create();
+ proxyFactory = (Factory) result;
+ return result;
}
- formatter.format( " )" );
- getDigester().getLogger().debug( formatter.toString() );
}
-
- instance = constructor.newInstance( initargs );
}
- getDigester().push( instance );
+ return proxyFactory.newInstance( lazyLoader );
}
/**
@@ -233,6 +233,13 @@ public class ObjectCreateRule
throws Exception
{
Object top = getDigester().pop();
+
+ if ( isEnhanced( top.getClass() ) )
+ {
+ // do lazy load?!?
+ getDigester().popParams();
+ }
+
if ( getDigester().getLogger().isDebugEnabled() )
{
getDigester().getLogger().debug( format( "[ObjectCreateRule]{%s} Pop '%s'",
Added: commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRuleLazyLoader.java
URL: http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRuleLazyLoader.java?rev=1200623&view=auto
==============================================================================
--- commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRuleLazyLoader.java (added)
+++ commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRuleLazyLoader.java Thu Nov 10 23:32:22 2011
@@ -0,0 +1,73 @@
+package org.apache.commons.digester3;
+
+/*
+ * 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.
+ */
+
+import static org.apache.commons.beanutils.ConvertUtils.convert;
+
+import java.lang.reflect.Constructor;
+
+import net.sf.cglib.proxy.LazyLoader;
+
+final class ObjectCreateRuleLazyLoader
+ implements LazyLoader
+{
+
+ private final Constructor<?> constructor;
+
+ private final Class<?>[] paramTypes;
+
+ private final Object[] parameters;
+
+ public ObjectCreateRuleLazyLoader( Constructor<?> constructor,
+ Class<?>[] paramTypes,
+ Object[] parameters )
+ {
+ this.constructor = constructor;
+ this.paramTypes = paramTypes;
+ this.parameters = parameters;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object loadObject()
+ throws Exception
+ {
+ // this piece of code is borrowed from CallMethodRule
+ Object[] paramValues = new Object[paramTypes.length];
+ for ( int i = 0; i < paramTypes.length; i++ )
+ {
+ // convert nulls and convert stringy parameters
+ // for non-stringy param types
+ if ( parameters[i] == null
+ || ( parameters[i] instanceof String && !String.class.isAssignableFrom( paramTypes[i] ) ) )
+ {
+ paramValues[i] = convert( (String) parameters[i], paramTypes[i] );
+ }
+ else
+ {
+ paramValues[i] = parameters[i];
+ }
+ }
+
+ return constructor.newInstance( paramValues );
+ }
+
+}
Propchange: commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/ObjectCreateRuleLazyLoader.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/annotations/handlers/ObjectCreateHandler.java
URL: http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/annotations/handlers/ObjectCreateHandler.java?rev=1200623&r1=1200622&r2=1200623&view=diff
==============================================================================
--- commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/annotations/handlers/ObjectCreateHandler.java (original)
+++ commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/annotations/handlers/ObjectCreateHandler.java Thu Nov 10 23:32:22 2011
@@ -19,13 +19,10 @@ package org.apache.commons.digester3.ann
* under the License.
*/
-import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import org.apache.commons.digester3.annotations.AnnotationHandler;
-import org.apache.commons.digester3.annotations.reflect.MethodArgument;
-import org.apache.commons.digester3.annotations.rules.Attribute;
import org.apache.commons.digester3.annotations.rules.ObjectCreate;
import org.apache.commons.digester3.binder.ObjectCreateBuilder;
import org.apache.commons.digester3.binder.RulesBinder;
@@ -69,17 +66,7 @@ public final class ObjectCreateHandler
if ( element instanceof Constructor<?> )
{
Constructor<?> method = (Constructor<?>) element;
- Annotation[][] parameterAnnotations = method.getParameterAnnotations();
- Class<?>[] parameterTypes = method.getParameterTypes();
- for ( int i = 0; i < parameterTypes.length; i++ )
- {
- MethodArgument methodArgument = new MethodArgument( i, parameterTypes[i], parameterAnnotations[i] );
- if ( methodArgument.isAnnotationPresent( Attribute.class ) )
- {
- Attribute attribute = methodArgument.getAnnotation( Attribute.class );
- builder.addConstructorArgument( attribute.value() ).ofType( methodArgument.getParameterType() );
- }
- }
+ builder.usingConstructor( method.getParameterTypes() );
}
}
Modified: commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/ObjectCreateBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/ObjectCreateBuilder.java?rev=1200623&r1=1200622&r2=1200623&view=diff
==============================================================================
--- commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/ObjectCreateBuilder.java (original)
+++ commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/ObjectCreateBuilder.java Thu Nov 10 23:32:22 2011
@@ -19,10 +19,6 @@ package org.apache.commons.digester3.bin
* under the License.
*/
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
import org.apache.commons.digester3.ObjectCreateRule;
/**
@@ -45,7 +41,7 @@ public final class ObjectCreateBuilder
*
* @since 3.2
*/
- private final Map<String, Class<?>> constructorArguments = new LinkedHashMap<String, Class<?>>();
+ private Class<?>[] constructorArgumentsType;
ObjectCreateBuilder( String keyPattern, String namespaceURI, RulesBinder mainBinder, LinkedRuleBuilder mainBuilder,
ClassLoader classLoader )
@@ -113,18 +109,19 @@ public final class ObjectCreateBuilder
/**
*
- * @param attibuteName
* @return
* @since 3.2
*/
- public ConstructorArgumentTypeBinder addConstructorArgument( String attibuteName )
+ public ObjectCreateBuilder usingConstructor( Class<?>...constructorArgumentsType )
{
- if ( attibuteName == null )
+ if ( constructorArgumentsType == null )
{
- reportError( "createObject().addConstructorArgument( String )", "NULL attibute name not allowed" );
+ reportError( "createObject().usingConstructor( Class<?>[] )", "NULL parametersTypes not allowed" );
}
- return new ConstructorArgumentTypeBinder( this, constructorArguments, attibuteName, classLoader );
+ this.constructorArgumentsType = constructorArgumentsType;
+
+ return this;
}
/**
@@ -135,9 +132,9 @@ public final class ObjectCreateBuilder
{
ObjectCreateRule objectCreateRule = new ObjectCreateRule( attributeName, type );
- for ( Entry<String, Class<?>> argEntry : constructorArguments.entrySet() )
+ if ( constructorArgumentsType != null )
{
- objectCreateRule.addConstructorArgument( argEntry.getKey(), argEntry.getValue() );
+ objectCreateRule.setConstructorArguments( constructorArgumentsType );
}
return objectCreateRule;
Modified: commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/xmlrules/XmlRulesModule.java
URL: http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/xmlrules/XmlRulesModule.java?rev=1200623&r1=1200622&r2=1200623&view=diff
==============================================================================
--- commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/xmlrules/XmlRulesModule.java (original)
+++ commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/xmlrules/XmlRulesModule.java Thu Nov 10 23:32:22 2011
@@ -90,7 +90,6 @@ final class XmlRulesModule
forPattern( "*/factory-create-rule" ).addRule( new FactoryCreateRule( targetRulesBinder, patternStack ) );
forPattern( "*/node-create-rule" ).addRule( new NodeCreateRule( targetRulesBinder, patternStack ) );
forPattern( "*/object-create-rule" ).addRule( new ObjectCreateRule( targetRulesBinder, patternStack ) );
- forPattern( "*/object-create-rule/constructor-argument" ).addRule( new ConstructorArgumentRule() );
forPattern( "*/set-properties-rule" ).addRule( new SetPropertiesRule( targetRulesBinder, patternStack ) );
forPattern( "*/set-properties-rule/alias" )
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=1200623&r1=1200622&r2=1200623&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 Thu Nov 10 23:32:22 2011
@@ -43,18 +43,26 @@ public final class Digester153TestCase
throws Exception
{
ObjectCreateRule createRule = new ObjectCreateRule( TestBean.class );
- createRule.addConstructorArgument( "boolean", boolean.class );
- createRule.addConstructorArgument( "double", double.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", 1, "double" );
TestBean bean = digester.parse( getClass().getResourceAsStream( "BasicConstructor.xml" ) );
assertTrue( bean.getBooleanProperty() );
assertEquals( 9.99D, bean.getDoubleProperty(), 0 );
+
+ // do it again to exercise the cglib Factory:
+ bean = digester.parse( getClass().getResourceAsStream( "BasicConstructor.xml" ) );
+
+ assertTrue( bean.getBooleanProperty() );
+ assertEquals( 9.99D, bean.getDoubleProperty(), 0 );
}
+ /*
@Test
public void basicConstructorViaBinder()
throws Exception
@@ -163,5 +171,6 @@ public final class Digester153TestCase
assertTrue( bean.getBooleanProperty() );
assertEquals( 9.99D, bean.getDoubleProperty(), 0 );
}
+ */
}
Modified: commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/TestBean.java
URL: http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/TestBean.java?rev=1200623&r1=1200622&r2=1200623&view=diff
==============================================================================
--- commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/TestBean.java (original)
+++ commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/TestBean.java Thu Nov 10 23:32:22 2011
@@ -18,7 +18,7 @@
package org.apache.commons.digester3;
-import org.apache.commons.digester3.annotations.rules.Attribute;
+import org.apache.commons.digester3.annotations.rules.CallParam;
import org.apache.commons.digester3.annotations.rules.ObjectCreate;
/**
@@ -37,8 +37,8 @@ public class TestBean
}
@ObjectCreate( pattern = "toplevel/bean" )
- public TestBean( @Attribute( "boolean" ) boolean booleanProperty,
- @Attribute( "double" ) double doubleProperty )
+ public TestBean( @CallParam( pattern = "toplevel/bean", attributeName = "boolean" ) boolean booleanProperty,
+ @CallParam( pattern = "toplevel/bean", attributeName = "double" ) double doubleProperty )
{
setBooleanProperty( booleanProperty );
setDoubleProperty( doubleProperty );