src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/StructureLoader.java

Sun, 31 Aug 2014 16:14:36 +0400

author
aefimov
date
Sun, 31 Aug 2014 16:14:36 +0400
changeset 707
31893650acaf
parent 650
121e938cb9c3
child 1103
face9bd6bac2
permissions
-rw-r--r--

8036981: JAXB not preserving formatting for xsd:any Mixed content
Reviewed-by: lancea, mkos

     1 /*
     2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.xml.internal.bind.v2.runtime.unmarshaller;
    28 import java.util.Collection;
    29 import java.util.HashMap;
    30 import java.util.Map;
    32 import javax.xml.namespace.QName;
    34 import com.sun.xml.internal.bind.api.AccessorException;
    35 import com.sun.xml.internal.bind.v2.WellKnownNamespace;
    36 import com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl;
    37 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
    38 import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo;
    39 import com.sun.xml.internal.bind.v2.runtime.property.AttributeProperty;
    40 import com.sun.xml.internal.bind.v2.runtime.property.Property;
    41 import com.sun.xml.internal.bind.v2.runtime.property.StructureLoaderBuilder;
    42 import com.sun.xml.internal.bind.v2.runtime.property.UnmarshallerChain;
    43 import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor;
    44 import com.sun.xml.internal.bind.v2.runtime.reflect.TransducedAccessor;
    45 import com.sun.xml.internal.bind.v2.util.QNameMap;
    47 import java.util.Iterator;
    48 import org.xml.sax.Attributes;
    49 import org.xml.sax.SAXException;
    51 /**
    52  * Loads children of an element.
    53  *
    54  * <p>
    55  * This loader works with a single {@link JaxBeanInfo} and handles
    56  * attributes, child elements, or child text.
    57  *
    58  * @author Kohsuke Kawaguchi
    59  */
    60 public final class StructureLoader extends Loader {
    61     /**
    62      * This map statically stores information of the
    63      * unmarshaller loader and can be used while unmarshalling
    64      * Since creating new QNames is expensive use this optimized
    65      * version of the map
    66      */
    67     private final QNameMap<ChildLoader> childUnmarshallers = new QNameMap<ChildLoader>();
    69     /**
    70      * Loader that processes elements that didn't match anf of the {@link #childUnmarshallers}.
    71      * Can be null.
    72      */
    73     private /*final*/ ChildLoader catchAll;
    75     /**
    76      * If we have a loader for processing text. Otherwise null.
    77      */
    78     private /*final*/ ChildLoader textHandler;
    80     /**
    81      * Unmarshallers for attribute values.
    82      * May be null if no attribute is expected and {@link #attCatchAll}==null.
    83      */
    84     private /*final*/ QNameMap<TransducedAccessor> attUnmarshallers;
    86     /**
    87      * This will receive all the attributes
    88      * that were not processed. Never be null.
    89      */
    90     private /*final*/ Accessor<Object,Map<QName,String>> attCatchAll;
    92     private final JaxBeanInfo beanInfo;
    94     /**
    95      * The number of scopes this dispatcher needs to keep active.
    96      */
    97     private /*final*/ int frameSize;
    99     // this class is potentially useful for general audience, not just for ClassBeanInfoImpl,
   100     // but since right now that is the only user, we make the construction code very specific
   101     // to ClassBeanInfoImpl. See rev.1.5 of this file for the original general purpose definition.
   102     public StructureLoader(ClassBeanInfoImpl beanInfo) {
   103         super(true);
   104         this.beanInfo = beanInfo;
   105     }
   107     /**
   108      * Completes the initialization.
   109      *
   110      * <p>
   111      * To fix the cyclic reference issue, the main part of the initialization needs to be done
   112      * after a {@link StructureLoader} is set to {@link ClassBeanInfoImpl#loader}.
   113      */
   114     public void init( JAXBContextImpl context, ClassBeanInfoImpl beanInfo, Accessor<?,Map<QName,String>> attWildcard) {
   115         UnmarshallerChain chain = new UnmarshallerChain(context);
   116         for (ClassBeanInfoImpl bi = beanInfo; bi != null; bi = bi.superClazz) {
   117             for (int i = bi.properties.length - 1; i >= 0; i--) {
   118                 Property p = bi.properties[i];
   120                 switch(p.getKind()) {
   121                 case ATTRIBUTE:
   122                     if(attUnmarshallers==null)
   123                         attUnmarshallers = new QNameMap<TransducedAccessor>();
   124                     AttributeProperty ap = (AttributeProperty) p;
   125                     attUnmarshallers.put(ap.attName.toQName(),ap.xacc);
   126                     break;
   127                 case ELEMENT:
   128                 case REFERENCE:
   129                 case MAP:
   130                 case VALUE:
   131                     p.buildChildElementUnmarshallers(chain,childUnmarshallers);
   132                     break;
   133                 }
   134             }
   135         }
   137         this.frameSize = chain.getScopeSize();
   139         textHandler = childUnmarshallers.get(StructureLoaderBuilder.TEXT_HANDLER);
   140         catchAll = childUnmarshallers.get(StructureLoaderBuilder.CATCH_ALL);
   142         if(attWildcard!=null) {
   143             attCatchAll = (Accessor<Object,Map<QName,String>>) attWildcard;
   144             // we use attUnmarshallers==null as a sign to skip the attribute processing
   145             // altogether, so if we have an att wildcard we need to have an empty qname map.
   146             if(attUnmarshallers==null)
   147                 attUnmarshallers = EMPTY;
   148         } else {
   149             attCatchAll = null;
   150         }
   151     }
   153     @Override
   154     public void startElement(UnmarshallingContext.State state, TagName ea) throws SAXException {
   155         UnmarshallingContext context = state.getContext();
   157         // create the object to unmarshal
   158         Object child;
   159         assert !beanInfo.isImmutable();
   161         // let's see if we can reuse the existing peer object
   162         child = context.getInnerPeer();
   164         if(child != null && beanInfo.jaxbType!=child.getClass())
   165             child = null;   // unexpected type.
   167         if(child != null)
   168             beanInfo.reset(child,context);
   170         if(child == null)
   171             child = context.createInstance(beanInfo);
   173         context.recordInnerPeer(child);
   175         state.setTarget(child);
   177         fireBeforeUnmarshal(beanInfo, child, state);
   180         context.startScope(frameSize);
   182         if(attUnmarshallers!=null) {
   183             Attributes atts = ea.atts;
   184             for (int i = 0; i < atts.getLength(); i ++){
   185                 String auri = atts.getURI(i);
   186                 // may be empty string based on parser settings
   187                 String alocal = atts.getLocalName(i);
   188                 if ("".equals(alocal)) {
   189                     alocal = atts.getQName(i);
   190                 }
   191                 String avalue = atts.getValue(i);
   192                 TransducedAccessor xacc = attUnmarshallers.get(auri, alocal);
   193                 try {
   194                     if(xacc!=null) {
   195                         xacc.parse(child,avalue);
   196                     } else if (attCatchAll!=null) {
   197                         String qname = atts.getQName(i);
   198                         if(atts.getURI(i).equals(WellKnownNamespace.XML_SCHEMA_INSTANCE))
   199                             continue;   // xsi:* attributes are meant to be processed by us, not by user apps.
   200                         Object o = state.getTarget();
   201                         Map<QName,String> map = attCatchAll.get(o);
   202                         if(map==null) {
   203                             // TODO: use  ClassFactory.inferImplClass(sig,knownImplClasses)
   205                             // if null, create a new map.
   206                             if(attCatchAll.valueType.isAssignableFrom(HashMap.class))
   207                                 map = new HashMap<QName,String>();
   208                             else {
   209                                 // we don't know how to create a map for this.
   210                                 // report an error and back out
   211                                 context.handleError(Messages.UNABLE_TO_CREATE_MAP.format(attCatchAll.valueType));
   212                                 return;
   213                             }
   214                             attCatchAll.set(o,map);
   215                         }
   217                         String prefix;
   218                         int idx = qname.indexOf(':');
   219                         if(idx<0)   prefix="";
   220                         else        prefix=qname.substring(0,idx);
   222                         map.put(new QName(auri,alocal,prefix),avalue);
   223                     }
   224                 } catch (AccessorException e) {
   225                    handleGenericException(e,true);
   226                 }
   227             }
   228         }
   229     }
   231     @Override
   232     public void childElement(UnmarshallingContext.State state, TagName arg) throws SAXException {
   233         ChildLoader child = childUnmarshallers.get(arg.uri,arg.local);
   234         if(child==null) {
   235             if ((beanInfo != null) && (beanInfo.getTypeNames() != null)) {
   236                 Iterator typeNamesIt = beanInfo.getTypeNames().iterator();
   237                 QName parentQName = null;
   238                 if ((typeNamesIt != null) && (typeNamesIt.hasNext()) && (catchAll == null)) {
   239                     parentQName = (QName) typeNamesIt.next();
   240                     String parentUri = parentQName.getNamespaceURI();
   241                     child = childUnmarshallers.get(parentUri, arg.local);
   242                 }
   243             }
   244             if (child == null) {
   245                 child = catchAll;
   246                 if(child==null) {
   247                     super.childElement(state,arg);
   248                     return;
   249                 }
   250             }
   251         }
   253         state.setLoader(child.loader);
   254         state.setReceiver(child.receiver);
   255     }
   257     @Override
   258     public Collection<QName> getExpectedChildElements() {
   259         return childUnmarshallers.keySet();
   260     }
   262     @Override
   263     public Collection<QName> getExpectedAttributes() {
   264         return attUnmarshallers.keySet();
   265     }
   267     @Override
   268     public void text(UnmarshallingContext.State state, CharSequence text) throws SAXException {
   269         if(textHandler!=null)
   270             textHandler.loader.text(state,text);
   271     }
   273     @Override
   274     public void leaveElement(UnmarshallingContext.State state, TagName ea) throws SAXException {
   275         state.getContext().endScope(frameSize);
   276         fireAfterUnmarshal(beanInfo, state.getTarget(), state.getPrev());
   277     }
   279     private static final QNameMap<TransducedAccessor> EMPTY = new QNameMap<TransducedAccessor>();
   281     public JaxBeanInfo getBeanInfo() {
   282         return beanInfo;
   283     }
   284 }

mercurial