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

Tue, 09 Apr 2013 14:51:13 +0100

author
alanb
date
Tue, 09 Apr 2013 14:51:13 +0100
changeset 368
0989ad8c0860
parent 286
f50545b5e2f1
child 450
b0c2840e2513
permissions
-rw-r--r--

8010393: Update JAX-WS RI to 2.2.9-b12941
Reviewed-by: alanb, erikj
Contributed-by: miroslav.kos@oracle.com, martin.grebac@oracle.com

     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.model.nav.Navigator;
    55 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer;
    56 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Patcher;
    57 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
    58 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.LocatorEx;
    60 import org.xml.sax.SAXException;
    62 /**
    63  * Used to list individual values of a multi-value property, and
    64  * to pack individual values into a multi-value property.
    65  *
    66  * @author Kohsuke Kawaguchi (kk@kohsuke.org)
    67  */
    68 public abstract class Lister<BeanT,PropT,ItemT,PackT> {
    70     protected Lister() {}
    72     /**
    73      * Iterates values of a multi-value property.
    74      *
    75      * @param context
    76      *      This parameter is used to support ID/IDREF handling.
    77      */
    78     public abstract ListIterator<ItemT> iterator(PropT multiValueProp, XMLSerializer context);
    80     /**
    81      * Setting values to a multi-value property starts by creating
    82      * a transient object called "pack" from the current field.
    83      */
    84     public abstract PackT startPacking(BeanT bean, Accessor<BeanT, PropT> acc) throws AccessorException;
    86     /**
    87      * Once the {@link #startPacking} is called, you can
    88      * add values to the pack by using this method.
    89      */
    90     public abstract void addToPack( PackT pack, ItemT newValue ) throws AccessorException;
    92     /**
    93      * Finally, call this method to
    94      * wraps up the {@code pack}. This method may update the field of
    95      * the given bean.
    96      */
    97     public abstract void endPacking( PackT pack, BeanT bean, Accessor<BeanT,PropT> acc ) throws AccessorException;
    99     /**
   100      * Clears the values of the property.
   101      */
   102     public abstract void reset(BeanT o,Accessor<BeanT,PropT> acc) throws AccessorException;
   105     /**
   106      * Gets a reference to the appropriate {@link Lister} object
   107      * if the field is a multi-value field. Otherwise null.
   108      *
   109      * @param fieldType
   110      *      the type of the field that stores the collection
   111      * @param idness
   112      *      ID-ness of the property.
   113      * @param adapter
   114      *      adapter to be used for individual items. can be null.
   115      */
   116     public static <BeanT,PropT,ItemT,PackT>
   117         Lister<BeanT,PropT,ItemT,PackT> create(Type fieldType,ID idness, Adapter<Type,Class> adapter) {
   119         Class rawType = Navigator.REFLECTION.erasure(fieldType);
   120         Class itemType;
   122         Lister l;
   123         if( rawType.isArray() ) {
   124             itemType = rawType.getComponentType();
   125             l = getArrayLister(itemType);
   126         } else
   127         if( Collection.class.isAssignableFrom(rawType) ) {
   128             Type bt = Navigator.REFLECTION.getBaseClass(fieldType,Collection.class);
   129             if(bt instanceof ParameterizedType)
   130                 itemType = Navigator.REFLECTION.erasure(((ParameterizedType)bt).getActualTypeArguments()[0]);
   131             else
   132                 itemType = Object.class;
   133             l = new CollectionLister(getImplClass(rawType));
   134         } else
   135             return null;
   137         if(idness==ID.IDREF)
   138             l = new IDREFS(l,itemType);
   140         if(adapter!=null)
   141             l = new AdaptedLister(l,adapter.adapterType);
   143         return l;
   144     }
   146     private static Class getImplClass(Class<?> fieldType) {
   147         return ClassFactory.inferImplClass(fieldType,COLLECTION_IMPL_CLASSES);
   148     }
   150     /**
   151      * Cache instances of {@link ArrayLister}s.
   152      */
   153     private static final Map<Class,WeakReference<Lister>> arrayListerCache =
   154         Collections.synchronizedMap(new WeakHashMap<Class,WeakReference<Lister>>());
   156     /**
   157      * Creates a lister for array type.
   158      */
   159     private static Lister getArrayLister( Class componentType ) {
   160         Lister l=null;
   161         if(componentType.isPrimitive())
   162             l = primitiveArrayListers.get(componentType);
   163         else {
   164             WeakReference<Lister> wr = arrayListerCache.get(componentType);
   165             if(wr!=null)
   166                 l = wr.get();
   167             if(l==null) {
   168                 l = new ArrayLister(componentType);
   169                 arrayListerCache.put(componentType,new WeakReference<Lister>(l));
   170             }
   171         }
   172         assert l!=null;
   173         return l;
   174     }
   176     /**
   177      * {@link Lister} for an array.
   178      *
   179      * <p>
   180      * Array packing is slower, but we expect this to be used less frequently than
   181      * the {@link CollectionLister}.
   182      */
   183     private static final class ArrayLister<BeanT,ItemT> extends Lister<BeanT,ItemT[],ItemT,Pack<ItemT>> {
   185         private final Class<ItemT> itemType;
   187         public ArrayLister(Class<ItemT> itemType) {
   188             this.itemType = itemType;
   189         }
   191         public ListIterator<ItemT> iterator(final ItemT[] objects, XMLSerializer context) {
   192             return new ListIterator<ItemT>() {
   193                 int idx=0;
   194                 public boolean hasNext() {
   195                     return idx<objects.length;
   196                 }
   198                 public ItemT next() {
   199                     return objects[idx++];
   200                 }
   201             };
   202         }
   204         public Pack startPacking(BeanT current, Accessor<BeanT, ItemT[]> acc) {
   205             return new Pack<ItemT>(itemType);
   206         }
   208         public void addToPack(Pack<ItemT> objects, ItemT o) {
   209             objects.add(o);
   210         }
   212         public void endPacking( Pack<ItemT> pack, BeanT bean, Accessor<BeanT,ItemT[]> acc ) throws AccessorException {
   213             acc.set(bean,pack.build());
   214         }
   216         public void reset(BeanT o,Accessor<BeanT,ItemT[]> acc) throws AccessorException {
   217             acc.set(o,(ItemT[])Array.newInstance(itemType,0));
   218         }
   220     }
   222     public static final class Pack<ItemT> extends ArrayList<ItemT> {
   223         private final Class<ItemT> itemType;
   225         public Pack(Class<ItemT> itemType) {
   226             this.itemType = itemType;
   227         }
   229         public ItemT[] build() {
   230             return super.toArray( (ItemT[])Array.newInstance(itemType,size()) );
   231         }
   232     }
   234     /**
   235      * Listers for the primitive type arrays, keyed by their primitive Class object.
   236      */
   237     /*package*/ static final Map<Class,Lister> primitiveArrayListers = new HashMap<Class,Lister>();
   239     static {
   240         // register primitive array listers
   241         PrimitiveArrayListerBoolean.register();
   242         PrimitiveArrayListerByte.register();
   243         PrimitiveArrayListerCharacter.register();
   244         PrimitiveArrayListerDouble.register();
   245         PrimitiveArrayListerFloat.register();
   246         PrimitiveArrayListerInteger.register();
   247         PrimitiveArrayListerLong.register();
   248         PrimitiveArrayListerShort.register();
   249     }
   251     /**
   252      * {@link Lister} for a collection
   253      */
   254     public static final class CollectionLister<BeanT,T extends Collection> extends Lister<BeanT,T,Object,T> {
   256         /**
   257          * Sometimes we need to create a new instance of a collection.
   258          * This is such an implementation class.
   259          */
   260         private final Class<? extends T> implClass;
   262         public CollectionLister(Class<? extends T> implClass) {
   263             this.implClass = implClass;
   264         }
   266         public ListIterator iterator(T collection, XMLSerializer context) {
   267             final Iterator itr = collection.iterator();
   268             return new ListIterator() {
   269                 public boolean hasNext() {
   270                     return itr.hasNext();
   271                 }
   272                 public Object next() {
   273                     return itr.next();
   274                 }
   275             };
   276         }
   278         public T startPacking(BeanT bean, Accessor<BeanT, T> acc) throws AccessorException {
   279             T collection = acc.get(bean);
   280             if(collection==null) {
   281                 collection = ClassFactory.create(implClass);
   282                 if(!acc.isAdapted())
   283                     acc.set(bean,collection);
   284             }
   285             collection.clear();
   286             return collection;
   287         }
   289         public void addToPack(T collection, Object o) {
   290             collection.add(o);
   291         }
   293         public void endPacking( T collection, BeanT bean, Accessor<BeanT,T> acc ) throws AccessorException {
   294             // this needs to be done in the endPacking, because
   295             // sometimes the accessor uses an adapter, and the adapter needs to see
   296             // the whole thing.
   298             // but always doing so causes a problem when this collection property
   299             // is getter-only
   301             // invoke set when possible (see Issue 488)
   302             try {
   303                 if (acc.isAdapted()) {
   304                     acc.set(bean,collection);
   305                 }
   306             } catch (AccessorException ae) {
   307                 if(acc.isAdapted()) throw ae;
   308             }
   309         }
   311         public void reset(BeanT bean, Accessor<BeanT, T> acc) throws AccessorException {
   312             T collection = acc.get(bean);
   313             if(collection == null) {
   314                 return;
   315             }
   316             collection.clear();
   317         }
   318     }
   320     /**
   321      * {@link Lister} for IDREFS.
   322      */
   323     private static final class IDREFS<BeanT,PropT> extends Lister<BeanT,PropT,String,IDREFS<BeanT,PropT>.Pack> {
   324         private final Lister<BeanT,PropT,Object,Object> core;
   325         /**
   326          * Expected type to which IDREF resolves to.
   327          */
   328         private final Class itemType;
   330         public IDREFS(Lister core, Class itemType) {
   331             this.core = core;
   332             this.itemType = itemType;
   333         }
   335         public ListIterator<String> iterator(PropT prop, XMLSerializer context) {
   336             final ListIterator i = core.iterator(prop,context);
   338             return new IDREFSIterator(i, context);
   339         }
   341         public Pack startPacking(BeanT bean, Accessor<BeanT, PropT> acc) {
   342             return new Pack(bean,acc);
   343         }
   345         public void addToPack(Pack pack, String item) {
   346             pack.add(item);
   347         }
   349         public void endPacking(Pack pack, BeanT bean, Accessor<BeanT, PropT> acc) {
   350         }
   352         public void reset(BeanT bean, Accessor<BeanT, PropT> acc) throws AccessorException {
   353             core.reset(bean,acc);
   354         }
   356         /**
   357          * PackT for this lister.
   358          */
   359         private class Pack implements Patcher {
   360             private final BeanT bean;
   361             private final List<String> idrefs = new ArrayList<String>();
   362             private final UnmarshallingContext context;
   363             private final Accessor<BeanT,PropT> acc;
   364             private final LocatorEx location;
   366             public Pack(BeanT bean, Accessor<BeanT,PropT> acc) {
   367                 this.bean = bean;
   368                 this.acc = acc;
   369                 this.context = UnmarshallingContext.getInstance();
   370                 this.location = new LocatorEx.Snapshot(context.getLocator());
   371                 context.addPatcher(this);
   372             }
   374             public void add(String item) {
   375                 idrefs.add(item);
   376             }
   378             /**
   379              * Resolves IDREFS and fill in the actual array.
   380              */
   381             public void run() throws SAXException {
   382                 try {
   383                     Object pack = core.startPacking(bean,acc);
   385                     for( String id : idrefs ) {
   386                         Callable callable = context.getObjectFromId(id,itemType);
   387                         Object t;
   389                         try {
   390                             t = (callable!=null) ? callable.call() : null;
   391                         } catch (SAXException e) {
   392                             throw e;
   393                         } catch (Exception e) {
   394                             throw new SAXException2(e);
   395                         }
   397                         if(t==null) {
   398                             context.errorUnresolvedIDREF(bean,id,location);
   399                         } else {
   400                             TODO.prototype(); // TODO: check if the type of t is proper.
   401                             core.addToPack(pack,t);
   402                         }
   403                     }
   405                     core.endPacking(pack,bean,acc);
   406                 } catch (AccessorException e) {
   407                     context.handleError(e);
   408                 }
   409             }
   410         }
   411     }
   413     /**
   414      * {@link Iterator} for IDREFS lister.
   415      *
   416      * <p>
   417      * Only in ArrayElementProperty we need to get the actual
   418      * referenced object. This is a kind of ugly way to make that work.
   419      */
   420     public static final class IDREFSIterator implements ListIterator<String> {
   421         private final ListIterator i;
   422         private final XMLSerializer context;
   423         private Object last;
   425         private IDREFSIterator(ListIterator i, XMLSerializer context) {
   426             this.i = i;
   427             this.context = context;
   428         }
   430         public boolean hasNext() {
   431             return i.hasNext();
   432         }
   434         /**
   435          * Returns the last referenced object (not just its ID)
   436          */
   437         public Object last() {
   438             return last;
   439         }
   441         public String next() throws SAXException, JAXBException {
   442             last = i.next();
   443             String id = context.grammar.getBeanInfo(last,true).getId(last,context);
   444             if(id==null) {
   445                 context.errorMissingId(last);
   446             }
   447             return id;
   448         }
   449     }
   451     /**
   452      * Gets the special {@link Lister} used to recover from an error.
   453      */
   454     @SuppressWarnings("unchecked")
   455     public static <A,B,C,D> Lister<A,B,C,D> getErrorInstance() {
   456         return ERROR;
   457     }
   459     public static final Lister ERROR = new Lister() {
   460         public ListIterator iterator(Object o, XMLSerializer context) {
   461             return EMPTY_ITERATOR;
   462         }
   464         public Object startPacking(Object o, Accessor accessor) {
   465             return null;
   466         }
   468         public void addToPack(Object o, Object o1) {
   469         }
   471         public void endPacking(Object o, Object o1, Accessor accessor) {
   472         }
   474         public void reset(Object o, Accessor accessor) {
   475         }
   476     };
   478     private static final ListIterator EMPTY_ITERATOR = new ListIterator() {
   479         public boolean hasNext() {
   480             return false;
   481         }
   483         public Object next() {
   484             throw new IllegalStateException();
   485         }
   486     };
   488     private static final Class[] COLLECTION_IMPL_CLASSES = new Class[] {
   489         ArrayList.class,
   490         LinkedList.class,
   491         HashSet.class,
   492         TreeSet.class,
   493         Stack.class
   494     };
   495 }

mercurial