src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/Lister.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, 2013, 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.reflect;
    28 import java.lang.ref.WeakReference;
    29 import java.lang.reflect.Array;
    30 import java.lang.reflect.ParameterizedType;
    31 import java.lang.reflect.Type;
    32 import java.util.ArrayList;
    33 import java.util.Collection;
    34 import java.util.Collections;
    35 import java.util.HashMap;
    36 import java.util.Iterator;
    37 import java.util.List;
    38 import java.util.Map;
    39 import java.util.WeakHashMap;
    40 import java.util.LinkedList;
    41 import java.util.HashSet;
    42 import java.util.TreeSet;
    43 import java.util.Stack;
    44 import java.util.concurrent.Callable;
    46 import javax.xml.bind.JAXBException;
    48 import com.sun.istack.internal.SAXException2;
    49 import com.sun.xml.internal.bind.api.AccessorException;
    50 import com.sun.xml.internal.bind.v2.ClassFactory;
    51 import com.sun.xml.internal.bind.v2.TODO;
    52 import com.sun.xml.internal.bind.v2.model.core.Adapter;
    53 import com.sun.xml.internal.bind.v2.model.core.ID;
    54 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer;
    55 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Patcher;
    56 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
    57 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.LocatorEx;
    59 import org.xml.sax.SAXException;
    61 /**
    62  * Used to list individual values of a multi-value property, and
    63  * to pack individual values into a multi-value property.
    64  *
    65  * @author Kohsuke Kawaguchi (kk@kohsuke.org)
    66  */
    67 public abstract class Lister<BeanT,PropT,ItemT,PackT> {
    69     protected Lister() {}
    71     /**
    72      * Iterates values of a multi-value property.
    73      *
    74      * @param context
    75      *      This parameter is used to support ID/IDREF handling.
    76      */
    77     public abstract ListIterator<ItemT> iterator(PropT multiValueProp, XMLSerializer context);
    79     /**
    80      * Setting values to a multi-value property starts by creating
    81      * a transient object called "pack" from the current field.
    82      */
    83     public abstract PackT startPacking(BeanT bean, Accessor<BeanT, PropT> acc) throws AccessorException;
    85     /**
    86      * Once the {@link #startPacking} is called, you can
    87      * add values to the pack by using this method.
    88      */
    89     public abstract void addToPack( PackT pack, ItemT newValue ) throws AccessorException;
    91     /**
    92      * Finally, call this method to
    93      * wraps up the {@code pack}. This method may update the field of
    94      * the given bean.
    95      */
    96     public abstract void endPacking( PackT pack, BeanT bean, Accessor<BeanT,PropT> acc ) throws AccessorException;
    98     /**
    99      * Clears the values of the property.
   100      */
   101     public abstract void reset(BeanT o,Accessor<BeanT,PropT> acc) throws AccessorException;
   104     /**
   105      * Gets a reference to the appropriate {@link Lister} object
   106      * if the field is a multi-value field. Otherwise null.
   107      *
   108      * @param fieldType
   109      *      the type of the field that stores the collection
   110      * @param idness
   111      *      ID-ness of the property.
   112      * @param adapter
   113      *      adapter to be used for individual items. can be null.
   114      */
   115     public static <BeanT,PropT,ItemT,PackT>
   116         Lister<BeanT,PropT,ItemT,PackT> create(Type fieldType,ID idness, Adapter<Type,Class> adapter) {
   118         Class rawType = (Class) Utils.REFLECTION_NAVIGATOR.erasure(fieldType);
   119         Class itemType;
   121         Lister l;
   122         if( rawType.isArray() ) {
   123             itemType = rawType.getComponentType();
   124             l = getArrayLister(itemType);
   125         } else
   126         if( Collection.class.isAssignableFrom(rawType) ) {
   127             Type bt = Utils.REFLECTION_NAVIGATOR.getBaseClass(fieldType,Collection.class);
   128             if(bt instanceof ParameterizedType)
   129                 itemType = (Class) Utils.REFLECTION_NAVIGATOR.erasure(((ParameterizedType)bt).getActualTypeArguments()[0]);
   130             else
   131                 itemType = Object.class;
   132             l = new CollectionLister(getImplClass(rawType));
   133         } else
   134             return null;
   136         if(idness==ID.IDREF)
   137             l = new IDREFS(l,itemType);
   139         if(adapter!=null)
   140             l = new AdaptedLister(l,adapter.adapterType);
   142         return l;
   143     }
   145     private static Class getImplClass(Class<?> fieldType) {
   146         return ClassFactory.inferImplClass(fieldType,COLLECTION_IMPL_CLASSES);
   147     }
   149     /**
   150      * Cache instances of {@link ArrayLister}s.
   151      */
   152     private static final Map<Class,WeakReference<Lister>> arrayListerCache =
   153         Collections.synchronizedMap(new WeakHashMap<Class,WeakReference<Lister>>());
   155     /**
   156      * Creates a lister for array type.
   157      */
   158     private static Lister getArrayLister( Class componentType ) {
   159         Lister l=null;
   160         if(componentType.isPrimitive())
   161             l = primitiveArrayListers.get(componentType);
   162         else {
   163             WeakReference<Lister> wr = arrayListerCache.get(componentType);
   164             if(wr!=null)
   165                 l = wr.get();
   166             if(l==null) {
   167                 l = new ArrayLister(componentType);
   168                 arrayListerCache.put(componentType,new WeakReference<Lister>(l));
   169             }
   170         }
   171         assert l!=null;
   172         return l;
   173     }
   175     /**
   176      * {@link Lister} for an array.
   177      *
   178      * <p>
   179      * Array packing is slower, but we expect this to be used less frequently than
   180      * the {@link CollectionLister}.
   181      */
   182     private static final class ArrayLister<BeanT,ItemT> extends Lister<BeanT,ItemT[],ItemT,Pack<ItemT>> {
   184         private final Class<ItemT> itemType;
   186         public ArrayLister(Class<ItemT> itemType) {
   187             this.itemType = itemType;
   188         }
   190         public ListIterator<ItemT> iterator(final ItemT[] objects, XMLSerializer context) {
   191             return new ListIterator<ItemT>() {
   192                 int idx=0;
   193                 public boolean hasNext() {
   194                     return idx<objects.length;
   195                 }
   197                 public ItemT next() {
   198                     return objects[idx++];
   199                 }
   200             };
   201         }
   203         public Pack startPacking(BeanT current, Accessor<BeanT, ItemT[]> acc) {
   204             return new Pack<ItemT>(itemType);
   205         }
   207         public void addToPack(Pack<ItemT> objects, ItemT o) {
   208             objects.add(o);
   209         }
   211         public void endPacking( Pack<ItemT> pack, BeanT bean, Accessor<BeanT,ItemT[]> acc ) throws AccessorException {
   212             acc.set(bean,pack.build());
   213         }
   215         public void reset(BeanT o,Accessor<BeanT,ItemT[]> acc) throws AccessorException {
   216             acc.set(o,(ItemT[])Array.newInstance(itemType,0));
   217         }
   219     }
   221     public static final class Pack<ItemT> extends ArrayList<ItemT> {
   222         private final Class<ItemT> itemType;
   224         public Pack(Class<ItemT> itemType) {
   225             this.itemType = itemType;
   226         }
   228         public ItemT[] build() {
   229             return super.toArray( (ItemT[])Array.newInstance(itemType,size()) );
   230         }
   231     }
   233     /**
   234      * Listers for the primitive type arrays, keyed by their primitive Class object.
   235      */
   236     /*package*/ static final Map<Class,Lister> primitiveArrayListers = new HashMap<Class,Lister>();
   238     static {
   239         // register primitive array listers
   240         PrimitiveArrayListerBoolean.register();
   241         PrimitiveArrayListerByte.register();
   242         PrimitiveArrayListerCharacter.register();
   243         PrimitiveArrayListerDouble.register();
   244         PrimitiveArrayListerFloat.register();
   245         PrimitiveArrayListerInteger.register();
   246         PrimitiveArrayListerLong.register();
   247         PrimitiveArrayListerShort.register();
   248     }
   250     /**
   251      * {@link Lister} for a collection
   252      */
   253     public static final class CollectionLister<BeanT,T extends Collection> extends Lister<BeanT,T,Object,T> {
   255         /**
   256          * Sometimes we need to create a new instance of a collection.
   257          * This is such an implementation class.
   258          */
   259         private final Class<? extends T> implClass;
   261         public CollectionLister(Class<? extends T> implClass) {
   262             this.implClass = implClass;
   263         }
   265         public ListIterator iterator(T collection, XMLSerializer context) {
   266             final Iterator itr = collection.iterator();
   267             return new ListIterator() {
   268                 public boolean hasNext() {
   269                     return itr.hasNext();
   270                 }
   271                 public Object next() {
   272                     return itr.next();
   273                 }
   274             };
   275         }
   277         public T startPacking(BeanT bean, Accessor<BeanT, T> acc) throws AccessorException {
   278             T collection = acc.get(bean);
   279             if(collection==null) {
   280                 collection = ClassFactory.create(implClass);
   281                 if(!acc.isAdapted())
   282                     acc.set(bean,collection);
   283             }
   284             collection.clear();
   285             return collection;
   286         }
   288         public void addToPack(T collection, Object o) {
   289             collection.add(o);
   290         }
   292         public void endPacking( T collection, BeanT bean, Accessor<BeanT,T> acc ) throws AccessorException {
   293             // this needs to be done in the endPacking, because
   294             // sometimes the accessor uses an adapter, and the adapter needs to see
   295             // the whole thing.
   297             // but always doing so causes a problem when this collection property
   298             // is getter-only
   300             // invoke set when possible (see Issue 488)
   301             try {
   302                 if (acc.isAdapted()) {
   303                     acc.set(bean,collection);
   304                 }
   305             } catch (AccessorException ae) {
   306                 if(acc.isAdapted()) throw ae;
   307             }
   308         }
   310         public void reset(BeanT bean, Accessor<BeanT, T> acc) throws AccessorException {
   311             T collection = acc.get(bean);
   312             if(collection == null) {
   313                 return;
   314             }
   315             collection.clear();
   316         }
   317     }
   319     /**
   320      * {@link Lister} for IDREFS.
   321      */
   322     private static final class IDREFS<BeanT,PropT> extends Lister<BeanT,PropT,String,IDREFS<BeanT,PropT>.Pack> {
   323         private final Lister<BeanT,PropT,Object,Object> core;
   324         /**
   325          * Expected type to which IDREF resolves to.
   326          */
   327         private final Class itemType;
   329         public IDREFS(Lister core, Class itemType) {
   330             this.core = core;
   331             this.itemType = itemType;
   332         }
   334         public ListIterator<String> iterator(PropT prop, XMLSerializer context) {
   335             final ListIterator i = core.iterator(prop,context);
   337             return new IDREFSIterator(i, context);
   338         }
   340         public Pack startPacking(BeanT bean, Accessor<BeanT, PropT> acc) {
   341             return new Pack(bean,acc);
   342         }
   344         public void addToPack(Pack pack, String item) {
   345             pack.add(item);
   346         }
   348         public void endPacking(Pack pack, BeanT bean, Accessor<BeanT, PropT> acc) {
   349         }
   351         public void reset(BeanT bean, Accessor<BeanT, PropT> acc) throws AccessorException {
   352             core.reset(bean,acc);
   353         }
   355         /**
   356          * PackT for this lister.
   357          */
   358         private class Pack implements Patcher {
   359             private final BeanT bean;
   360             private final List<String> idrefs = new ArrayList<String>();
   361             private final UnmarshallingContext context;
   362             private final Accessor<BeanT,PropT> acc;
   363             private final LocatorEx location;
   365             public Pack(BeanT bean, Accessor<BeanT,PropT> acc) {
   366                 this.bean = bean;
   367                 this.acc = acc;
   368                 this.context = UnmarshallingContext.getInstance();
   369                 this.location = new LocatorEx.Snapshot(context.getLocator());
   370                 context.addPatcher(this);
   371             }
   373             public void add(String item) {
   374                 idrefs.add(item);
   375             }
   377             /**
   378              * Resolves IDREFS and fill in the actual array.
   379              */
   380             public void run() throws SAXException {
   381                 try {
   382                     Object pack = core.startPacking(bean,acc);
   384                     for( String id : idrefs ) {
   385                         Callable callable = context.getObjectFromId(id,itemType);
   386                         Object t;
   388                         try {
   389                             t = (callable!=null) ? callable.call() : null;
   390                         } catch (SAXException e) {
   391                             throw e;
   392                         } catch (Exception e) {
   393                             throw new SAXException2(e);
   394                         }
   396                         if(t==null) {
   397                             context.errorUnresolvedIDREF(bean,id,location);
   398                         } else {
   399                             TODO.prototype(); // TODO: check if the type of t is proper.
   400                             core.addToPack(pack,t);
   401                         }
   402                     }
   404                     core.endPacking(pack,bean,acc);
   405                 } catch (AccessorException e) {
   406                     context.handleError(e);
   407                 }
   408             }
   409         }
   410     }
   412     /**
   413      * {@link Iterator} for IDREFS lister.
   414      *
   415      * <p>
   416      * Only in ArrayElementProperty we need to get the actual
   417      * referenced object. This is a kind of ugly way to make that work.
   418      */
   419     public static final class IDREFSIterator implements ListIterator<String> {
   420         private final ListIterator i;
   421         private final XMLSerializer context;
   422         private Object last;
   424         private IDREFSIterator(ListIterator i, XMLSerializer context) {
   425             this.i = i;
   426             this.context = context;
   427         }
   429         public boolean hasNext() {
   430             return i.hasNext();
   431         }
   433         /**
   434          * Returns the last referenced object (not just its ID)
   435          */
   436         public Object last() {
   437             return last;
   438         }
   440         public String next() throws SAXException, JAXBException {
   441             last = i.next();
   442             String id = context.grammar.getBeanInfo(last,true).getId(last,context);
   443             if(id==null) {
   444                 context.errorMissingId(last);
   445             }
   446             return id;
   447         }
   448     }
   450     /**
   451      * Gets the special {@link Lister} used to recover from an error.
   452      */
   453     @SuppressWarnings("unchecked")
   454     public static <A,B,C,D> Lister<A,B,C,D> getErrorInstance() {
   455         return ERROR;
   456     }
   458     public static final Lister ERROR = new Lister() {
   459         public ListIterator iterator(Object o, XMLSerializer context) {
   460             return EMPTY_ITERATOR;
   461         }
   463         public Object startPacking(Object o, Accessor accessor) {
   464             return null;
   465         }
   467         public void addToPack(Object o, Object o1) {
   468         }
   470         public void endPacking(Object o, Object o1, Accessor accessor) {
   471         }
   473         public void reset(Object o, Accessor accessor) {
   474         }
   475     };
   477     private static final ListIterator EMPTY_ITERATOR = new ListIterator() {
   478         public boolean hasNext() {
   479             return false;
   480         }
   482         public Object next() {
   483             throw new IllegalStateException();
   484         }
   485     };
   487     private static final Class[] COLLECTION_IMPL_CLASSES = new Class[] {
   488         ArrayList.class,
   489         LinkedList.class,
   490         HashSet.class,
   491         TreeSet.class,
   492         Stack.class
   493     };
   494 }

mercurial