You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by mv...@apache.org on 2003/11/24 02:58:24 UTC

cvs commit: jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io BeanRuleSet.java

mvdb        2003/11/23 17:58:24

  Modified:    betwixt/src/java/org/apache/commons/betwixt/io
                        BeanRuleSet.java
  Added:       betwixt/src/test/org/apache/commons/betwixt/dotbetwixt
                        MsgBean.betwixt MsgBean.java MsgParserTest.java
  Log:
   The problem fixed here is that an element without an updater would
   not process it's attributes correctly even though they had updaters when creating the bean.
  Thanx to Mike Stanly for spotting this and supplying a testcase for it.
  (I refactored the testcase a bit, so all original exceptions are thrown nicely) and to put the test into 1 class (except for the bean)
  
  Permission from Mike was granted to add his test to betwixt through this mail: 
  http://nagoya.apache.org/eyebrowse/ReadMsg?listName=commons-dev@jakarta.apache.org&msgId=1122934
  
  
  
  Revision  Changes    Path
  1.1                  jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/dotbetwixt/MsgBean.betwixt
  
  Index: MsgBean.betwixt
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <info>
  	<element name="message">
  		<attribute name="type" property="type"/>
  		<attribute name="to" property="toAddress"/>
  		<attribute name="from" property="fromAddress"/>		
  		<element name="body">
  			<attribute name="name" property="name"/>
  			<attribute name="status" property="status"/>
  			<element name="description" property="description"/>
  			<element name="optional">
  				<element name="field-1">
  					<attribute name="value" property="optionalField1"/>
  				</element>
  				<element name="field-2">
  					<attribute name="value" property="optionalField2"/>
  				</element>
  			</element>
  		</element>
  	</element>
  </info>
  
  
  
  1.1                  jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/dotbetwixt/MsgBean.java
  
  Index: MsgBean.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/dotbetwixt/MsgBean.java,v 1.1 2003/11/24 01:58:24 mvdb Exp $
   * $Revision: 1.1 $
   * $Date: 2003/11/24 01:58:24 $
   *
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001-2003 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 acknowledgement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgement may appear in the software itself,
   *    if and wherever such third-party acknowledgements normally appear.
   *
   * 4. The names "Apache", "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 apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache" nor may "Apache" appear in their names without prior 
   *    written permission of the Apache Software Foundation.
   *
   * 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/>.
   *
   */ 
  package org.apache.commons.betwixt.dotbetwixt;
  
  /**
   * The bean used to identify a problem there was when a dotbetwixt file
   * did not have any update methods on the element, but on the attributes.
   * 
   * @author <a href="mstanley@cauldronsolutions.com">Mike Stanley</a>
   * @version $Id: MsgBean.java,v 1.1 2003/11/24 01:58:24 mvdb Exp $
   */
  public class MsgBean
  {
      private String type;
      private String status;
      private String name;
      private String description;
      private String toAddress;
      private String fromAddress;
      private String optionalField1;
      private String optionalField2;    
  
      /**
       * 
       */
      public MsgBean()
      {
          super();
      }
  
      /**
       * @return
       */
      public String getFromAddress()
      {
          return fromAddress;
      }
  
      /**
       * @param fromAddress
       */
      public void setFromAddress(String fromAddress)
      {
          this.fromAddress = fromAddress;
      }
  
      /**
       * @return
       */
      public String getName()
      {
          return name;
      }
  
      /**
       * @param name
       */
      public void setName(String name)
      {
          this.name = name;
      }
  
      /**
       * @return
       */
      public String getStatus()
      {
          return status;
      }
  
      /**
       * @param status
       */
      public void setStatus(String status)
      {
          this.status = status;
      }
  
      /**
       * @return
       */
      public String getToAddress()
      {
          return toAddress;
      }
  
      /**
       * @param toAddress
       */
      public void setToAddress(String toAddress)
      {
          this.toAddress = toAddress;
      }
  
      /**
       * @return
       */
      public String getType()
      {
          return type;
      }
  
      /**
       * @param type
       */
      public void setType(String type)
      {
          this.type = type;
      }
  
      /**
       * @return
       */
      public String getDescription()
      {
          return description;
      }
  
      /**
       * @param description
       */
      public void setDescription(String description)
      {
          this.description = description;
      }
  
      /**
       * @return
       */
      public String getOptionalField1()
      {
          return optionalField1;
      }
  
      /**
       * @param optionalField1
       */
      public void setOptionalField1(String optionalField1)
      {
          this.optionalField1 = optionalField1;
      }
  
      /**
       * @return
       */
      public String getOptionalField2()
      {
          return optionalField2;
      }
  
      /**
       * @param optionalField2
       */
      public void setOptionalField2(String optionalField2)
      {
          this.optionalField2 = optionalField2;
      }
  
  }
  
  
  
  1.1                  jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/dotbetwixt/MsgParserTest.java
  
  Index: MsgParserTest.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/betwixt/src/test/org/apache/commons/betwixt/dotbetwixt/MsgParserTest.java,v 1.1 2003/11/24 01:58:24 mvdb Exp $
   * $Revision: 1.1 $
   * $Date: 2003/11/24 01:58:24 $
   *
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001-2003 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 acknowledgement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgement may appear in the software itself,
   *    if and wherever such third-party acknowledgements normally appear.
   *
   * 4. The names "Apache", "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 apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache" nor may "Apache" appear in their names without prior 
   *    written permission of the Apache Software Foundation.
   *
   * 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/>.
   *
   */ 
   package org.apache.commons.betwixt.dotbetwixt;
  
  import java.io.StringReader;
  import java.io.StringWriter;
  
  import org.apache.commons.betwixt.io.BeanReader;
  import org.apache.commons.betwixt.io.BeanWriter;
  
  import junit.framework.TestCase;
  /**
   * Tests the marshalling and unmarshalling of MsgBeans with Betwixt.
   * The problem tested here is that an element without an updater would
   * not process it's attributes correctly even though they had updaters.
   * 
   * @author <a href="mstanley@cauldronsolutions.com">Mike Stanley</a>
   * @version $Id: MsgParserTest.java,v 1.1 2003/11/24 01:58:24 mvdb Exp $
   */
  public class MsgParserTest extends TestCase
  {
      private static final String XML_PROLOG = "<?xml version='1.0' ?>\n";
      private MsgBean msg;
  
      /*
       * @see TestCase#setUp()
       */
      protected void setUp() throws Exception
      {
          msg = new MsgBean();
          msg.setDescription("Some simple descriptive text");
          msg.setToAddress("mike@somewhere.com");
          msg.setFromAddress("debbie@somwhere.com");
          msg.setName("basicMsg");
          msg.setOptionalField1("7-12-99");
          msg.setOptionalField2("true");
          msg.setStatus("sent");
          msg.setType("spam");
      }
  
      public void testGetAsXml() throws Exception
      {
          String xmlMsg = null;
          xmlMsg = getAsXml(msg);            
          assertNotNull("XML String should not be null", xmlMsg);
          
      }
  
      public void testParseMsg() throws Exception
      {
          MsgBean newMsg = null;
         // install request marshall/unmarshall
         String xmlMsg = getAsXml(msg);
         newMsg = parseMsg(xmlMsg);
  
         assertNotNull("new MsgBean should not be null.", newMsg);
         assertEquals( msg.getDescription(), newMsg.getDescription() );
         assertEquals( msg.getFromAddress(), newMsg.getFromAddress() );
         assertEquals( msg.getName(), newMsg.getName() );
         assertEquals( msg.getOptionalField1(), newMsg.getOptionalField1() );
         assertEquals( msg.getOptionalField2(), newMsg.getOptionalField2() );
         assertEquals( msg.getStatus(), newMsg.getStatus() );
         assertEquals( msg.getToAddress(), newMsg.getToAddress() );
         assertEquals( msg.getType(), newMsg.getType() );
      }
      
      /**
       * Returns the bean as an xml string.
       * 
       * @param msg
       * @return
       * @throws Exception
       */
      public static final String getAsXml(MsgBean msg) 
      throws Exception
      {
          StringWriter writer = new StringWriter();
  
          // Betwixt just writes out the bean as a fragment
          // we want well-formed xml, we need to add the prolog
          writer.write(XML_PROLOG);
  
          // Create a BeanWriter which writes to our prepared stream
          BeanWriter beanWriter = new BeanWriter(writer);
  
          // Configure betwixt
          // For more details see java docs or later in the main documentation
          beanWriter.getXMLIntrospector().setAttributesForPrimitives(true);
          beanWriter.setWriteIDs(false);
          beanWriter.enablePrettyPrint();
  
          // Write example bean as base element 'person'
          beanWriter.write("message", msg);
          beanWriter.flush();
  
          return writer.toString();
      }
      
      /**
       * Parses the passed in message xml
       * 
       * @param xmlMessage
       * @return
       * @throws Exception
       */
      public static final MsgBean parseMsg(String xmlMessage)
          throws Exception
      {
          MsgBean msg = null;
          BeanReader beanReader = new BeanReader();
          // Configure the reader
          beanReader.getXMLIntrospector().setAttributesForPrimitives(true);
          // Register beans so that betwixt knows what the xml is 
          beanReader.registerBeanClass("message", MsgBean.class);
          StringReader stringReader = new StringReader(xmlMessage);
          return  (MsgBean) beanReader.parse(stringReader);
      }
      
      
  
  }
  
  
  
  1.16      +87 -68    jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanRuleSet.java
  
  Index: BeanRuleSet.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanRuleSet.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- BeanRuleSet.java	9 Oct 2003 20:52:06 -0000	1.15
  +++ BeanRuleSet.java	24 Nov 2003 01:58:24 -0000	1.16
  @@ -89,6 +89,7 @@
   /** <p>Sets <code>Betwixt</code> digestion rules for a bean class.</p>
     *
     * @author <a href="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
  +  * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
     * @version $Revision$
     */
   public class BeanRuleSet implements RuleSet {
  @@ -405,6 +406,13 @@
                           if ( log.isTraceEnabled() ) {
                               log.trace("Element does not have updater: " + childDescriptor);
                           }
  +                        if (childDescriptor.hasAttributes()) {
  +                            if ( log.isTraceEnabled() ) {
  +                                log.trace( "Element has attributes, so adding rule anyway : "
  +                                            + childDescriptor );
  +                            }
  +                            addRule(path,childDescriptor, context);
  +                        }
                       }
       
                       ElementDescriptor[] grandChildren = childDescriptor.getElementDescriptors();
  @@ -618,8 +626,10 @@
                 * @see Rule#begin(String, String, Attributes)
                 */
               public void begin(String namespace, String name, Attributes attributes) {
  -                log.debug( "Called with descriptor: " + descriptor 
  -                            + " propertyType: " + descriptor.getPropertyType() );
  +                if ( log.isDebugEnabled() ) {
  +                    log.debug( "Called with descriptor: " + descriptor 
  +                                + " propertyType: " + descriptor.getPropertyType() );
  +                }
                   
                   if (log.isTraceEnabled()) {
                       int attributesLength = attributes.getLength();
  @@ -633,81 +643,86 @@
                       }
                   }
                   
  -        
  -                
                   // XXX: if a single rule instance gets reused and nesting occurs
                   // XXX: we should probably use a stack of booleans to test if we created a bean
                   // XXX: or let digester take nulls, which would be easier for us ;-)
                   createdBean = false;
  -                        
                   Object instance = null;
  -                if ( beanClass != null ) {
  +                // if we are a reference to a type we should lookup the original
  +                // as this ElementDescriptor will be 'hollow' 
  +                // and have no child attributes/elements.
  +                // XXX: this should probably be done by the NodeDescriptors...
  +                ElementDescriptor typeDescriptor = getElementDescriptor( descriptor );
  +                if ( typeDescriptor.getUpdater() == null && beanClass == null ) {
  +                    // we try to get the instance from the context.
  +                    instance = context.getBean();
  +                    if ( instance == null ) {
  +                        return;
  +                    }
  +                } else {
                       instance = createBean( namespace, name, attributes );
                       if ( instance != null ) {
                           createdBean = true;
                           context.setBean( instance );
                           digester.push( instance );
  +                    } else {
  +                        // we don't do anything if the instance is null.
  +                        return;
  +                    }
  +                }
  +        
  +                // iterate through all attributes        
  +                AttributeDescriptor[] attributeDescriptors 
  +                    = typeDescriptor.getAttributeDescriptors();
  +                if ( attributeDescriptors != null ) {
  +                    for ( int i = 0, size = attributeDescriptors.length; i < size; i++ ) {
  +                        AttributeDescriptor attributeDescriptor = attributeDescriptors[i];
                           
  -                
  -                        // if we are a reference to a type we should lookup the original
  -                        // as this ElementDescriptor will be 'hollow' 
  -                        // and have no child attributes/elements.
  -                        // XXX: this should probably be done by the NodeDescriptors...
  -                        ElementDescriptor typeDescriptor = getElementDescriptor( descriptor );
  -                        //ElementDescriptor typeDescriptor = descriptor;
  -                
  -                        // iterate through all attributes        
  -                        AttributeDescriptor[] attributeDescriptors 
  -                            = typeDescriptor.getAttributeDescriptors();
  -                        if ( attributeDescriptors != null ) {
  -                            for ( int i = 0, size = attributeDescriptors.length; i < size; i++ ) {
  -                                AttributeDescriptor attributeDescriptor = attributeDescriptors[i];
  -                                
  -                                // The following isn't really the right way to find the attribute
  -                                // but it's quite robust.
  -                                // The idea is that you try both namespace and local name first
  -                                // and if this returns null try the qName.
  -                                String value = attributes.getValue( 
  -                                    attributeDescriptor.getURI(),
  -                                    attributeDescriptor.getLocalName() 
  -                                );
  -                                
  -                                if (value == null) {
  -                                    value = attributes.getValue(
  -                                        attributeDescriptor.getQualifiedName());
  -                                }
  -                                
  -                                if (log.isTraceEnabled()) {
  -                                    log.trace("Attr URL:" + attributeDescriptor.getURI());
  -                                    log.trace(
  -                                                "Attr LocalName:" 
  -                                                + attributeDescriptor.getLocalName() );
  -                                    log.trace(value);
  -                                }
  -                                
  -                                Updater updater = attributeDescriptor.getUpdater();
  -                                log.trace(updater);
  -                                if ( updater != null && value != null ) {
  -                                    updater.update( context, value );
  -                                }
  -                            }
  +                        // The following isn't really the right way to find the attribute
  +                        // but it's quite robust.
  +                        // The idea is that you try both namespace and local name first
  +                        // and if this returns null try the qName.
  +                        String value = attributes.getValue( 
  +                            attributeDescriptor.getURI(),
  +                            attributeDescriptor.getLocalName() 
  +                        );
  +                        
  +                        if ( value == null ) {
  +                            value = attributes.getValue(
  +                                attributeDescriptor.getQualifiedName());
                           }
                           
  -                        if (log.isTraceEnabled()) {
  -                            log.trace("Created bean " + instance);
  -                            log.trace("Path prefix: " + pathPrefix);
  +                        if ( log.isTraceEnabled() ) {
  +                            log.trace("Attr URL:" + attributeDescriptor.getURI());
  +                            log.trace(
  +                                        "Attr LocalName:" 
  +                                        + attributeDescriptor.getLocalName() );
  +                            log.trace(value);
                           }
                           
  -                        // add bean for ID matching
  -                        if ( context.getMapIDs() ) {
  -                            // XXX need to support custom ID attribute names
  -                            // XXX i have a feeling that the current mechanism might need to change
  -                            // XXX so i'm leaving this till later
  -                            String id = attributes.getValue( "id" );
  -                            if ( id != null ) {
  -                                context.putBean( id, instance );
  -                            }
  +                        Updater updater = attributeDescriptor.getUpdater();
  +                        if ( log.isTraceEnabled() ) {
  +                            log.trace("Updater : "+updater);
                           }
  +                        if ( updater != null && value != null ) {
  +                            updater.update( context, value );
  +                        }
  +                    }
  +                }
  +                
  +                if ( log.isTraceEnabled() ) {
  +                    log.trace("Created bean " + instance);
  +                    log.trace("Path prefix: " + pathPrefix);
  +                }
  +                
  +                // add bean for ID matching
  +                if ( context.getMapIDs() ) {
  +                    // XXX need to support custom ID attribute names
  +                    // XXX i have a feeling that the current mechanism might need to change
  +                    // XXX so i'm leaving this till later
  +                    String id = attributes.getValue( "id" );
  +                    if ( id != null ) {
  +                        context.putBean( id, instance );
                       }
                   }
               }
  @@ -717,7 +732,9 @@
                 */
               public void body(String namespace, String name, String text) {
                   
  -                log.trace("Body with text " + text);
  +                if ( log.isTraceEnabled() ) {
  +                    log.trace("Body with text " + text);
  +                }
                   if ( digester.getCount() > 0 ) {
                       Context bodyContext = context.newContext( digester.peek() );
                       // Take the first content descriptor
  @@ -729,8 +746,10 @@
                               log.trace(descriptor);
                           }
                           Updater updater = descriptor.getUpdater();
  -                        log.trace( "Updating mixed content with:" );
  -                        log.trace( updater );
  +                        if ( log.isTraceEnabled() ) {
  +                            log.trace( "Updating mixed content with:" );
  +                            log.trace( updater );
  +                        }
                           if ( updater != null && text != null ) {
                               updater.update( bodyContext, text );
                           }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org