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