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

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

mercurial