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 
  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.logging.Level;
  38 import java.util.logging.Logger;
  39 
  40 import javax.xml.bind.JAXBElement;
  41 import javax.xml.bind.annotation.adapters.XmlAdapter;
  42 
  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.runtime.JAXBContextImpl;
  50 import com.sun.xml.internal.bind.v2.runtime.reflect.opt.OptimizedAccessorFactory;
  51 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
  52 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Receiver;
  53 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
  54 
  55 import 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  */
  73 public 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 }
--- EOF ---