src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeClassInfoImpl.java

Thu, 12 Oct 2017 19:44:07 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:44:07 +0800
changeset 760
e530533619ec
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 2010, 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.model.impl;
    28 import java.io.IOException;
    29 import java.lang.annotation.Annotation;
    30 import java.lang.reflect.Field;
    31 import java.lang.reflect.Method;
    32 import java.lang.reflect.Modifier;
    33 import java.lang.reflect.Type;
    34 import java.util.List;
    35 import java.util.Map;
    37 import javax.xml.bind.JAXBException;
    38 import javax.xml.namespace.QName;
    39 import javax.xml.stream.XMLStreamException;
    41 import com.sun.istack.internal.NotNull;
    42 import com.sun.xml.internal.bind.AccessorFactory;
    43 import com.sun.xml.internal.bind.AccessorFactoryImpl;
    44 import com.sun.xml.internal.bind.InternalAccessorFactory;
    45 import com.sun.xml.internal.bind.XmlAccessorFactory;
    46 import com.sun.xml.internal.bind.annotation.XmlLocation;
    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.model.annotation.Locatable;
    50 import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
    51 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeClassInfo;
    52 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeElement;
    53 import com.sun.xml.internal.bind.v2.model.runtime.RuntimePropertyInfo;
    54 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeValuePropertyInfo;
    55 import com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationException;
    56 import com.sun.xml.internal.bind.v2.runtime.Location;
    57 import com.sun.xml.internal.bind.v2.runtime.Name;
    58 import com.sun.xml.internal.bind.v2.runtime.Transducer;
    59 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer;
    60 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
    61 import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor;
    62 import com.sun.xml.internal.bind.v2.runtime.reflect.TransducedAccessor;
    63 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
    65 import org.xml.sax.Locator;
    66 import org.xml.sax.SAXException;
    68 /**
    69  * @author Kohsuke Kawaguchi (kk@kohsuke.org)
    70  */
    71 class RuntimeClassInfoImpl extends ClassInfoImpl<Type,Class,Field,Method>
    72         implements RuntimeClassInfo, RuntimeElement {
    74     /**
    75      * If this class has a property annotated with {@link XmlLocation},
    76      * this field will get the accessor for it.
    77      *
    78      * TODO: support method based XmlLocation
    79      */
    80     private Accessor<?,Locator> xmlLocationAccessor;
    82     private AccessorFactory accessorFactory;
    84     private boolean supressAccessorWarnings = false;
    86     public RuntimeClassInfoImpl(RuntimeModelBuilder modelBuilder, Locatable upstream, Class clazz) {
    87         super(modelBuilder, upstream, clazz);
    88         accessorFactory = createAccessorFactory(clazz);
    89     }
    91     protected AccessorFactory createAccessorFactory(Class clazz) {
    92         XmlAccessorFactory factoryAnn;
    93         AccessorFactory accFactory = null;
    95         // user providing class to be used.
    96         JAXBContextImpl context = ((RuntimeModelBuilder) builder).context;
    97         if (context!=null) {
    98             this.supressAccessorWarnings = context.supressAccessorWarnings;
    99             if (context.xmlAccessorFactorySupport) {
   100                 factoryAnn = findXmlAccessorFactoryAnnotation(clazz);
   101                 if (factoryAnn != null) {
   102                     try {
   103                         accFactory = factoryAnn.value().newInstance();
   104                     } catch (InstantiationException e) {
   105                         builder.reportError(new IllegalAnnotationException(
   106                                 Messages.ACCESSORFACTORY_INSTANTIATION_EXCEPTION.format(
   107                                 factoryAnn.getClass().getName(), nav().getClassName(clazz)), this));
   108                     } catch (IllegalAccessException e) {
   109                         builder.reportError(new IllegalAnnotationException(
   110                                 Messages.ACCESSORFACTORY_ACCESS_EXCEPTION.format(
   111                                 factoryAnn.getClass().getName(), nav().getClassName(clazz)),this));
   112                     }
   113                 }
   114             }
   115         }
   118         // Fall back to local AccessorFactory when no
   119         // user not providing one or as error recovery.
   120         if (accFactory == null){
   121             accFactory = AccessorFactoryImpl.getInstance();
   122         }
   123         return accFactory;
   124     }
   126     protected XmlAccessorFactory findXmlAccessorFactoryAnnotation(Class clazz) {
   127         XmlAccessorFactory factoryAnn = reader().getClassAnnotation(XmlAccessorFactory.class,clazz,this);
   128         if (factoryAnn == null) {
   129             factoryAnn = reader().getPackageAnnotation(XmlAccessorFactory.class,clazz,this);
   130         }
   131         return factoryAnn;
   132     }
   135     public Method getFactoryMethod(){
   136         return super.getFactoryMethod();
   137     }
   139     public final RuntimeClassInfoImpl getBaseClass() {
   140         return (RuntimeClassInfoImpl)super.getBaseClass();
   141     }
   143     @Override
   144     protected ReferencePropertyInfoImpl createReferenceProperty(PropertySeed<Type,Class,Field,Method> seed) {
   145         return new RuntimeReferencePropertyInfoImpl(this,seed);
   146     }
   148     @Override
   149     protected AttributePropertyInfoImpl createAttributeProperty(PropertySeed<Type,Class,Field,Method> seed) {
   150         return new RuntimeAttributePropertyInfoImpl(this,seed);
   151     }
   153     @Override
   154     protected ValuePropertyInfoImpl createValueProperty(PropertySeed<Type,Class,Field,Method> seed) {
   155         return new RuntimeValuePropertyInfoImpl(this,seed);
   156     }
   158     @Override
   159     protected ElementPropertyInfoImpl createElementProperty(PropertySeed<Type,Class,Field,Method> seed) {
   160         return new RuntimeElementPropertyInfoImpl(this,seed);
   161     }
   163     @Override
   164     protected MapPropertyInfoImpl createMapProperty(PropertySeed<Type,Class,Field,Method> seed) {
   165         return new RuntimeMapPropertyInfoImpl(this,seed);
   166     }
   169     @Override
   170     public List<? extends RuntimePropertyInfo> getProperties() {
   171         return (List<? extends RuntimePropertyInfo>)super.getProperties();
   172     }
   174     @Override
   175     public RuntimePropertyInfo getProperty(String name) {
   176         return (RuntimePropertyInfo)super.getProperty(name);
   177     }
   180     public void link() {
   181         getTransducer();    // populate the transducer
   182         super.link();
   183     }
   185     private Accessor<?,Map<QName,String>> attributeWildcardAccessor;
   187     public <B> Accessor<B,Map<QName,String>> getAttributeWildcard() {
   188         for( RuntimeClassInfoImpl c=this; c!=null; c=c.getBaseClass() ) {
   189             if(c.attributeWildcard!=null) {
   190                 if(c.attributeWildcardAccessor==null)
   191                     c.attributeWildcardAccessor = c.createAttributeWildcardAccessor();
   192                 return (Accessor<B,Map<QName,String>>)c.attributeWildcardAccessor;
   193             }
   194         }
   195         return null;
   196     }
   198     private boolean computedTransducer = false;
   199     private Transducer xducer = null;
   201     public Transducer getTransducer() {
   202         if(!computedTransducer) {
   203             computedTransducer = true;
   204             xducer = calcTransducer();
   205         }
   206         return xducer;
   207     }
   209     /**
   210      * Creates a transducer if this class is bound to a text in XML.
   211      */
   212     private Transducer calcTransducer() {
   213         RuntimeValuePropertyInfo valuep=null;
   214         if(hasAttributeWildcard())
   215             return null;        // has attribute wildcard. Can't be handled as a leaf
   216         for (RuntimeClassInfoImpl ci = this; ci != null; ci = ci.getBaseClass()) {
   217             for( RuntimePropertyInfo pi : ci.getProperties() )
   218                 if(pi.kind()==PropertyKind.VALUE) {
   219                     valuep = (RuntimeValuePropertyInfo)pi;
   220                 } else {
   221                     // this bean has something other than a value
   222                     return null;
   223                 }
   224         }
   225         if(valuep==null)
   226             return null;
   227         if( !valuep.getTarget().isSimpleType() )
   228             return null;    // if there's an error, recover from it by returning null.
   230         return new TransducerImpl(getClazz(),TransducedAccessor.get(
   231                 ((RuntimeModelBuilder)builder).context,valuep));
   232     }
   234     /**
   235      * Creates
   236      */
   237     private Accessor<?,Map<QName,String>> createAttributeWildcardAccessor() {
   238         assert attributeWildcard!=null;
   239         return ((RuntimePropertySeed)attributeWildcard).getAccessor();
   240     }
   242     @Override
   243     protected RuntimePropertySeed createFieldSeed(Field field) {
   244        final boolean readOnly = Modifier.isStatic(field.getModifiers());
   245         Accessor acc;
   246         try {
   247             if (supressAccessorWarnings) {
   248                 acc = ((InternalAccessorFactory)accessorFactory).createFieldAccessor(clazz, field, readOnly, supressAccessorWarnings);
   249             } else {
   250                 acc = accessorFactory.createFieldAccessor(clazz, field, readOnly);
   251             }
   252         } catch(JAXBException e) {
   253             builder.reportError(new IllegalAnnotationException(
   254                     Messages.CUSTOM_ACCESSORFACTORY_FIELD_ERROR.format(
   255                     nav().getClassName(clazz), e.toString()), this ));
   256             acc = Accessor.getErrorInstance(); // error recovery
   257         }
   258         return new RuntimePropertySeed(super.createFieldSeed(field), acc );
   259     }
   261     @Override
   262     public RuntimePropertySeed createAccessorSeed(Method getter, Method setter) {
   263         Accessor acc;
   264         try {
   265             acc = accessorFactory.createPropertyAccessor(clazz, getter, setter);
   266         } catch(JAXBException e) {
   267             builder.reportError(new IllegalAnnotationException(
   268                 Messages.CUSTOM_ACCESSORFACTORY_PROPERTY_ERROR.format(
   269                 nav().getClassName(clazz), e.toString()), this ));
   270             acc = Accessor.getErrorInstance(); // error recovery
   271         }
   272         return new RuntimePropertySeed( super.createAccessorSeed(getter,setter),
   273           acc );
   274     }
   276     @Override
   277     protected void checkFieldXmlLocation(Field f) {
   278         if(reader().hasFieldAnnotation(XmlLocation.class,f))
   279             // TODO: check for XmlLocation signature
   280             // TODO: check a collision with the super class
   281             xmlLocationAccessor = new Accessor.FieldReflection<Object,Locator>(f);
   282     }
   284     public Accessor<?,Locator> getLocatorField() {
   285         return xmlLocationAccessor;
   286     }
   288     static final class RuntimePropertySeed implements PropertySeed<Type,Class,Field,Method> {
   289         /**
   290          * @see #getAccessor()
   291          */
   292         private final Accessor acc;
   294         private final PropertySeed<Type,Class,Field,Method> core;
   296         public RuntimePropertySeed(PropertySeed<Type,Class,Field,Method> core, Accessor acc) {
   297             this.core = core;
   298             this.acc = acc;
   299         }
   301         public String getName() {
   302             return core.getName();
   303         }
   305         public <A extends Annotation> A readAnnotation(Class<A> annotationType) {
   306             return core.readAnnotation(annotationType);
   307         }
   309         public boolean hasAnnotation(Class<? extends Annotation> annotationType) {
   310             return core.hasAnnotation(annotationType);
   311         }
   313         public Type getRawType() {
   314             return core.getRawType();
   315         }
   317         public Location getLocation() {
   318             return core.getLocation();
   319         }
   321         public Locatable getUpstream() {
   322             return core.getUpstream();
   323         }
   325         public Accessor getAccessor() {
   326             return acc;
   327         }
   328     }
   332     /**
   333      * {@link Transducer} implementation used when this class maps to PCDATA in XML.
   334      *
   335      * TODO: revisit the exception handling
   336      */
   337     private static final class TransducerImpl<BeanT> implements Transducer<BeanT> {
   338         private final TransducedAccessor<BeanT> xacc;
   339         private final Class<BeanT> ownerClass;
   341         public TransducerImpl(Class<BeanT> ownerClass,TransducedAccessor<BeanT> xacc) {
   342             this.xacc = xacc;
   343             this.ownerClass = ownerClass;
   344         }
   346         public boolean useNamespace() {
   347             return xacc.useNamespace();
   348         }
   350         public boolean isDefault() {
   351             return false;
   352         }
   354         public void declareNamespace(BeanT bean, XMLSerializer w) throws AccessorException {
   355             try {
   356                 xacc.declareNamespace(bean,w);
   357             } catch (SAXException e) {
   358                 throw new AccessorException(e);
   359             }
   360         }
   362         public @NotNull CharSequence print(BeanT o) throws AccessorException {
   363             try {
   364                 CharSequence value = xacc.print(o);
   365                 if(value==null)
   366                     throw new AccessorException(Messages.THERE_MUST_BE_VALUE_IN_XMLVALUE.format(o));
   367                 return value;
   368             } catch (SAXException e) {
   369                 throw new AccessorException(e);
   370             }
   371         }
   373         public BeanT parse(CharSequence lexical) throws AccessorException, SAXException {
   374             UnmarshallingContext ctxt = UnmarshallingContext.getInstance();
   375             BeanT inst;
   376             if(ctxt!=null)
   377                 inst = (BeanT)ctxt.createInstance(ownerClass);
   378             else
   379                 // when this runs for parsing enum constants,
   380                 // there's no UnmarshallingContext.
   381                 inst = ClassFactory.create(ownerClass);
   383             xacc.parse(inst,lexical);
   384             return inst;
   385         }
   387         public void writeText(XMLSerializer w, BeanT o, String fieldName) throws IOException, SAXException, XMLStreamException, AccessorException {
   388             if(!xacc.hasValue(o))
   389                 throw new AccessorException(Messages.THERE_MUST_BE_VALUE_IN_XMLVALUE.format(o));
   390             xacc.writeText(w,o,fieldName);
   391         }
   393         public void writeLeafElement(XMLSerializer w, Name tagName, BeanT o, String fieldName) throws IOException, SAXException, XMLStreamException, AccessorException {
   394             if(!xacc.hasValue(o))
   395                 throw new AccessorException(Messages.THERE_MUST_BE_VALUE_IN_XMLVALUE.format(o));
   396             xacc.writeLeafElement(w,tagName,o,fieldName);
   397         }
   399         public QName getTypeName(BeanT instance) {
   400             return null;
   401         }
   402     }
   403 }

mercurial