Although the unmarshaller is configured with "unm.setIgnoreExtraElements( true )" the
UnmarshalHandler does not ignore a nested unknown tag which has the same name like a known tag
within a container two level higher.
i.e.:
<root>
<container1>
<culpritTag> <--
this is known by the schema
</culpritTag>
<container2>
<culpritTag> <-- this is NOT known by
the schema and should be ignored
...
</culpritTag>
</container2>
</container1>
</root>
The bug is located in the (private)
UnmarshalHandler.startElement method.
part of this method (my comments marked with
>>>>>HB<<<<<:
...
//-- loop through stack and find correct descriptor
int pIdx =
_stateInfo.size() - 2; //-- index of parentState
UnmarshalState targetState = parentState;
String path = "";
StringBuffer pathBuf = null;
int count = 0;
boolean isWrapper = false;
XMLClassDescriptor oldClassDesc = classDesc;
while (descriptor == null) {
descriptor =
classDesc.getFieldDescriptor(name, NodeType.Element);
>>>>>HB<<<<<: within the
third loop the descriptor is no more NULL since it has found the "culpritTag" in container1
//--
Namespace patch, should be moved to XMLClassDescriptor, but
//-- this is the least intrusive
patch at the moment. kv - 20030423
if ((descriptor != null) && (!descriptor.isContainer()))
{
if ((namespace != null) && (namespace.length() > 0)) {
if (!namespaceEquals(namespace,
descriptor.getNameSpaceURI())) {
//-- if descriptor namespace is not null, then we must
//--
have a namespace match, so set descriptor to null,
//-- or if descriptor is not a wildcard we can
also
//-- set to null.
if ((descriptor.getNameSpaceURI() != null) ||
(!descriptor.matches("*"))) {
descriptor = null;
}
}
}
}
//-- end namespace
patch
/*
If descriptor is null, we need to handle possible inheritence,
which might
not be described in the current ClassDescriptor.
This can be a slow process...for speed use the
match attribute
of the xml element in the mapping file. This logic might
not be completely
necessary, and perhaps we should remove it.
*/
if ((descriptor == null) && (count == 0) &&
(!targetState.wrapper)) {
MarshalFramework.InheritanceMatch[] matches =
searchInheritance(name, namespace, classDesc, _cdResolver);
if (matches.length != 0) {
InheritanceMatch match = matches[0];
descriptor = match.parentFieldDesc;
cdInherited =
match.inheritedClassDesc;
break; //-- found
}
isWrapper = (isWrapper ||
hasFieldsAtLocation(name, classDesc));
}
else if (descriptor != null) {
>>>>>HB<<<<<:
Flow is then entering here
String tmpPath = descriptor.getLocationPath();
if (tmpPath ==
null) tmpPath = "";
if (path.equals(tmpPath)) break; //-- found
>>>>>HB<<<<<: This if
returns false, so no break occurs, but the variable "descriptor" is still assigned so
it breaks
when it tries to enter the loop again.
You should put an else part where the "descriptor" is set to
NULL again.
}
else {
if (pathBuf == null)
pathBuf = new StringBuffer();
else
pathBuf.setLength(0);
pathBuf.append(path);
pathBuf.append('/');
pathBuf.append(name);
isWrapper = (isWrapper ||
hasFieldsAtLocation(pathBuf.toString(), classDesc));
}
//-- Make sure there are more
parent classes on stack
//-- otherwise break, since there is nothing to do
if (pIdx == 0)
break;
//-- adjust name and try parent
if (count == 0)
path = targetState.elementName;
else {
if (pathBuf == null)
pathBuf = new StringBuffer();
else
pathBuf.setLength(0);
pathBuf.append(targetState.elementName);
pathBuf.append('/');
pathBuf.append(path);
path = pathBuf.toString();
}
//-- get
--pIdx;
targetState = (UnmarshalState)_stateInfo.elementAt(pIdx);
classDesc =
targetState.classDesc;
count++;
}
//-- The field descriptor is still null, we face a
problem
if (descriptor == null) {
>>>>>HB<<<<<: This if is not entered since descriptor is
not NULL. But it should be entered !
//-- reset classDesc
classDesc = oldClassDesc;
//--
isWrapper?
if (isWrapper) {
state.classDesc = new
XMLClassDescriptorImpl(ContainerElement.class, name);
state.wrapper = true;
if
(debug) {
message("wrapper-element: " + name);
}
//-- process attributes
processWrapperAttributes(atts);
return;
}
String mesg = "unable to find
FieldDescriptor for '" + name;
mesg += "' in ClassDescriptor of " +
classDesc.getXMLName();
//-- unwrap classDesc, if necessary, for the check
//--
Introspector.introspected done below
if (classDesc instanceof
InternalXMLClassDescriptor) {
classDesc =
((InternalXMLClassDescriptor)classDesc).getClassDescriptor();
}
//-- If we are
skipping elements that have appeared in the XML but for
//-- which we have no mapping, increase the
ignore depth counter and return
if (! _strictElements) {
++_ignoreElementDepth;
//--
remove the StateInfo we just added
_stateInfo.pop();
if (debug) {
message(mesg + " -
ignoring extra element.");
}
return;
}
//if we have no field descriptor and
//the
class descriptor was introspected
//just log it
else if
(Introspector.introspected(classDesc)) {
//if (warn)
message(mesg);
return;
}
//-- otherwise report error since we cannot find a suitable
//-- descriptor
else {
throw new
SAXException(mesg);
}
} //-- end null descriptor
...