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 }