You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by dk...@apache.org on 2010/10/07 17:51:03 UTC
svn commit: r1005501 - in /cxf/branches/2.2.x-fixes: ./
rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java
Author: dkulp
Date: Thu Oct 7 15:51:03 2010
New Revision: 1005501
URL: http://svn.apache.org/viewvc?rev=1005501&view=rev
Log:
Merged revisions 1005499 via svnmerge from
https://svn.apache.org/repos/asf/cxf/trunk
........
r1005499 | dkulp | 2010-10-07 11:49:15 -0400 (Thu, 07 Oct 2010) | 3 lines
[CXF-3047] When validating, wrapper the reader with a new reader that
will fake some extra NS events to work around definciencies in the stax
and validation API's
........
Modified:
cxf/branches/2.2.x-fixes/ (props changed)
cxf/branches/2.2.x-fixes/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java
Propchange: cxf/branches/2.2.x-fixes/
('svn:mergeinfo' removed)
Propchange: cxf/branches/2.2.x-fixes/
------------------------------------------------------------------------------
Binary property 'svnmerge-integrated' - no diff available.
Modified: cxf/branches/2.2.x-fixes/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.2.x-fixes/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java?rev=1005501&r1=1005500&r2=1005501&view=diff
==============================================================================
--- cxf/branches/2.2.x-fixes/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java (original)
+++ cxf/branches/2.2.x-fixes/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java Thu Oct 7 15:51:03 2010
@@ -34,9 +34,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
+import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
import java.util.logging.Logger;
@@ -49,7 +52,9 @@ import javax.xml.bind.annotation.XmlAcce
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import javax.xml.bind.attachment.AttachmentMarshaller;
import javax.xml.bind.attachment.AttachmentUnmarshaller;
+import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamConstants;
@@ -723,7 +728,6 @@ public final class JAXBEncoderDecoder {
public static Object unmarshall(Unmarshaller u, Object source, QName elName,
Class<?> clazz, boolean unwrap) {
Object obj = null;
-
try {
boolean unmarshalWithClass = true;
@@ -751,11 +755,22 @@ public final class JAXBEncoderDecoder {
// as it doesn't read beyond the end so the DepthXMLStreamReader state
// would be OK when it returns. The main winner is FastInfoset where parsing
// a testcase I have goes from about 300/sec to well over 1000.
+
DepthXMLStreamReader dr = (DepthXMLStreamReader)source;
- obj = unmarshalWithClass ? u.unmarshal(dr.getReader(), clazz) : u
+ XMLStreamReader reader = dr.getReader();
+ if (u.getSchema() != null) {
+ //validating, but we may need more namespaces
+ reader = findExtraNamespaces(reader);
+ }
+ obj = unmarshalWithClass ? u.unmarshal(reader, clazz) : u
.unmarshal(dr.getReader());
} else if (source instanceof XMLStreamReader) {
- obj = unmarshalWithClass ? u.unmarshal((XMLStreamReader)source, clazz) : u
+ XMLStreamReader reader = (XMLStreamReader)source;
+ if (u.getSchema() != null) {
+ //validating, but we may need more namespaces
+ reader = findExtraNamespaces(reader);
+ }
+ obj = unmarshalWithClass ? u.unmarshal(reader, clazz) : u
.unmarshal((XMLStreamReader)source);
} else if (source instanceof XMLEventReader) {
obj = unmarshalWithClass ? u.unmarshal((XMLEventReader)source, clazz) : u
@@ -782,6 +797,98 @@ public final class JAXBEncoderDecoder {
}
return unwrap ? getElementValue(obj) : obj;
}
+
+ private static XMLStreamReader findExtraNamespaces(XMLStreamReader source) {
+ //due to a deficiency in the Stax API, there isn't a way to get all
+ //the namespace prefixes that are "valid" at this point. Thus, JAXB
+ //cannot set all the prefixes into the validator (which also doesn't allow
+ //setting a NSContext, just allows declaring of prefixes) so resolving
+ //prefixes and such will fail if they were declared on any of the parent
+ //elements.
+ //
+ //We'll use some reflection to grab the known namespaces from woodstox
+ //or the xerces parser and fake extra namespace decls on the root elements.
+ //slight performance penalty, but there already is a penalty if you are validating
+ //anyway.
+
+ NamespaceContext c = source.getNamespaceContext();
+ final Map<String, String> nsMap = new TreeMap<String, String>();
+ try {
+ try {
+ //Woodstox version
+ c = (NamespaceContext)c.getClass().getMethod("createNonTransientNsContext", Location.class)
+ .invoke(c, new Object[1]);
+ } catch (Throwable t) {
+ //ignore
+ }
+ Field f = c.getClass().getDeclaredField("mNamespaces");
+ f.setAccessible(true);
+ String ns[] = (String[])f.get(c);
+ for (int x = 0; x < ns.length; x += 2) {
+ nsMap.put(ns[x], ns[x + 1]);
+ }
+ } catch (Throwable t) {
+ //internal JDK/xerces version
+ try {
+ Field f = c.getClass().getDeclaredField("fNamespaceContext");
+ f.setAccessible(true);
+ Object c2 = f.get(c);
+ Enumeration enm = (Enumeration)c2.getClass().getMethod("getAllPrefixes").invoke(c2);
+ while (enm.hasMoreElements()) {
+ String s = (String)enm.nextElement();
+ nsMap.put(s, c.getNamespaceURI(s));
+ }
+ } catch (Throwable t2) {
+ //ignore
+ }
+ }
+ if (!nsMap.isEmpty()) {
+ for (int x = 0; x < source.getNamespaceCount(); x++) {
+ String pfx = source.getNamespacePrefix(x);
+ nsMap.remove(pfx);
+ }
+ if (!nsMap.isEmpty()) {
+ @SuppressWarnings("unchecked")
+ final Map.Entry<String, String> namespaces[]
+ = nsMap.entrySet().toArray(new Map.Entry[nsMap.size()]);
+ //OK. we have extra namespaces. We'll need to wrapper the reader
+ //with a new one that will fake extra namespace events
+ source = new DepthXMLStreamReader(source) {
+ public int getNamespaceCount() {
+ if (getDepth() == 0 && isStartElement()) {
+ return super.getNamespaceCount() + nsMap.size();
+ }
+ return super.getNamespaceCount();
+ }
+
+ public String getNamespacePrefix(int arg0) {
+ if (getDepth() == 0 && isStartElement()) {
+ int i = super.getNamespaceCount();
+ if (arg0 >= i) {
+ arg0 -= i;
+ return namespaces[arg0].getKey();
+ }
+ }
+ return super.getNamespacePrefix(arg0);
+ }
+
+ public String getNamespaceURI(int arg0) {
+ if (getDepth() == 0 && isStartElement()) {
+ int i = super.getNamespaceCount();
+ if (arg0 >= i) {
+ arg0 -= i;
+ return namespaces[arg0].getValue();
+ }
+ }
+ return super.getNamespaceURI(arg0);
+ }
+
+ };
+ }
+ }
+
+ return source;
+ }
public static Object getElementValue(Object obj) {
if (null == obj) {