Array in bean causes element after to not be set
------------------------------------------------

                 Key: BETWIXT-61
                 URL: https://issues.apache.org/jira/browse/BETWIXT-61
             Project: Commons Betwixt
          Issue Type: Bug
         Environment: Windows XP, Suns Java 1.5.0_07, Betwixt Version 0.8 
Source.
            Reporter: Stephen Halsey


Hi,

I am having a problem with a class that has arrays in it and writing and 
reading them using betwixt.  I have tracked down the problem and created a 
simple unit test with the 3 classes below that demonstate this.  If you create 
a new org.apache.commons.betwixt.arraybug package in your src/test folder of 
you betwixt source code and put these classes in you should be able to run the 
tests.

I have put an explanation of what the test does at the top of the 
TestBetwixtArrayBugUnit class.

I'm sorry if I've just used the wrong settings or something, but I based it on 
the code from the examples page at 
http://commons.apache.org/betwixt/guide/examples.html for doing a round trip on 
a simple bean.

I'm not sure, but there is a chance this could be related to the error someone 
reported at:-

http://markmail.org/message/ofm3yp7gf7auhfcp

because I may have seen the EmptyStackException under certain circumstances too 
whilst developing this test, but in this test you will see no exception is 
generated, the value just comes out null for the xxx parameter because it is 
alphabetically after the array parameter, which is actually more worrying as 
its a lot harder to spot.

If you would like me to I can do a bit more work and get sample debug output to 
try and work out why it is doing what it is doing?

thanks




Steve






package org.apache.commons.betwixt.arraybug;

import java.beans.IntrospectionException;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

import junit.framework.TestCase;
import org.apache.commons.betwixt.io.BeanReader;
import org.apache.commons.betwixt.io.BeanWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;


/*
 * TestBetwixtArrayBugUnit class.
 * 
 * This class contains two unit tests. One will run
 * successfully and do a round trip on a simple bean,  
 * the other will fail because a value has not been set
 * on reading a bean out of xml using betwixt.  This
 * seems to happens when a String array is read
 * in, and means that all variables alphabeticically 
 * after is will be null.  From looking at the output
 * with logging set to debug you can see that the xxx
 * parameter value does not have the "Calling setter method"
 * part in it when the test fails.
 * 
 * 
 * 
 */
public class TestBetwixtArrayBugUnit extends TestCase {

        
    static Log log = LogFactory.getLog( TestBetwixtArrayBugUnit.class );

        public void testRoundTripThatWorks() throws IOException, SAXException, 
IntrospectionException
    {
        log.info("In this test we test a round trip of an object that works.  
We create a WithoutBugBean object, convert " +
                        "it to xml, convert from xml back into a new 
WithoutBugBean object "
                        + " and check that they are equal and we find that they 
are and so the test passes.");
        String aOriginal = "aString";
        String xxxOriginal = "xxxString";
        WithoutBugBean withoutBugBeanOriginal = new 
WithoutBugBean(aOriginal,xxxOriginal);

        
        log.info("Starting off with withoutBugBeanOriginal = " + 
withoutBugBeanOriginal);
        // Start by preparing the writer
        // We'll write to a string 
        StringWriter outputWriter = new StringWriter(); 
        
        // Betwixt just writes out the bean as a fragment
        // So if we want well-formed xml, we need to add the prolog
        outputWriter.write("<?xml version='1.0' ?>\n");
        
        // Create a BeanWriter which writes to our prepared stream
        BeanWriter beanWriter = new BeanWriter(outputWriter);
        
        // Configure betwixt
        // For more details see java docs or later in the main documentation
        
beanWriter.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(false);
        beanWriter.getBindingConfiguration().setMapIDs(false);
        beanWriter.enablePrettyPrint();

        // If the base element is not passed in, Betwixt will guess 
        // But let's write example bean as base element 'person'
        beanWriter.write("WithoutBugBean", withoutBugBeanOriginal);
        
        // Write to System.out
        // (We could have used the empty constructor for BeanWriter 
        // but this way is more instructive)
        String xmlString = outputWriter.toString();
        
        // Betwixt writes fragments not documents so does not automatically 
close 
        // writers or streams.
        // This example will do no more writing so close the writer now.
        outputWriter.close();
 
        log.info(" xmlString = " + xmlString);
        
        
        
        // First construct the xml which will be read in
        // For this example, read in from a hard coded string
        StringReader xmlReader = new StringReader(xmlString);
        
        // Now convert this to a bean using betwixt
        // Create BeanReader
        BeanReader beanReader  = new BeanReader();
        
        // Configure the reader
        // If you're round-tripping, make sure that the configurations are 
compatible!
        
beanReader.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(false);
        beanReader.getBindingConfiguration().setMapIDs(false);
        
        // Register beans so that betwixt knows what the xml is to be converted 
to
        // Since the element mapped to a PersonBean isn't called the same 
        // as Betwixt would have guessed, need to register the path as well
        beanReader.registerBeanClass("WithoutBugBean", WithoutBugBean.class);
       
        // Now we parse the xml
        WithoutBugBean withoutBugBeanNew = (WithoutBugBean) 
beanReader.parse(xmlReader);
        
        log.info("Got back withoutBugBeanNew = " + withoutBugBeanNew);
        
        log.info("Now checking that withoutBugBeanNew equals 
withoutBugBeanOriginal");
        assertTrue(withoutBugBeanNew.equals(withoutBugBeanOriginal));
    }
    
    
    public void testRoundTripThatDoesNotWorkWithArray() throws IOException, 
SAXException, IntrospectionException
    {
        log.info("In this test we test a round trip of an object with an array 
in that DOES NOT work.  " +
                        "As before we create a WithBugBean object, convert " +
                        "it to xml, convert from xml back into a new 
WithBugBean object "
                        + " and check that they are equal and we find that they 
are NOT because one of the elements is null.");
        String aOriginal = "aString";
        String[] littleArray = new String[2];
        littleArray[0] = "littleArrayString0";
        littleArray[1] = "littleArrayString1";
        String xxxOriginal = "xxxString";
        WithBugBean withBugBeanOriginal = new 
WithBugBean(aOriginal,littleArray,xxxOriginal);

        
        log.info("Starting off with withBugBeanOriginal = " + 
withBugBeanOriginal);
        // Start by preparing the writer
        // We'll write to a string 
        StringWriter outputWriter = new StringWriter(); 
        
        // Betwixt just writes out the bean as a fragment
        // So if we want well-formed xml, we need to add the prolog
        outputWriter.write("<?xml version='1.0' ?>\n");
        
        // Create a BeanWriter which writes to our prepared stream
        BeanWriter beanWriter = new BeanWriter(outputWriter);
        
        // Configure betwixt
        // For more details see java docs or later in the main documentation
        
beanWriter.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(false);
        beanWriter.getBindingConfiguration().setMapIDs(false);
        beanWriter.enablePrettyPrint();

        // If the base element is not passed in, Betwixt will guess 
        // But let's write example bean as base element 'person'
        beanWriter.write("WithBugBean", withBugBeanOriginal);
        
        // Write to System.out
        // (We could have used the empty constructor for BeanWriter 
        // but this way is more instructive)
        String xmlString = outputWriter.toString();
        
        // Betwixt writes fragments not documents so does not automatically 
close 
        // writers or streams.
        // This example will do no more writing so close the writer now.
        outputWriter.close();
 
        log.info(" xmlString = " + xmlString);
        
        
        
        // First construct the xml which will be read in
        // For this example, read in from a hard coded string
        StringReader xmlReader = new StringReader(xmlString);
        
        // Now convert this to a bean using betwixt
        // Create BeanReader
        BeanReader beanReader  = new BeanReader();
        
        // Configure the reader
        // If you're round-tripping, make sure that the configurations are 
compatible!
        
beanReader.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(false);
        beanReader.getBindingConfiguration().setMapIDs(false);
        
        // Register beans so that betwixt knows what the xml is to be converted 
to
        // Since the element mapped to a PersonBean isn't called the same 
        // as Betwixt would have guessed, need to register the path as well
        beanReader.registerBeanClass("WithBugBean", WithBugBean.class);
       
        // Now we parse the xml
        WithBugBean withBugBeanNew = (WithBugBean) beanReader.parse(xmlReader);
        
        log.info("Got back withBugBeanNew = " + withBugBeanNew);
        
        log.info("Now checking that withBugBeanNew equals 
withBugBeanOriginal.");
        log.info("At this point you should see the test FAIL because xxx has 
been set to null "
                        + " because it is alphabetically after the littleArray 
and betwixt suddenly seems to stop setting variables once "
                        + " it hits this littleArray");
        assertTrue(withBugBeanNew.equals(withBugBeanOriginal));
    }
    
        }






package org.apache.commons.betwixt.arraybug;

/*
 * WithBugBean class.
 * This is the bean that DOES demonstrate the betwixt bug with arrays because 
the xxx
 * variable gets set to null when you try to read it in.
 */

public class WithBugBean {
    
    private String a;
    //This class has the additional littleArray value.
    String[] littleArray;
    private String xxx;
       
    public WithBugBean()
    {
    }
    
    public WithBugBean(String a, String[] littleArray, String xxx)
    {
        setA(a);
        setLittleArray(littleArray);
        setXxx(xxx);
    }
    
    
    public String toString() {  
        return "[" + this.getClass().getName() + ": a=" + a + " xxx =  " + xxx 
+ "]";
    }

        public String getA() {
                return a;
        }

        public void setA(String a) {
                this.a = a;
        }

        public String getXxx() {
                return xxx;
        }

        public void setXxx(String xxx) {
                this.xxx = xxx;
        }
        
    public boolean equals( Object obj ) {
        if ( obj == null ) return false;
        return this.hashCode() == obj.hashCode();
    }
    
    public int hashCode() {
        return toString().hashCode();
    }

        public String[] getLittleArray() {
                return littleArray;
        }

        public void setLittleArray(String[] littleArray) {
                this.littleArray = littleArray;
        }
}


















package org.apache.commons.betwixt.arraybug;


/*
 * WithoutBugBean class.
 * This is the bean that does not demonstrate the betwixt bug with arrays.
 */

public class WithoutBugBean {
    
    private String a;
    private String xxx;
       
    public WithoutBugBean()
    {
    }
    
    public WithoutBugBean(String a, String xxx)
    {
        setA(a);
        setXxx(xxx);
    }
    
    
    public String toString() {  
        return "[" + this.getClass().getName() + ": a=" + a + " xxx =  " + xxx 
+ "]";
    }

        public String getA() {
                return a;
        }

        public void setA(String a) {
                this.a = a;
        }

        public String getXxx() {
                return xxx;
        }

        public void setXxx(String xxx) {
                this.xxx = xxx;
        }
        
    public boolean equals( Object obj ) {
        if ( obj == null ) return false;
        return this.hashCode() == obj.hashCode();
    }
    
    public int hashCode() {
        return toString().hashCode();
    }
}







-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to