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

Fri, 04 Oct 2013 16:21:34 +0100

author
mkos
date
Fri, 04 Oct 2013 16:21:34 +0100
changeset 408
b0610cd08440
parent 368
0989ad8c0860
child 450
b0c2840e2513
permissions
-rw-r--r--

8025054: Update JAX-WS RI integration to 2.2.9-b130926.1035
Reviewed-by: chegar

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

mercurial