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) {