001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.xml.internal.bind.v2.runtime.reflect;
027:
028: import java.lang.reflect.Field;
029: import java.lang.reflect.InvocationTargetException;
030: import java.lang.reflect.Method;
031: import java.lang.reflect.Modifier;
032: import java.lang.reflect.Type;
033: import java.util.HashMap;
034: import java.util.Map;
035: import java.util.logging.Level;
036: import java.util.logging.Logger;
037:
038: import javax.xml.bind.JAXBElement;
039: import javax.xml.bind.annotation.adapters.XmlAdapter;
040:
041: import com.sun.xml.internal.bind.Util;
042: import com.sun.xml.internal.bind.api.AccessorException;
043: import com.sun.xml.internal.bind.api.JAXBRIContext;
044: import com.sun.xml.internal.bind.v2.model.core.Adapter;
045: import com.sun.xml.internal.bind.v2.model.nav.Navigator;
046: import com.sun.xml.internal.bind.v2.runtime.reflect.opt.OptimizedAccessorFactory;
047: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
048: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Receiver;
049: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
050:
051: import org.xml.sax.SAXException;
052:
053: /**
054: * Accesses a particular property of a bean.
055: *
056: * <p>
057: * This interface encapsulates the access to the actual data store.
058: * The intention is to generate implementations for a particular bean
059: * and a property to improve the performance.
060: *
061: * <p>
062: * Accessor can be used as a receiver. Upon receiving an object
063: * it sets that to the field.
064: *
065: * @see Accessor.FieldReflection
066: * @see TransducedAccessor
067: *
068: * @author Kohsuke Kawaguchi (kk@kohsuke.org)
069: */
070: public abstract class Accessor<BeanT, ValueT> implements Receiver {
071:
072: public final Class<ValueT> valueType;
073:
074: public Class<ValueT> getValueType() {
075: return valueType;
076: }
077:
078: protected Accessor(Class<ValueT> valueType) {
079: this .valueType = valueType;
080: }
081:
082: /**
083: * Returns the optimized version of the same accessor.
084: *
085: * @return
086: * At least the implementation can return <tt>this</tt>.
087: */
088: public Accessor<BeanT, ValueT> optimize() {
089: return this ;
090: }
091:
092: /**
093: * Gets the value of the property of the given bean object.
094: *
095: * @param bean
096: * must not be null.
097: * @throws AccessorException
098: * if failed to set a value. For example, the getter method
099: * may throw an exception.
100: *
101: * @since 2.0 EA1
102: */
103: public abstract ValueT get(BeanT bean) throws AccessorException;
104:
105: /**
106: * Sets the value of the property of the given bean object.
107: *
108: * @param bean
109: * must not be null.
110: * @param value
111: * the value to be set. Setting value to null means resetting
112: * to the VM default value (even for primitive properties.)
113: * @throws AccessorException
114: * if failed to set a value. For example, the setter method
115: * may throw an exception.
116: *
117: * @since 2.0 EA1
118: */
119: public abstract void set(BeanT bean, ValueT value)
120: throws AccessorException;
121:
122: /**
123: * Sets the value without adapting the value.
124: *
125: * This ugly entry point is only used by JAX-WS.
126: * See {@link JAXBRIContext#getElementPropertyAccessor}
127: */
128: public Object getUnadapted(BeanT bean) throws AccessorException {
129: return get(bean);
130: }
131:
132: /**
133: * Sets the value without adapting the value.
134: *
135: * This ugly entry point is only used by JAX-WS.
136: * See {@link JAXBRIContext#getElementPropertyAccessor}
137: */
138: public void setUnadapted(BeanT bean, Object value)
139: throws AccessorException {
140: set(bean, (ValueT) value);
141: }
142:
143: public void receive(UnmarshallingContext.State state, Object o)
144: throws SAXException {
145: try {
146: set((BeanT) state.target, (ValueT) o);
147: } catch (AccessorException e) {
148: Loader.handleGenericException(e, true);
149: }
150: }
151:
152: /**
153: * Wraps this {@link Accessor} into another {@link Accessor}
154: * and performs the type adaption as necessary.
155: */
156: public final <T> Accessor<BeanT, T> adapt(Class<T> targetType,
157: final Class<? extends XmlAdapter<T, ValueT>> adapter) {
158: return new AdaptedAccessor<BeanT, ValueT, T>(targetType, this ,
159: adapter);
160: }
161:
162: public final <T> Accessor<BeanT, T> adapt(
163: Adapter<Type, Class> adapter) {
164: return new AdaptedAccessor<BeanT, ValueT, T>(
165: (Class<T>) Navigator.REFLECTION
166: .erasure(adapter.defaultType), this ,
167: adapter.adapterType);
168: }
169:
170: /**
171: * Flag that will be set to true after issueing a warning
172: * about the lack of permission to access non-public fields.
173: */
174: private static boolean accessWarned = false;
175:
176: /**
177: * {@link Accessor} that uses Java reflection to access a field.
178: */
179: public static class FieldReflection<BeanT, ValueT> extends
180: Accessor<BeanT, ValueT> {
181: public final Field f;
182:
183: private static final Logger logger = Util.getClassLogger();
184:
185: // TODO: revisit. this is a security hole because this method can be used by anyone
186: // to enable access to a field.
187: public FieldReflection(Field f) {
188: super ((Class<ValueT>) f.getType());
189: this .f = f;
190:
191: int mod = f.getModifiers();
192: if (!Modifier.isPublic(mod)
193: || Modifier.isFinal(mod)
194: || !Modifier.isPublic(f.getDeclaringClass()
195: .getModifiers())) {
196: try {
197: f.setAccessible(true);
198: } catch (SecurityException e) {
199: if (!accessWarned)
200: // this happens when we don't have enough permission.
201: logger
202: .log(
203: Level.WARNING,
204: Messages.UNABLE_TO_ACCESS_NON_PUBLIC_FIELD
205: .format(
206: f
207: .getDeclaringClass()
208: .getName(),
209: f.getName()), e);
210: accessWarned = true;
211: }
212: }
213: }
214:
215: public ValueT get(BeanT bean) {
216: try {
217: return (ValueT) f.get(bean);
218: } catch (IllegalAccessException e) {
219: throw new IllegalAccessError(e.getMessage());
220: }
221: }
222:
223: public void set(BeanT bean, ValueT value) {
224: try {
225: if (value == null)
226: value = (ValueT) uninitializedValues.get(valueType);
227: f.set(bean, value);
228: } catch (IllegalAccessException e) {
229: throw new IllegalAccessError(e.getMessage());
230: }
231: }
232:
233: @Override
234: public Accessor<BeanT, ValueT> optimize() {
235: Accessor<BeanT, ValueT> acc = OptimizedAccessorFactory
236: .get(f);
237: if (acc != null)
238: return acc;
239: else
240: return this ;
241: }
242: }
243:
244: /**
245: * Read-only access to {@link Field}. Used to handle a static field.
246: */
247: public static final class ReadOnlyFieldReflection<BeanT, ValueT>
248: extends FieldReflection<BeanT, ValueT> {
249: public ReadOnlyFieldReflection(Field f) {
250: super (f);
251: }
252:
253: public void set(BeanT bean, ValueT value) {
254: // noop
255: }
256:
257: @Override
258: public Accessor<BeanT, ValueT> optimize() {
259: return this ;
260: }
261: }
262:
263: /**
264: * {@link Accessor} that uses Java reflection to access a getter and a setter.
265: */
266: public static class GetterSetterReflection<BeanT, ValueT> extends
267: Accessor<BeanT, ValueT> {
268: public final Method getter;
269: public final Method setter;
270:
271: private static final Logger logger = Util.getClassLogger();
272:
273: public GetterSetterReflection(Method getter, Method setter) {
274: super ((Class<ValueT>) (getter != null ? getter
275: .getReturnType() : setter.getParameterTypes()[0]));
276: this .getter = getter;
277: this .setter = setter;
278:
279: if (getter != null)
280: makeAccessible(getter);
281: if (setter != null)
282: makeAccessible(setter);
283: }
284:
285: private void makeAccessible(Method m) {
286: if (!Modifier.isPublic(m.getModifiers())
287: || !Modifier.isPublic(m.getDeclaringClass()
288: .getModifiers())) {
289: try {
290: m.setAccessible(true);
291: } catch (SecurityException e) {
292: if (!accessWarned)
293: // this happens when we don't have enough permission.
294: logger
295: .log(
296: Level.WARNING,
297: Messages.UNABLE_TO_ACCESS_NON_PUBLIC_FIELD
298: .format(
299: m
300: .getDeclaringClass()
301: .getName(),
302: m.getName()), e);
303: accessWarned = true;
304: }
305: }
306: }
307:
308: public ValueT get(BeanT bean) throws AccessorException {
309: try {
310: return (ValueT) getter.invoke(bean);
311: } catch (IllegalAccessException e) {
312: throw new IllegalAccessError(e.getMessage());
313: } catch (InvocationTargetException e) {
314: throw handleInvocationTargetException(e);
315: }
316: }
317:
318: public void set(BeanT bean, ValueT value)
319: throws AccessorException {
320: try {
321: if (value == null)
322: value = (ValueT) uninitializedValues.get(valueType);
323: setter.invoke(bean, value);
324: } catch (IllegalAccessException e) {
325: throw new IllegalAccessError(e.getMessage());
326: } catch (InvocationTargetException e) {
327: throw handleInvocationTargetException(e);
328: }
329: }
330:
331: private AccessorException handleInvocationTargetException(
332: InvocationTargetException e) {
333: // don't block a problem in the user code
334: Throwable t = e.getTargetException();
335: if (t instanceof RuntimeException)
336: throw (RuntimeException) t;
337: if (t instanceof Error)
338: throw (Error) t;
339:
340: // otherwise it's a checked exception.
341: // I'm not sure how to handle this.
342: // we can throw a checked exception from here,
343: // but because get/set would be called from so many different places,
344: // the handling would be tedious.
345: return new AccessorException(t);
346: }
347:
348: @Override
349: public Accessor<BeanT, ValueT> optimize() {
350: if (getter == null || setter == null)
351: // if we aren't complete, OptimizedAccessor won't always work
352: return this ;
353:
354: Accessor<BeanT, ValueT> acc = OptimizedAccessorFactory.get(
355: getter, setter);
356: if (acc != null)
357: return acc;
358: else
359: return this ;
360: }
361: }
362:
363: /**
364: * A version of {@link GetterSetterReflection} thaat doesn't have any setter.
365: *
366: * <p>
367: * This provides a user-friendly error message.
368: */
369: public static class GetterOnlyReflection<BeanT, ValueT> extends
370: GetterSetterReflection<BeanT, ValueT> {
371: public GetterOnlyReflection(Method getter) {
372: super (getter, null);
373: }
374:
375: @Override
376: public void set(BeanT bean, ValueT value)
377: throws AccessorException {
378: throw new AccessorException(Messages.NO_SETTER
379: .format(getter.toString()));
380: }
381: }
382:
383: /**
384: * A version of {@link GetterSetterReflection} thaat doesn't have any getter.
385: *
386: * <p>
387: * This provides a user-friendly error message.
388: */
389: public static class SetterOnlyReflection<BeanT, ValueT> extends
390: GetterSetterReflection<BeanT, ValueT> {
391: public SetterOnlyReflection(Method setter) {
392: super (null, setter);
393: }
394:
395: @Override
396: public ValueT get(BeanT bean) throws AccessorException {
397: throw new AccessorException(Messages.NO_GETTER
398: .format(setter.toString()));
399: }
400: }
401:
402: /**
403: * Special {@link Accessor} used to recover from errors.
404: */
405: public static final Accessor ERROR = new Accessor(Object.class) {
406: public Object get(Object o) {
407: return null;
408: }
409:
410: public void set(Object o, Object o1) {
411: }
412: };
413:
414: /**
415: * {@link Accessor} for {@link JAXBElement#getValue()}.
416: */
417: public static final Accessor<JAXBElement, Object> JAXB_ELEMENT_VALUE = new Accessor<JAXBElement, Object>(
418: Object.class) {
419: public Object get(JAXBElement jaxbElement) {
420: return jaxbElement.getValue();
421: }
422:
423: public void set(JAXBElement jaxbElement, Object o) {
424: jaxbElement.setValue(o);
425: }
426: };
427:
428: /**
429: * Uninitialized map keyed by their classes.
430: */
431: private static final Map<Class, Object> uninitializedValues = new HashMap<Class, Object>();
432:
433: static {
434: /*
435: static byte default_value_byte = 0;
436: static boolean default_value_boolean = false;
437: static char default_value_char = 0;
438: static float default_value_float = 0;
439: static double default_value_double = 0;
440: static int default_value_int = 0;
441: static long default_value_long = 0;
442: static short default_value_short = 0;
443: */
444: uninitializedValues.put(byte.class, Byte.valueOf((byte) 0));
445: uninitializedValues.put(boolean.class, false);
446: uninitializedValues
447: .put(char.class, Character.valueOf((char) 0));
448: uninitializedValues.put(float.class, Float.valueOf(0));
449: uninitializedValues.put(double.class, Double.valueOf(0));
450: uninitializedValues.put(int.class, Integer.valueOf(0));
451: uninitializedValues.put(long.class, Long.valueOf(0));
452: uninitializedValues.put(short.class, Short.valueOf((short) 0));
453: }
454:
455: }
|