ArrayIndexOutOfBoundsException caused by org.jibx.extras.DomMapperBase
----------------------------------------------------------------------

                 Key: JIBX-228
                 URL: http://jira.codehaus.org/browse/JIBX-228
             Project: JiBX
          Issue Type: Bug
          Components: core
    Affects Versions: JiBX 1.1.6
         Environment: JiBX v1.1.6a
JDK v1.5.0_06
Eclipse IDE "Ganymede" v3.4 + JiBX eclipse plugin activated
            Reporter: Alexandre Delarge
             Fix For: JiBX 1.1.6
         Attachments: jibx-jira.zip

Hello,


I refactored a web service application that made heavy usage of DOM 
generation/parsing to use JiBX instead.

While working on this, I wrote a couple JiBX bindings that rely on the 
"org.jibx.extras.DomElementMapper" class that comes as a part of JiBX extras.

Using this mapper to marshall arbitrary portions of DOM trees raised a number 
of ArrayIndexOutOfBoundsException that prevented my application to success in 
generating response messages.

I drilled down these error causes into JiBX source code, and here is what I 
found (note: all references to source code below are taken from v1.1.6a).


1) Lookup of known namespaces & prefixes
==================================

In class "org.jibx.extras.DomMapperBase", in many places inside the method 
"findNamespaceIndex" you return -1 if you don't find a namespace prefix among 
the list owned by the m_xmlWriter object.
Here is an example on line 123:
---
  [...]
  int index = m_xmlWriter.getPrefixIndex(prefix);
  if (index >= 0) {
      return getNamespaceUri(index).equals(uri) ?
          index : -1;
  } else {        // line 122
      return -1;  // line 123
  }
  [...]
---

This -1 value greatly increases the chances of getting an 
ArrayIndexOutOfBoundsException from method "getNamespacePrefix(int index)" in 
class "org.jibx.runtime.impl.XMLWriterNamespaceBase".

The -1 value results from a failure in finding the exact given prefix in the 
list of prefixes the m_xmlWriter object owns. 
I think that looking for the namespace itself inside the list of namespace URIs 
owned by the m_xmlWriter object will do the right job, while suppressing many 
of the exceptions.
To me it sounds valid, because it happens that the namespace URI is known but 
just associated to a different prefix.

During the marshalling of various DOM elements, I got bothered by this missing 
lookup in several places, so I implemented it into a new private method:
---
  /**
   * Get index number for declared namespace.
   *
   * @param uri namespace URI (empty string if none)
   * @return namespace index number, or <code>-1</code> if not declared or
   * masked
   */
  private int findNamespaceURIIndex(String uri) {
        String[] uris = m_xmlWriter.getNamespaces();
        for (int i = 0; i < uris.length; i++) {
                if(uris[i].equals(uri)) {
                        return i;
                }
        }
        return -1;
  }
---

Then I updated the "findNamespaceIndex" method accordingly, in the 3 following 
locations (lines 108, 115, and 123):
---
[...]
        } else {
           return findNamespaceURIIndex(uri);                     // line 108
        }
      } else {
        return -1;
      }
    } else {
    return m_defaultNamespaceURI.equals(uri) ?                    
            m_defaultNamespaceIndex : findNamespaceURIIndex(uri); // line 115
  }
} else {
    int index = m_xmlWriter.getPrefixIndex(prefix);
    if (index >= 0) {
        return getNamespaceUri(index).equals(uri) ?
            index : -1;
    } else {                                                       
        return findNamespaceURIIndex(uri);                           // line 123
    }
[...]
---


2) Discovery of namespaces & prefixes
==============================

I also had troubles with the strategy for handling some namespaces declarations 
coming from a DOM tree, with the same kind of symptoms showing up: 
ArrayIndexOutOfBoundsException rising from class 
"org.jibx.runtime.impl.StreamWriterBase", more exactly from method 
"writePrefix".

For that one I had to look closely at method "marshalElement" in class 
"org.jibx.extras.DomElementMapper", stepping into the algorithm for getting the 
right namespace index for the current element.

Actually, I think the following assignment at line 227 (by the way is the "==" 
operator wanted here, or is it "equals()" ?):
---
[...]
  if (uri == decluri) {
    nsi = defind;     // line 227
  }
[...]
---


Will occasionally de-activates the lookup for the right index among newly 
discovered namespaces, which is made at line 251:
---
[...]
  for (int i = 0; i < length; i++) {
    prefs[i] = (String)nss.get(i*2);
    uris[i] = (String)nss.get(i*2+1);
    nums[i] = base + i;
    if (nsi < 0 && uri.equals(uris[i])) {                   // line 251
      if ((prefix == null && prefs[i] == "") ||
        (prefix != null && prefix.equals(prefs[i]))) {
        nsi = base + i;
      }
    }
  }
[...]
---

This may result in an incorrect index being used, because the lookup made at 
line 251 takes into account the index shift introduced by the addition of new 
namespaces, while this assignment does not.
I therefore remove it.

However the main issue with that method in my humble opinion is the fact we 
don't check that we have found the element's namespace index just after we 
checked all the attributes for namespaces declarations.
I therefore added the following statements just before line 233:
---
[...]
  /*
   * if we get there without having found an index for the current
   * element's namespace, we add it to the list.
   */
  if(nsi == -1 && (nss == null || !nss.contains(uri))) {
        if(nss == null) nss = new ArrayList();
      nss.add(prefix == null ? "" : prefix);
      nss.add(uri == null ? "" : uri);
  }
[...]
---

I don't alter the value of "nsi", so the aforementioned lookup located at line 
251 will assign it with the right value.


I attach a sample Eclipse project to this report, it contains a sample set of 
Java classes, XML file, and binding that exhibits the 2nd issue (I cannot 
easily cause the 1st one to happen).
The code I bundle features a JUnit test case in class 
"test.jibx.junit.TestDomMapper".

I include my version of the "DomMapperBase" class, which enables the code I 
wrote  to work fine.
I also include a visual summary of the differences between the original 
version, of the class and mine, hoping this will help.


Regards,
Alex.

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: 
http://jira.codehaus.org/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

-------------------------------------------------------------------------
Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW!
Studies have shown that voting for your favorite open source project,
along with a healthy diet, reduces your potential for chronic lameness
and boredom. Vote Now at http://www.sourceforge.net/community/cca08
_______________________________________________
jibx-devs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jibx-devs

Reply via email to