Fri, 23 Aug 2013 09:57:21 +0100
8022885: Update JAX-WS RI integration to 2.2.9-b14140
8013016: Rebase 8009009 against the latest jdk8/jaxws
Reviewed-by: alanb, chegar
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 }