castor
  1. castor
  2. CASTOR-2921

Unmarshalling increases preinitialized array-length

    Details

    • Type: Bug Bug
    • Status: Open Open
    • Priority: Blocker Blocker
    • Resolution: Unresolved
    • Affects Version/s: 1.3.1
    • Fix Version/s: 1.3.4
    • Component/s: XML
    • Labels:
      None
    • Environment:
      Platform-independent
    • Testcase included:
      yes
    • Number of attachments :
      2

      Description

      Found a tricky bug when (un-)marshalling arrays.

      public class Dim1 {
         private int[] values;
      
         public Dim1() {
            this.values = new int[2];
         }
      
         //getters + setters for 'values'
      }
      

      If you marshal an instance of Dim1 and unmarshal it again, 'Dim1.values' has now four and not two values. I included a junit test-case that demonstrates the problem.

        Activity

        Hide
        Werner Guttmann added a comment -

        Martin, it looks like this is a side-effect of your constructor code. Once I removed the initialization of the array to the test method, everythings's fine.

        Show
        Werner Guttmann added a comment - Martin, it looks like this is a side-effect of your constructor code. Once I removed the initialization of the array to the test method, everythings's fine.
        Hide
        Werner Guttmann added a comment -

        Test case highlighting the problem with the constructor code.

        Show
        Werner Guttmann added a comment - Test case highlighting the problem with the constructor code.
        Hide
        Werner Guttmann added a comment -

        Actually, please ignore my last comment. It's completely wrong .. . Just looked at the test case again, and I think that you have got the wrong expectations. Here's why: Castor will add to your array, and that's it. If it has been initialized already. If the array would not have been initialized already, Castor would initialize it (to an array of 0 length). But in this case, the array has been initialized only.

        As such, there's no way for Castor to derive that you are trying to pre-initialize an array. From Castor's point of view, there's an property of type array, and it has been initialized already (is not null).

        Does this make sense ?

        Show
        Werner Guttmann added a comment - Actually, please ignore my last comment. It's completely wrong .. . Just looked at the test case again, and I think that you have got the wrong expectations. Here's why: Castor will add to your array, and that's it. If it has been initialized already. If the array would not have been initialized already, Castor would initialize it (to an array of 0 length). But in this case, the array has been initialized only. As such, there's no way for Castor to derive that you are trying to pre-initialize an array. From Castor's point of view, there's an property of type array, and it has been initialized already (is not null). Does this make sense ?
        Hide
        Martin Bolz added a comment -

        Hi Werner, when I noticed the described behavior I was just unsure how to feel about that...I know maybe it's a very theorical issue because I think it's not very common to initialize an array in a no-arg-constructor (?, not sure about that but I think this is just like the no-arg constructor of java.util.ArrayList works). It just didn't seem 'right' to me that the state of the instance changed by marshalling and unmarshalling again. From a users point of view I would expect that all non-transient and non-static fields are exactly the same after going through this process. Am I wrong here? Do you know if there is a particular reason why castor adds the newly created array and not simply overrides the reference?

        Show
        Martin Bolz added a comment - Hi Werner, when I noticed the described behavior I was just unsure how to feel about that...I know maybe it's a very theorical issue because I think it's not very common to initialize an array in a no-arg-constructor (?, not sure about that but I think this is just like the no-arg constructor of java.util.ArrayList works). It just didn't seem 'right' to me that the state of the instance changed by marshalling and unmarshalling again. From a users point of view I would expect that all non-transient and non-static fields are exactly the same after going through this process. Am I wrong here? Do you know if there is a particular reason why castor adds the newly created array and not simply overrides the reference?
        Hide
        Werner Guttmann added a comment -

        Hi Martin, I agree that the observed behaviour during a full round-trip does not feel right, but I guess one has to clearly distinguish between various things here:

        • object instantitation
        • object initialization
        • adding artefacts to such objects as a result of unmarshalling.

        As already said, if your POJO does not e.g. create the int[] instance, Castor will do so by using reflection and eventually calling newInstance(). But if the object instance already is in place, Castor will use it as it is to add objects to the array in your case.

        To clarify my argumen(s) even further, how would Castor be able to distinguish between an int[] initialized with default values (as in your case) and any values (2, 4) ? Personally, I do not think it should be able to do so.

        When it comes to your last question, Castor uses whatever is there. If there's an object instance of either an array or e.g. a LinkedList, it will use it and e.g. call the add() methid on the LinkedList. If there isn't such an instance, it will create it. In other words, either leave it up to Castor or control it yourself. But once you control it, that's it.

        Show
        Werner Guttmann added a comment - Hi Martin, I agree that the observed behaviour during a full round-trip does not feel right, but I guess one has to clearly distinguish between various things here: object instantitation object initialization adding artefacts to such objects as a result of unmarshalling. As already said, if your POJO does not e.g. create the int[] instance, Castor will do so by using reflection and eventually calling newInstance() . But if the object instance already is in place, Castor will use it as it is to add objects to the array in your case. To clarify my argumen(s) even further, how would Castor be able to distinguish between an int[] initialized with default values (as in your case) and any values (2, 4) ? Personally, I do not think it should be able to do so. When it comes to your last question, Castor uses whatever is there. If there's an object instance of either an array or e.g. a LinkedList , it will use it and e.g. call the add() methid on the LinkedList . If there isn't such an instance, it will create it. In other words, either leave it up to Castor or control it yourself. But once you control it, that's it.
        Hide
        Werner Guttmann added a comment -

        Martin, any thoughts on my last question ?

        Show
        Werner Guttmann added a comment - Martin, any thoughts on my last question ?
        Hide
        Martin Bolz added a comment -

        I'm sorry Werner but it still feels wrong to me to add something as a result of unmarshalling. I would instead expect castor to override the preinitialized array. Can't figure out the sense of the add-behavior in a scenario where I have the array populated with default values.

        If I remove the initialization of the array from the constructor just to adapt the behavior of the unmarshaller I'm ending up with having to initialize the array for myself each time I create an instance of the class. Give me a hint if I'm wrong but isn't my constructor supposed to initialize my private fields?

        Show
        Martin Bolz added a comment - I'm sorry Werner but it still feels wrong to me to add something as a result of unmarshalling. I would instead expect castor to override the preinitialized array. Can't figure out the sense of the add-behavior in a scenario where I have the array populated with default values. If I remove the initialization of the array from the constructor just to adapt the behavior of the unmarshaller I'm ending up with having to initialize the array for myself each time I create an instance of the class. Give me a hint if I'm wrong but isn't my constructor supposed to initialize my private fields?

          People

          • Assignee:
            Werner Guttmann
            Reporter:
            Martin Bolz
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated: