jstrachan 2002/10/17 00:51:31 Modified: jelly/src/java/org/apache/commons/jelly/tags/bean BeanTagLibrary.java BeanPropertyTag.java jelly/src/java/org/apache/commons/jelly/tags/core UseListTag.java jelly/src/test/org/apache/commons/jelly/bean suite.jelly Added: jelly/src/java/org/apache/commons/jelly/tags/bean BeanTag.java jelly/src/java/org/apache/commons/jelly/impl CollectionTag.java Log: Added support for CollectionTag so that the bean tag library can be used to make collections of beans easily. Also refactored the bean tag library implementation a little so that both bean and property based tags work share the processing code (adding themselves to their parent via a setter, adder or a parent CollectionTag) Revision Changes Path 1.2 +1 -2 jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/bean/BeanTagLibrary.java Index: BeanTagLibrary.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/bean/BeanTagLibrary.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- BeanTagLibrary.java 16 Oct 2002 18:17:57 -0000 1.1 +++ BeanTagLibrary.java 17 Oct 2002 07:51:31 -0000 1.2 @@ -68,7 +68,6 @@ import org.apache.commons.jelly.TagLibrary; import org.apache.commons.jelly.impl.TagFactory; import org.apache.commons.jelly.impl.TagScript; -import org.apache.commons.jelly.tags.core.UseBeanTag; import org.xml.sax.Attributes; @@ -135,7 +134,7 @@ // is the name bound to a specific class Class beanType = getBeanType(name, attributes); if (beanType != null) { - return new UseBeanTag(beanType); + return new BeanTag(beanType, name); } // its a property tag 1.2 +9 -79 jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/bean/BeanPropertyTag.java Index: BeanPropertyTag.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/bean/BeanPropertyTag.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- BeanPropertyTag.java 16 Oct 2002 18:17:57 -0000 1.1 +++ BeanPropertyTag.java 17 Oct 2002 07:51:31 -0000 1.2 @@ -73,8 +73,6 @@ import org.apache.commons.jelly.MissingAttributeException; import org.apache.commons.jelly.TagSupport; import org.apache.commons.jelly.XMLOutput; -import org.apache.commons.jelly.impl.BeanSource; -import org.apache.commons.jelly.tags.core.UseBeanTag; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -88,7 +86,7 @@ * @author <a href="mailto:[EMAIL PROTECTED]">James Strachan</a> * @version $Revision$ */ -public class BeanPropertyTag extends UseBeanTag { +public class BeanPropertyTag extends BeanTag { /** empty arguments constant */ private static final Object[] EMPTY_ARGS = {}; @@ -100,34 +98,22 @@ private static final Log log = LogFactory.getLog(BeanPropertyTag.class); - /** the name of the property to create */ - private String propertyName; - /** the name of the create method */ private String createMethodName; - /** the name of the adder method */ - private String addMethodName; - - public BeanPropertyTag(String propertyName) { - super(Object.class); - - this.propertyName = propertyName; - - int length = propertyName.length(); - if (length > 0) { + public BeanPropertyTag(String tagName) { + super(Object.class, tagName); + + if (tagName.length() > 0) { createMethodName = "create" - + propertyName.substring(0,1).toUpperCase() - + propertyName.substring(1); - addMethodName = "add" - + propertyName.substring(0,1).toUpperCase() - + propertyName.substring(1); + + tagName.substring(0,1).toUpperCase() + + tagName.substring(1); } } /** - * Creates a new instance, try finding a parent property. + * Creates a new instance by calling a create method on the parent bean */ protected Object newInstance(Class theClass, Map attributes, XMLOutput output) throws Exception { Object parentObject = getParentObject(); @@ -145,43 +131,12 @@ } } else { - throw new JellyException( "The " + propertyName + " tag must be nested within a tag which maps to a bean property" ); + throw new JellyException( "The " + getTagName() + " tag must be nested within a tag which maps to a bean property" ); } return null; } /** - * By default this will export the bean using the given variable if it is defined. - * This Strategy method allows derived tags to process the beans in different ways - * such as to register this bean with its parent tag etc. - */ - protected void processBean(String var, Object bean) throws Exception { - if (var != null) { - context.setVariable(var, bean); - } - - // now lets try set the parent property via calling the adder or the setter method - Object parentObject = getParentObject(); - if (parentObject != null && bean != null) { - // lets see if there's a setter method... - Method method = findAddMethod(parentObject.getClass(), bean.getClass()); - if (method != null) { - Object[] args = { bean }; - try { - method.invoke(parentObject, args); - } - catch (Exception e) { - throw new JellyException( "failed to invoke method: " + method + " on bean: " + parentObject + " reason: " + e, e ); - } - } - else { - BeanUtils.setProperty(parentObject, propertyName, bean); - } - - } - } - - /** * Finds the Method to create a new property object */ protected Method findCreateMethod(Class theClass) { @@ -192,29 +147,4 @@ theClass, createMethodName, EMPTY_ARG_TYPES ); } - - /** - * Finds the Method to add the new bean - */ - protected Method findAddMethod(Class beanClass, Class valueClass) { - if (addMethodName == null) { - return null; - } - Class[] argTypes = { valueClass }; - return MethodUtils.getAccessibleMethod( - beanClass, addMethodName, argTypes - ); - } - - - /** - * @return the parent bean object - */ - protected Object getParentObject() throws Exception { - BeanSource tag = (BeanSource) findAncestorWithClass(BeanSource.class); - if (tag != null) { - return tag.getBean(); - } - return null; - } } 1.1 jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/bean/BeanTag.java Index: BeanTag.java =================================================================== /* * $Header: /home/cvs/jakarta-commons-sandbox/jelly/src/taglibs/beanshell/src/java/org/apache/commons/jelly/tags/beanshell/BeanShellExpressionFactory.java,v 1.1 2002/05/21 07:58:55 jstrachan Exp $ * $Revision: 1.1 $ * $Date: 2002/05/21 07:58:55 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * $Id: BeanShellExpressionFactory.java,v 1.1 2002/05/21 07:58:55 jstrachan Exp $ */ package org.apache.commons.jelly.tags.bean; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.MethodUtils; import org.apache.commons.jelly.JellyException; import org.apache.commons.jelly.MissingAttributeException; import org.apache.commons.jelly.TagSupport; import org.apache.commons.jelly.XMLOutput; import org.apache.commons.jelly.impl.BeanSource; import org.apache.commons.jelly.impl.CollectionTag; import org.apache.commons.jelly.tags.core.UseBeanTag; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Creates a bean for the given tag which is then either output as a variable * or can be added to a parent tag. * * @author <a href="mailto:[EMAIL PROTECTED]">James Strachan</a> * @version $Revision: 1.1 $ */ public class BeanTag extends UseBeanTag { /** empty arguments constant */ private static final Object[] EMPTY_ARGS = {}; /** empty argument types constant */ private static final Class[] EMPTY_ARG_TYPES = {}; /** The Log to which logging calls will be made. */ private static final Log log = LogFactory.getLog(BeanTag.class); /** the name of the property to create */ private String tagName; /** the name of the adder method */ private String addMethodName; public BeanTag(Class defaultClass, String tagName) { super(defaultClass); this.tagName = tagName; if (tagName.length() > 0) { addMethodName = "add" + tagName.substring(0,1).toUpperCase() + tagName.substring(1); } } /** * @return the local name of the XML tag to which this tag is bound */ public String getTagName() { return tagName; } /** * Output the tag as a named variable. If the parent bean has an adder or setter * method then invoke that to register this bean with its parent. */ protected void processBean(String var, Object bean) throws Exception { if (var != null) { context.setVariable(var, bean); } // now lets try set the parent property via calling the adder or the setter method if (bean != null) { Object parentObject = getParentObject(); if (parentObject != null) { if (parentObject instanceof Collection) { Collection collection = (Collection) parentObject; collection.add(bean); } else { // lets see if there's a setter method... Method method = findAddMethod(parentObject.getClass(), bean.getClass()); if (method != null) { Object[] args = { bean }; try { method.invoke(parentObject, args); } catch (Exception e) { throw new JellyException( "failed to invoke method: " + method + " on bean: " + parentObject + " reason: " + e, e ); } } else { BeanUtils.setProperty(parentObject, tagName, bean); } } } else { // lets try find a parent List to add this bean to CollectionTag tag = (CollectionTag) findAncestorWithClass(CollectionTag.class); if (tag != null) { tag.addItem(bean); } else { log.warn( "Could not add bean to parent for bean: " + bean ); } } } } /** * Finds the Method to add the new bean */ protected Method findAddMethod(Class beanClass, Class valueClass) { if (addMethodName == null) { return null; } Class[] argTypes = { valueClass }; return MethodUtils.getAccessibleMethod( beanClass, addMethodName, argTypes ); } /** * @return the parent bean object */ protected Object getParentObject() throws Exception { BeanSource tag = (BeanSource) findAncestorWithClass(BeanSource.class); if (tag != null) { return tag.getBean(); } return null; } } 1.1 jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/impl/CollectionTag.java Index: CollectionTag.java =================================================================== /* * $Header: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/core/IfTag.java,v 1.6 2002/05/17 15:18:08 jstrachan Exp $ * $Revision: 1.6 $ * $Date: 2002/05/17 15:18:08 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * $Id: IfTag.java,v 1.6 2002/05/17 15:18:08 jstrachan Exp $ */ package org.apache.commons.jelly.impl; /** * A tag which is capable of consuming objects, such as a <useList> tag * such that nested objects will be added to the parent tag. * * @author <a href="mailto:[EMAIL PROTECTED]">James Strachan</a> * @version $Revision: 1.6 $ */ public interface CollectionTag { /** * @return adds an item to the tags collection */ public void addItem(Object value); } 1.3 +8 -1 jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/core/UseListTag.java Index: UseListTag.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/core/UseListTag.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- UseListTag.java 30 Sep 2002 17:46:59 -0000 1.2 +++ UseListTag.java 17 Oct 2002 07:51:31 -0000 1.3 @@ -62,6 +62,7 @@ import java.util.Map; import org.apache.commons.jelly.expression.Expression; +import org.apache.commons.jelly.impl.CollectionTag; /** * A tag which creates a List implementation and optionally @@ -73,7 +74,7 @@ * @author <a href="mailto:[EMAIL PROTECTED]">James Strachan</a> * @version $Revision$ */ -public class UseListTag extends UseBeanTag { +public class UseListTag extends UseBeanTag implements CollectionTag { private Expression items; @@ -85,6 +86,12 @@ } + // CollectionTag interface + //------------------------------------------------------------------------- + public void addItem(Object value) { + getList().add(value); + } + // DynaTag interface //------------------------------------------------------------------------- public Class getAttributeType(String name) throws Exception { 1.2 +50 -1 jakarta-commons-sandbox/jelly/src/test/org/apache/commons/jelly/bean/suite.jelly Index: suite.jelly =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/test/org/apache/commons/jelly/bean/suite.jelly,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- suite.jelly 16 Oct 2002 18:17:57 -0000 1.1 +++ suite.jelly 17 Oct 2002 07:51:31 -0000 1.2 @@ -6,7 +6,7 @@ xmlns:test="jelly:junit" xmlns:log="jelly:log"> -<test:case name="simpleBean"> +<test:case name="testNestedBean"> <customer var="c1" name="James" location="London" > <order amount="100" price="2.99"> @@ -41,6 +41,55 @@ <test:assertEquals expected="Pizza" actual="${c1.orders[1].product.name}"/> +</test:case> + + +<test:case name="testBeanList"> + + <j:useList var="list"> + <customer name="James" location="London"> + <order amount="100" price="2.99"> + <product id="p1" name="Beer"/> + </order> + <order amount="200" price="4.99"> + <product id="p2" name="Pizza"/> + </order> + </customer> + <customer name="Bob" location="Atlanta"> + <order amount="200" price="2.99"> + <product id="p1" name="Beer"/> + </order> + </customer> + </j:useList> + + <log:info>Created a list of customers ${list}</log:info> + + <test:assertTrue test="${size(list) == 2}"/> + + <test:assertEquals expected="James" actual="${list[0].name}"/> + <test:assertEquals expected="London" actual="${list[0].location}"/> + + <test:assertTrue test="${size(list[0].orders) == 2}"/> + + <test:assertTrue test="${list[0].orders[0].amount == 100}"/> + <test:assertTrue test="${list[0].orders[0].price == 2.99}"/> + + <test:assertTrue test="${list[0].orders[1].amount == 200}"/> + <test:assertTrue test="${list[0].orders[1].price == 4.99}"/> + + <test:assertTrue test="${list[0].orders[0].product != null}"/> + <test:assertTrue test="${list[0].orders[1].product != null}"/> + + <test:assertEquals expected="p1" actual="${list[0].orders[0].product.id}"/> + <test:assertEquals expected="Beer" actual="${list[0].orders[0].product.name}"/> + + <test:assertEquals expected="p2" actual="${list[0].orders[1].product.id}"/> + <test:assertEquals expected="Pizza" actual="${list[0].orders[1].product.name}"/> + + + <test:assertEquals expected="Bob" actual="${list[1].name}"/> + <test:assertEquals expected="Atlanta" actual="${list[1].location}"/> + </test:case> </test:suite>
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>