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, 2011, 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.reflect.Field;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Modifier;
32 import java.lang.reflect.Type;
33 import java.util.Arrays;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.logging.Level;
38 import java.util.logging.Logger;
40 import javax.xml.bind.JAXBElement;
41 import javax.xml.bind.annotation.adapters.XmlAdapter;
43 import com.sun.istack.internal.Nullable;
44 import com.sun.xml.internal.bind.Util;
45 import com.sun.xml.internal.bind.api.AccessorException;
46 import com.sun.xml.internal.bind.api.JAXBRIContext;
47 import com.sun.xml.internal.bind.v2.model.core.Adapter;
48 import com.sun.xml.internal.bind.v2.model.impl.RuntimeModelBuilder;
49 import com.sun.xml.internal.bind.v2.model.nav.Navigator;
50 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
51 import com.sun.xml.internal.bind.v2.runtime.reflect.opt.OptimizedAccessorFactory;
52 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
53 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Receiver;
54 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
56 import org.xml.sax.SAXException;
58 /**
59 * Accesses a particular property of a bean.
60 * <p/>
61 * <p/>
62 * This interface encapsulates the access to the actual data store.
63 * The intention is to generate implementations for a particular bean
64 * and a property to improve the performance.
65 * <p/>
66 * <p/>
67 * Accessor can be used as a receiver. Upon receiving an object
68 * it sets that to the field.
69 *
70 * @author Kohsuke Kawaguchi (kk@kohsuke.org)
71 * @see Accessor.FieldReflection
72 * @see TransducedAccessor
73 */
74 public abstract class Accessor<BeanT, ValueT> implements Receiver {
76 public final Class<ValueT> valueType;
78 public Class<ValueT> getValueType() {
79 return valueType;
80 }
82 protected Accessor(Class<ValueT> valueType) {
83 this.valueType = valueType;
84 }
86 /**
87 * Returns the optimized version of the same accessor.
88 *
89 * @param context The {@link JAXBContextImpl} that owns the whole thing.
90 * (See {@link RuntimeModelBuilder#context}.)
91 * @return At least the implementation can return <tt>this</tt>.
92 */
93 public Accessor<BeanT, ValueT> optimize(@Nullable JAXBContextImpl context) {
94 return this;
95 }
98 /**
99 * Gets the value of the property of the given bean object.
100 *
101 * @param bean must not be null.
102 * @throws AccessorException if failed to set a value. For example, the getter method
103 * may throw an exception.
104 * @since 2.0 EA1
105 */
106 public abstract ValueT get(BeanT bean) throws AccessorException;
108 /**
109 * Sets the value of the property of the given bean object.
110 *
111 * @param bean must not be null.
112 * @param value the value to be set. Setting value to null means resetting
113 * to the VM default value (even for primitive properties.)
114 * @throws AccessorException if failed to set a value. For example, the setter method
115 * may throw an exception.
116 * @since 2.0 EA1
117 */
118 public abstract void set(BeanT bean, ValueT value) throws AccessorException;
121 /**
122 * Sets the value without adapting the value.
123 * <p/>
124 * This ugly entry point is only used by JAX-WS.
125 * See {@link JAXBRIContext#getElementPropertyAccessor}
126 */
127 public Object getUnadapted(BeanT bean) throws AccessorException {
128 return get(bean);
129 }
131 /**
132 * Returns true if this accessor wraps an adapter.
133 * <p/>
134 * This method needs to be used with care, but it helps some optimization.
135 */
136 public boolean isAdapted() {
137 return false;
138 }
140 /**
141 * Sets the value without adapting the value.
142 * <p/>
143 * This ugly entry point is only used by JAX-WS.
144 * See {@link JAXBRIContext#getElementPropertyAccessor}
145 */
146 public void setUnadapted(BeanT bean, Object value) throws AccessorException {
147 set(bean, (ValueT) value);
148 }
150 public void receive(UnmarshallingContext.State state, Object o) throws SAXException {
151 try {
152 set((BeanT) state.target, (ValueT) o);
153 } catch (AccessorException e) {
154 Loader.handleGenericException(e, true);
155 } catch (IllegalAccessError iae) {
156 // throw UnmarshalException instead IllegalAccesssError | Issue 475
157 Loader.handleGenericError(iae);
158 }
159 }
161 private static List<Class> nonAbstractableClasses = Arrays.asList(new Class[]{
162 Object.class,
163 java.util.Calendar.class,
164 javax.xml.datatype.Duration.class,
165 javax.xml.datatype.XMLGregorianCalendar.class,
166 java.awt.Image.class,
167 javax.activation.DataHandler.class,
168 javax.xml.transform.Source.class,
169 java.util.Date.class,
170 java.io.File.class,
171 java.net.URI.class,
172 java.net.URL.class,
173 Class.class,
174 String.class,
175 javax.xml.transform.Source.class}
176 );
178 public boolean isValueTypeAbstractable() {
179 return !nonAbstractableClasses.contains(getValueType());
180 }
182 /**
183 * Checks if it is not builtin jaxb class
184 * @param clazz to be checked
185 * @return true if it is NOT builtin class
186 */
187 public boolean isAbstractable(Class clazz) {
188 return !nonAbstractableClasses.contains(clazz);
189 }
191 /**
192 * Wraps this {@link Accessor} into another {@link Accessor}
193 * and performs the type adaption as necessary.
194 */
195 public final <T> Accessor<BeanT, T> adapt(Class<T> targetType, final Class<? extends XmlAdapter<T, ValueT>> adapter) {
196 return new AdaptedAccessor<BeanT, ValueT, T>(targetType, this, adapter);
197 }
199 public final <T> Accessor<BeanT, T> adapt(Adapter<Type, Class> adapter) {
200 return new AdaptedAccessor<BeanT, ValueT, T>(
201 (Class<T>) Navigator.REFLECTION.erasure(adapter.defaultType),
202 this,
203 adapter.adapterType);
204 }
206 /**
207 * Flag that will be set to true after issueing a warning
208 * about the lack of permission to access non-public fields.
209 */
210 private static boolean accessWarned = false;
213 /**
214 * {@link Accessor} that uses Java reflection to access a field.
215 */
216 public static class FieldReflection<BeanT, ValueT> extends Accessor<BeanT, ValueT> {
217 public final Field f;
219 private static final Logger logger = Util.getClassLogger();
221 public FieldReflection(Field f) {
222 this(f, false);
223 }
225 public FieldReflection(Field f, boolean supressAccessorWarnings) {
226 super((Class<ValueT>) f.getType());
227 this.f = f;
229 int mod = f.getModifiers();
230 if (!Modifier.isPublic(mod) || Modifier.isFinal(mod) || !Modifier.isPublic(f.getDeclaringClass().getModifiers())) {
231 try {
232 // attempt to make it accessible, but do so in the security context of the calling application.
233 // don't do this in the doPrivilege block, as that would create a security hole for anyone
234 // to make any field accessible.
235 f.setAccessible(true);
236 } catch (SecurityException e) {
237 if ((!accessWarned) && (!supressAccessorWarnings)) {
238 // this happens when we don't have enough permission.
239 logger.log(Level.WARNING, Messages.UNABLE_TO_ACCESS_NON_PUBLIC_FIELD.format(
240 f.getDeclaringClass().getName(),
241 f.getName()),
242 e);
243 }
244 accessWarned = true;
245 }
246 }
247 }
249 public ValueT get(BeanT bean) {
250 try {
251 return (ValueT) f.get(bean);
252 } catch (IllegalAccessException e) {
253 throw new IllegalAccessError(e.getMessage());
254 }
255 }
257 public void set(BeanT bean, ValueT value) {
258 try {
259 if (value == null)
260 value = (ValueT) uninitializedValues.get(valueType);
261 f.set(bean, value);
262 } catch (IllegalAccessException e) {
263 throw new IllegalAccessError(e.getMessage());
264 }
265 }
267 @Override
268 public Accessor<BeanT, ValueT> optimize(JAXBContextImpl context) {
269 if (context != null && context.fastBoot)
270 // let's not waste time on doing this for the sake of faster boot.
271 return this;
272 Accessor<BeanT, ValueT> acc = OptimizedAccessorFactory.get(f);
273 if (acc != null)
274 return acc;
275 else
276 return this;
277 }
278 }
280 /**
281 * Read-only access to {@link Field}. Used to handle a static field.
282 */
283 public static final class ReadOnlyFieldReflection<BeanT, ValueT> extends FieldReflection<BeanT, ValueT> {
284 public ReadOnlyFieldReflection(Field f, boolean supressAccessorWarnings) {
285 super(f, supressAccessorWarnings);
286 }
287 public ReadOnlyFieldReflection(Field f) {
288 super(f);
289 }
291 @Override
292 public void set(BeanT bean, ValueT value) {
293 // noop
294 }
296 @Override
297 public Accessor<BeanT, ValueT> optimize(JAXBContextImpl context) {
298 return this;
299 }
300 }
303 /**
304 * {@link Accessor} that uses Java reflection to access a getter and a setter.
305 */
306 public static class GetterSetterReflection<BeanT, ValueT> extends Accessor<BeanT, ValueT> {
307 public final Method getter;
308 public final Method setter;
310 private static final Logger logger = Util.getClassLogger();
312 public GetterSetterReflection(Method getter, Method setter) {
313 super(
314 (Class<ValueT>) (getter != null ?
315 getter.getReturnType() :
316 setter.getParameterTypes()[0]));
317 this.getter = getter;
318 this.setter = setter;
320 if (getter != null)
321 makeAccessible(getter);
322 if (setter != null)
323 makeAccessible(setter);
324 }
326 private void makeAccessible(Method m) {
327 if (!Modifier.isPublic(m.getModifiers()) || !Modifier.isPublic(m.getDeclaringClass().getModifiers())) {
328 try {
329 m.setAccessible(true);
330 } catch (SecurityException e) {
331 if (!accessWarned)
332 // this happens when we don't have enough permission.
333 logger.log(Level.WARNING, Messages.UNABLE_TO_ACCESS_NON_PUBLIC_FIELD.format(
334 m.getDeclaringClass().getName(),
335 m.getName()),
336 e);
337 accessWarned = true;
338 }
339 }
340 }
342 public ValueT get(BeanT bean) throws AccessorException {
343 try {
344 return (ValueT) getter.invoke(bean);
345 } catch (IllegalAccessException e) {
346 throw new IllegalAccessError(e.getMessage());
347 } catch (InvocationTargetException e) {
348 throw handleInvocationTargetException(e);
349 }
350 }
352 public void set(BeanT bean, ValueT value) throws AccessorException {
353 try {
354 if (value == null)
355 value = (ValueT) uninitializedValues.get(valueType);
356 setter.invoke(bean, value);
357 } catch (IllegalAccessException e) {
358 throw new IllegalAccessError(e.getMessage());
359 } catch (InvocationTargetException e) {
360 throw handleInvocationTargetException(e);
361 }
362 }
364 private AccessorException handleInvocationTargetException(InvocationTargetException e) {
365 // don't block a problem in the user code
366 Throwable t = e.getTargetException();
367 if (t instanceof RuntimeException)
368 throw (RuntimeException) t;
369 if (t instanceof Error)
370 throw (Error) t;
372 // otherwise it's a checked exception.
373 // I'm not sure how to handle this.
374 // we can throw a checked exception from here,
375 // but because get/set would be called from so many different places,
376 // the handling would be tedious.
377 return new AccessorException(t);
378 }
380 @Override
381 public Accessor<BeanT, ValueT> optimize(JAXBContextImpl context) {
382 if (getter == null || setter == null)
383 // if we aren't complete, OptimizedAccessor won't always work
384 return this;
385 if (context != null && context.fastBoot)
386 // let's not waste time on doing this for the sake of faster boot.
387 return this;
389 Accessor<BeanT, ValueT> acc = OptimizedAccessorFactory.get(getter, setter);
390 if (acc != null)
391 return acc;
392 else
393 return this;
394 }
395 }
397 /**
398 * A version of {@link GetterSetterReflection} that doesn't have any setter.
399 * <p/>
400 * <p/>
401 * This provides a user-friendly error message.
402 */
403 public static class GetterOnlyReflection<BeanT, ValueT> extends GetterSetterReflection<BeanT, ValueT> {
404 public GetterOnlyReflection(Method getter) {
405 super(getter, null);
406 }
408 @Override
409 public void set(BeanT bean, ValueT value) throws AccessorException {
410 throw new AccessorException(Messages.NO_SETTER.format(getter.toString()));
411 }
412 }
414 /**
415 * A version of {@link GetterSetterReflection} thaat doesn't have any getter.
416 * <p/>
417 * <p/>
418 * This provides a user-friendly error message.
419 */
420 public static class SetterOnlyReflection<BeanT, ValueT> extends GetterSetterReflection<BeanT, ValueT> {
421 public SetterOnlyReflection(Method setter) {
422 super(null, setter);
423 }
425 @Override
426 public ValueT get(BeanT bean) throws AccessorException {
427 throw new AccessorException(Messages.NO_GETTER.format(setter.toString()));
428 }
429 }
431 /**
432 * Gets the special {@link Accessor} used to recover from errors.
433 */
434 @SuppressWarnings("unchecked")
435 public static <A, B> Accessor<A, B> getErrorInstance() {
436 return ERROR;
437 }
439 private static final Accessor ERROR = new Accessor<Object, Object>(Object.class) {
440 public Object get(Object o) {
441 return null;
442 }
444 public void set(Object o, Object o1) {
445 }
446 };
448 /**
449 * {@link Accessor} for {@link JAXBElement#getValue()}.
450 */
451 public static final Accessor<JAXBElement, Object> JAXB_ELEMENT_VALUE = new Accessor<JAXBElement, Object>(Object.class) {
452 public Object get(JAXBElement jaxbElement) {
453 return jaxbElement.getValue();
454 }
456 public void set(JAXBElement jaxbElement, Object o) {
457 jaxbElement.setValue(o);
458 }
459 };
461 /**
462 * Uninitialized map keyed by their classes.
463 */
464 private static final Map<Class, Object> uninitializedValues = new HashMap<Class, Object>();
466 static {
467 /*
468 static byte default_value_byte = 0;
469 static boolean default_value_boolean = false;
470 static char default_value_char = 0;
471 static float default_value_float = 0;
472 static double default_value_double = 0;
473 static int default_value_int = 0;
474 static long default_value_long = 0;
475 static short default_value_short = 0;
476 */
477 uninitializedValues.put(byte.class, Byte.valueOf((byte) 0));
478 uninitializedValues.put(boolean.class, false);
479 uninitializedValues.put(char.class, Character.valueOf((char) 0));
480 uninitializedValues.put(float.class, Float.valueOf(0));
481 uninitializedValues.put(double.class, Double.valueOf(0));
482 uninitializedValues.put(int.class, Integer.valueOf(0));
483 uninitializedValues.put(long.class, Long.valueOf(0));
484 uninitializedValues.put(short.class, Short.valueOf((short) 0));
485 }
487 }