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

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 450
b0c2840e2513
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 2012, 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;
    28 import java.io.IOException;
    29 import java.lang.reflect.InvocationTargetException;
    30 import java.lang.reflect.Method;
    31 import java.lang.reflect.Modifier;
    32 import java.util.Collection;
    33 import java.util.Collections;
    34 import java.util.List;
    35 import java.util.Map;
    36 import java.util.logging.Level;
    37 import java.util.logging.Logger;
    39 import javax.xml.bind.ValidationEvent;
    40 import javax.xml.bind.annotation.XmlRootElement;
    41 import javax.xml.bind.helpers.ValidationEventImpl;
    42 import javax.xml.namespace.QName;
    43 import javax.xml.stream.XMLStreamException;
    45 import com.sun.istack.internal.FinalArrayList;
    46 import com.sun.xml.internal.bind.Util;
    47 import com.sun.xml.internal.bind.api.AccessorException;
    48 import com.sun.xml.internal.bind.v2.ClassFactory;
    49 import com.sun.xml.internal.bind.v2.WellKnownNamespace;
    50 import com.sun.xml.internal.bind.v2.model.core.ID;
    51 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeClassInfo;
    52 import com.sun.xml.internal.bind.v2.model.runtime.RuntimePropertyInfo;
    53 import com.sun.xml.internal.bind.v2.runtime.property.AttributeProperty;
    54 import com.sun.xml.internal.bind.v2.runtime.property.Property;
    55 import com.sun.xml.internal.bind.v2.runtime.property.PropertyFactory;
    56 import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor;
    57 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
    58 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.StructureLoader;
    59 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
    60 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiTypeLoader;
    62 import org.xml.sax.Locator;
    63 import org.xml.sax.SAXException;
    64 import org.xml.sax.helpers.LocatorImpl;
    66 /**
    67  * {@link JaxBeanInfo} implementation for j2s bean.
    68  *
    69  * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
    70  */
    71 public final class ClassBeanInfoImpl<BeanT> extends JaxBeanInfo<BeanT> implements AttributeAccessor<BeanT> {
    73     /**
    74      * Properties of this bean class but not its ancestor classes.
    75      */
    76     public final Property<BeanT>[] properties;
    78     /**
    79      * Non-null if this bean has an ID property.
    80      */
    81     private Property<? super BeanT> idProperty;
    83     /**
    84      * Immutable configured loader for this class.
    85      *
    86      * <p>
    87      * Set from the link method, but considered final.
    88      */
    89     private Loader loader;
    90     private Loader loaderWithTypeSubst;
    92     /**
    93      * Set only until the link phase to avoid leaking memory.
    94      */
    95     private RuntimeClassInfo ci;
    97     private final Accessor<? super BeanT,Map<QName,String>> inheritedAttWildcard;
    98     private final Transducer<BeanT> xducer;
   100     /**
   101      * {@link ClassBeanInfoImpl} that represents the super class of {@link #jaxbType}.
   102      */
   103     public final ClassBeanInfoImpl<? super BeanT> superClazz;
   105     private final Accessor<? super BeanT,Locator> xmlLocatorField;
   107     private final Name tagName;
   109     private boolean retainPropertyInfo = false;
   111     /**
   112      * The {@link AttributeProperty}s for this type and all its ancestors.
   113      * If {@link JAXBContextImpl#c14nSupport} is true, this is sorted alphabetically.
   114      */
   115     private /*final*/ AttributeProperty<BeanT>[] attributeProperties;
   117     /**
   118      * {@link Property}s that need to receive {@link Property#serializeURIs(Object, XMLSerializer)} callback.
   119      */
   120     private /*final*/ Property<BeanT>[] uriProperties;
   122     private final Method factoryMethod;
   124     /*package*/ ClassBeanInfoImpl(JAXBContextImpl owner, RuntimeClassInfo ci) {
   125         super(owner,ci,ci.getClazz(),ci.getTypeName(),ci.isElement(),false,true);
   127         this.ci = ci;
   128         this.inheritedAttWildcard = ci.getAttributeWildcard();
   129         this.xducer = ci.getTransducer();
   130         this.factoryMethod = ci.getFactoryMethod();
   131         this.retainPropertyInfo = owner.retainPropertyInfo;
   133         // make the factory accessible
   134         if(factoryMethod!=null) {
   135             int classMod = factoryMethod.getDeclaringClass().getModifiers();
   137             if(!Modifier.isPublic(classMod) || !Modifier.isPublic(factoryMethod.getModifiers())) {
   138                 // attempt to make it work even if the constructor is not accessible
   139                 try {
   140                     factoryMethod.setAccessible(true);
   141                 } catch(SecurityException e) {
   142                     // but if we don't have a permission to do so, work gracefully.
   143                     logger.log(Level.FINE,"Unable to make the method of "+factoryMethod+" accessible",e);
   144                     throw e;
   145                 }
   146             }
   147         }
   150         if(ci.getBaseClass()==null)
   151             this.superClazz = null;
   152         else
   153             this.superClazz = owner.getOrCreate(ci.getBaseClass());
   155         if(superClazz!=null && superClazz.xmlLocatorField!=null)
   156             xmlLocatorField = superClazz.xmlLocatorField;
   157         else
   158             xmlLocatorField = ci.getLocatorField();
   160         // create property objects
   161         Collection<? extends RuntimePropertyInfo> ps = ci.getProperties();
   162         this.properties = new Property[ps.size()];
   163         int idx=0;
   164         boolean elementOnly = true;
   165         for( RuntimePropertyInfo info : ps ) {
   166             Property p = PropertyFactory.create(owner,info);
   167             if(info.id()==ID.ID)
   168                 idProperty = p;
   169             properties[idx++] = p;
   170             elementOnly &= info.elementOnlyContent();
   171             checkOverrideProperties(p);
   172         }
   173         // super class' idProperty might not be computed at this point,
   174         // so check that later
   176         hasElementOnlyContentModel( elementOnly );
   177         // again update this value later when we know that of the super class
   179         if(ci.isElement())
   180             tagName = owner.nameBuilder.createElementName(ci.getElementName());
   181         else
   182             tagName = null;
   184         setLifecycleFlags();
   185     }
   187     private void checkOverrideProperties(Property p) {
   188         ClassBeanInfoImpl bi = this;
   189         while ((bi = bi.superClazz) != null) {
   190             Property[] props = bi.properties;
   191             if (props == null) break;
   192             for (Property superProperty : props) {
   193                 if (superProperty != null) {
   194                     String spName = superProperty.getFieldName();
   195                     if ((spName != null) && (spName.equals(p.getFieldName()))) {
   196                         superProperty.setHiddenByOverride(true);
   197                     }
   198                 }
   199             }
   200         }
   201     }
   203     @Override
   204     protected void link(JAXBContextImpl grammar) {
   205         if(uriProperties!=null)
   206             return; // avoid linking twice
   208         super.link(grammar);
   210         if(superClazz!=null)
   211             superClazz.link(grammar);
   213         getLoader(grammar,true);    // make sure to build the loader if we haven't done so.
   215         // propagate values from super class
   216         if(superClazz!=null) {
   217             if(idProperty==null)
   218                 idProperty = superClazz.idProperty;
   220             if(!superClazz.hasElementOnlyContentModel())
   221                 hasElementOnlyContentModel(false);
   222         }
   224         // create a list of attribute/URI handlers
   225         List<AttributeProperty> attProps = new FinalArrayList<AttributeProperty>();
   226         List<Property> uriProps = new FinalArrayList<Property>();
   227         for (ClassBeanInfoImpl bi = this; bi != null; bi = bi.superClazz) {
   228             for (int i = 0; i < bi.properties.length; i++) {
   229                 Property p = bi.properties[i];
   230                 if(p instanceof AttributeProperty)
   231                     attProps.add((AttributeProperty) p);
   232                 if(p.hasSerializeURIAction())
   233                     uriProps.add(p);
   234             }
   235         }
   236         if(grammar.c14nSupport)
   237             Collections.sort(attProps);
   239         if(attProps.isEmpty())
   240             attributeProperties = EMPTY_PROPERTIES;
   241         else
   242             attributeProperties = attProps.toArray(new AttributeProperty[attProps.size()]);
   244         if(uriProps.isEmpty())
   245             uriProperties = EMPTY_PROPERTIES;
   246         else
   247             uriProperties = uriProps.toArray(new Property[uriProps.size()]);
   248     }
   250     @Override
   251     public void wrapUp() {
   252         for (Property p : properties)
   253             p.wrapUp();
   254         ci = null;
   255         super.wrapUp();
   256     }
   258     public String getElementNamespaceURI(BeanT bean) {
   259         return tagName.nsUri;
   260     }
   262     public String getElementLocalName(BeanT bean) {
   263         return tagName.localName;
   264     }
   266     public BeanT createInstance(UnmarshallingContext context) throws IllegalAccessException, InvocationTargetException, InstantiationException, SAXException {
   268         BeanT bean = null;
   269         if (factoryMethod == null){
   270            bean = ClassFactory.create0(jaxbType);
   271         }else {
   272             Object o = ClassFactory.create(factoryMethod);
   273             if( jaxbType.isInstance(o) ){
   274                 bean = (BeanT)o;
   275             } else {
   276                 throw new InstantiationException("The factory method didn't return a correct object");
   277             }
   278         }
   280         if(xmlLocatorField!=null)
   281             // need to copy because Locator is mutable
   282             try {
   283                 xmlLocatorField.set(bean,new LocatorImpl(context.getLocator()));
   284             } catch (AccessorException e) {
   285                 context.handleError(e);
   286             }
   287         return bean;
   288     }
   290     public boolean reset(BeanT bean, UnmarshallingContext context) throws SAXException {
   291         try {
   292             if(superClazz!=null)
   293                 superClazz.reset(bean,context);
   294             for( Property<BeanT> p : properties )
   295                 p.reset(bean);
   296             return true;
   297         } catch (AccessorException e) {
   298             context.handleError(e);
   299             return false;
   300         }
   301     }
   303     public String getId(BeanT bean, XMLSerializer target) throws SAXException {
   304         if(idProperty!=null) {
   305             try {
   306                 return idProperty.getIdValue(bean);
   307             } catch (AccessorException e) {
   308                 target.reportError(null,e);
   309             }
   310         }
   311         return null;
   312     }
   314     public void serializeRoot(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException {
   315         if(tagName==null) {
   316             Class beanClass = bean.getClass();
   317             String message;
   318             if (beanClass.isAnnotationPresent(XmlRootElement.class)) {
   319                 message = Messages.UNABLE_TO_MARSHAL_UNBOUND_CLASS.format(beanClass.getName());
   320             } else {
   321                 message = Messages.UNABLE_TO_MARSHAL_NON_ELEMENT.format(beanClass.getName());
   322             }
   323             target.reportError(new ValidationEventImpl(ValidationEvent.ERROR,message,null, null));
   324         } else {
   325             target.startElement(tagName,bean);
   326             target.childAsSoleContent(bean,null);
   327             target.endElement();
   328             if (retainPropertyInfo) {
   329                 target.currentProperty.remove();
   330             }
   331         }
   332     }
   334     public void serializeBody(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException {
   335         if (superClazz != null) {
   336             superClazz.serializeBody(bean, target);
   337         }
   338         try {
   339             for (Property<BeanT> p : properties) {
   340                 if (retainPropertyInfo) {
   341                     target.currentProperty.set(p);
   342                 }
   343                 boolean isThereAnOverridingProperty = p.isHiddenByOverride();
   344                 if (!isThereAnOverridingProperty || bean.getClass().equals(jaxbType)) {
   345                     p.serializeBody(bean, target, null);
   346                 } else if (isThereAnOverridingProperty) {
   347                     // need to double check the override - it should be safe to do after the model has been created because it's targeted to override properties only
   348                     Class beanClass = bean.getClass();
   349                     if (Utils.REFLECTION_NAVIGATOR.getDeclaredField(beanClass, p.getFieldName()) == null) {
   350                         p.serializeBody(bean, target, null);
   351                     }
   352                 }
   353             }
   354         } catch (AccessorException e) {
   355             target.reportError(null, e);
   356         }
   357     }
   359     public void serializeAttributes(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException {
   360         for( AttributeProperty<BeanT> p : attributeProperties )
   361             try {
   362                 if (retainPropertyInfo) {
   363                 final Property parentProperty = target.getCurrentProperty();
   364                 target.currentProperty.set(p);
   365                 p.serializeAttributes(bean,target);
   366                 target.currentProperty.set(parentProperty);
   367                 } else {
   368                     p.serializeAttributes(bean,target);
   369                 }
   370                 if (p.attName.equals(WellKnownNamespace.XML_SCHEMA_INSTANCE, "nil")) {
   371                     isNilIncluded = true;
   372                 }
   373             } catch (AccessorException e) {
   374                 target.reportError(null,e);
   375             }
   377         try {
   378             if(inheritedAttWildcard!=null) {
   379                 Map<QName,String> map = inheritedAttWildcard.get(bean);
   380                 target.attWildcardAsAttributes(map,null);
   381             }
   382         } catch (AccessorException e) {
   383             target.reportError(null,e);
   384         }
   385     }
   387     public void serializeURIs(BeanT bean, XMLSerializer target) throws SAXException {
   388         try {
   389             if (retainPropertyInfo) {
   390             final Property parentProperty = target.getCurrentProperty();
   391             for( Property<BeanT> p : uriProperties ) {
   392                 target.currentProperty.set(p);
   393                 p.serializeURIs(bean,target);
   394             }
   395             target.currentProperty.set(parentProperty);
   396             } else {
   397                 for( Property<BeanT> p : uriProperties ) {
   398                     p.serializeURIs(bean,target);
   399                 }
   400             }
   401             if(inheritedAttWildcard!=null) {
   402                 Map<QName,String> map = inheritedAttWildcard.get(bean);
   403                 target.attWildcardAsURIs(map,null);
   404             }
   405         } catch (AccessorException e) {
   406             target.reportError(null,e);
   407         }
   408     }
   410     public Loader getLoader(JAXBContextImpl context, boolean typeSubstitutionCapable) {
   411         if(loader==null) {
   412             // these variables have to be set before they are initialized,
   413             // because the initialization may build other loaders and they may refer to this.
   414             StructureLoader sl = new StructureLoader(this);
   415             loader = sl;
   416             if(ci.hasSubClasses())
   417                 loaderWithTypeSubst = new XsiTypeLoader(this);
   418             else
   419                 // optimization. we know there can be no @xsi:type
   420                 loaderWithTypeSubst = loader;
   423             sl.init(context,this,ci.getAttributeWildcard());
   424         }
   425         if(typeSubstitutionCapable)
   426             return loaderWithTypeSubst;
   427         else
   428             return loader;
   429     }
   431     public Transducer<BeanT> getTransducer() {
   432         return xducer;
   433     }
   435     private static final AttributeProperty[] EMPTY_PROPERTIES = new AttributeProperty[0];
   437     private static final Logger logger = Util.getClassLogger();
   439 }

mercurial