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

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 450
b0c2840e2513
parent 0
373ffda63c9a
child 760
e530533619ec
permissions
-rw-r--r--

merge

     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  */
    26 package com.sun.xml.internal.bind.v2.runtime.reflect;
    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;
    40 import javax.xml.bind.JAXBElement;
    41 import javax.xml.bind.annotation.adapters.XmlAdapter;
    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;
    55 import org.xml.sax.SAXException;
    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 {
    75     public final Class<ValueT> valueType;
    77     public Class<ValueT> getValueType() {
    78         return valueType;
    79     }
    81     protected Accessor(Class<ValueT> valueType) {
    82         this.valueType = valueType;
    83     }
    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 <tt>this</tt>.
    91      */
    92     public Accessor<BeanT, ValueT> optimize(@Nullable JAXBContextImpl context) {
    93         return this;
    94     }
    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;
   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;
   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     }
   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     }
   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     }
   149     public void receive(UnmarshallingContext.State state, Object o) throws SAXException {
   150         try {
   151             set((BeanT) state.target, (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     }
   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     );
   177     public boolean isValueTypeAbstractable() {
   178         return !nonAbstractableClasses.contains(getValueType());
   179     }
   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     }
   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     }
   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     }
   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;
   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;
   218         private static final Logger logger = Util.getClassLogger();
   220         public FieldReflection(Field f) {
   221             this(f, false);
   222         }
   224         public FieldReflection(Field f, boolean supressAccessorWarnings) {
   225             super((Class<ValueT>) f.getType());
   226             this.f = f;
   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, as that would create a security hole for anyone
   233                     // to make any field accessible.
   234                     f.setAccessible(true);
   235                 } catch (SecurityException e) {
   236                     if ((!accessWarned) && (!supressAccessorWarnings)) {
   237                         // this happens when we don't have enough permission.
   238                         logger.log(Level.WARNING, Messages.UNABLE_TO_ACCESS_NON_PUBLIC_FIELD.format(
   239                                 f.getDeclaringClass().getName(),
   240                                 f.getName()),
   241                                 e);
   242                     }
   243                     accessWarned = true;
   244                 }
   245             }
   246         }
   248         public ValueT get(BeanT bean) {
   249             try {
   250                 return (ValueT) f.get(bean);
   251             } catch (IllegalAccessException e) {
   252                 throw new IllegalAccessError(e.getMessage());
   253             }
   254         }
   256         public void set(BeanT bean, ValueT value) {
   257             try {
   258                 if (value == null)
   259                     value = (ValueT) uninitializedValues.get(valueType);
   260                 f.set(bean, value);
   261             } catch (IllegalAccessException e) {
   262                 throw new IllegalAccessError(e.getMessage());
   263             }
   264         }
   266         @Override
   267         public Accessor<BeanT, ValueT> optimize(JAXBContextImpl context) {
   268             if (context != null && context.fastBoot)
   269                 // let's not waste time on doing this for the sake of faster boot.
   270                 return this;
   271             Accessor<BeanT, ValueT> acc = OptimizedAccessorFactory.get(f);
   272             if (acc != null)
   273                 return acc;
   274             else
   275                 return this;
   276         }
   277     }
   279     /**
   280      * Read-only access to {@link Field}. Used to handle a static field.
   281      */
   282     public static final class ReadOnlyFieldReflection<BeanT, ValueT> extends FieldReflection<BeanT, ValueT> {
   283         public ReadOnlyFieldReflection(Field f, boolean supressAccessorWarnings) {
   284             super(f, supressAccessorWarnings);
   285         }
   286         public ReadOnlyFieldReflection(Field f) {
   287             super(f);
   288         }
   290         @Override
   291         public void set(BeanT bean, ValueT value) {
   292             // noop
   293         }
   295         @Override
   296         public Accessor<BeanT, ValueT> optimize(JAXBContextImpl context) {
   297             return this;
   298         }
   299     }
   302     /**
   303      * {@link Accessor} that uses Java reflection to access a getter and a setter.
   304      */
   305     public static class GetterSetterReflection<BeanT, ValueT> extends Accessor<BeanT, ValueT> {
   306         public final Method getter;
   307         public final Method setter;
   309         private static final Logger logger = Util.getClassLogger();
   311         public GetterSetterReflection(Method getter, Method setter) {
   312             super(
   313                     (Class<ValueT>) (getter != null ?
   314                             getter.getReturnType() :
   315                             setter.getParameterTypes()[0]));
   316             this.getter = getter;
   317             this.setter = setter;
   319             if (getter != null)
   320                 makeAccessible(getter);
   321             if (setter != null)
   322                 makeAccessible(setter);
   323         }
   325         private void makeAccessible(Method m) {
   326             if (!Modifier.isPublic(m.getModifiers()) || !Modifier.isPublic(m.getDeclaringClass().getModifiers())) {
   327                 try {
   328                     m.setAccessible(true);
   329                 } catch (SecurityException e) {
   330                     if (!accessWarned)
   331                         // this happens when we don't have enough permission.
   332                         logger.log(Level.WARNING, Messages.UNABLE_TO_ACCESS_NON_PUBLIC_FIELD.format(
   333                                 m.getDeclaringClass().getName(),
   334                                 m.getName()),
   335                                 e);
   336                     accessWarned = true;
   337                 }
   338             }
   339         }
   341         public ValueT get(BeanT bean) throws AccessorException {
   342             try {
   343                 return (ValueT) getter.invoke(bean);
   344             } catch (IllegalAccessException e) {
   345                 throw new IllegalAccessError(e.getMessage());
   346             } catch (InvocationTargetException e) {
   347                 throw handleInvocationTargetException(e);
   348             }
   349         }
   351         public void set(BeanT bean, ValueT value) throws AccessorException {
   352             try {
   353                 if (value == null)
   354                     value = (ValueT) uninitializedValues.get(valueType);
   355                 setter.invoke(bean, value);
   356             } catch (IllegalAccessException e) {
   357                 throw new IllegalAccessError(e.getMessage());
   358             } catch (InvocationTargetException e) {
   359                 throw handleInvocationTargetException(e);
   360             }
   361         }
   363         private AccessorException handleInvocationTargetException(InvocationTargetException e) {
   364             // don't block a problem in the user code
   365             Throwable t = e.getTargetException();
   366             if (t instanceof RuntimeException)
   367                 throw (RuntimeException) t;
   368             if (t instanceof Error)
   369                 throw (Error) t;
   371             // otherwise it's a checked exception.
   372             // I'm not sure how to handle this.
   373             // we can throw a checked exception from here,
   374             // but because get/set would be called from so many different places,
   375             // the handling would be tedious.
   376             return new AccessorException(t);
   377         }
   379         @Override
   380         public Accessor<BeanT, ValueT> optimize(JAXBContextImpl context) {
   381             if (getter == null || setter == null)
   382                 // if we aren't complete, OptimizedAccessor won't always work
   383                 return this;
   384             if (context != null && context.fastBoot)
   385                 // let's not waste time on doing this for the sake of faster boot.
   386                 return this;
   388             Accessor<BeanT, ValueT> acc = OptimizedAccessorFactory.get(getter, setter);
   389             if (acc != null)
   390                 return acc;
   391             else
   392                 return this;
   393         }
   394     }
   396     /**
   397      * A version of {@link GetterSetterReflection} that doesn't have any setter.
   398      * <p/>
   399      * <p/>
   400      * This provides a user-friendly error message.
   401      */
   402     public static class GetterOnlyReflection<BeanT, ValueT> extends GetterSetterReflection<BeanT, ValueT> {
   403         public GetterOnlyReflection(Method getter) {
   404             super(getter, null);
   405         }
   407         @Override
   408         public void set(BeanT bean, ValueT value) throws AccessorException {
   409             throw new AccessorException(Messages.NO_SETTER.format(getter.toString()));
   410         }
   411     }
   413     /**
   414      * A version of {@link GetterSetterReflection} thaat doesn't have any getter.
   415      * <p/>
   416      * <p/>
   417      * This provides a user-friendly error message.
   418      */
   419     public static class SetterOnlyReflection<BeanT, ValueT> extends GetterSetterReflection<BeanT, ValueT> {
   420         public SetterOnlyReflection(Method setter) {
   421             super(null, setter);
   422         }
   424         @Override
   425         public ValueT get(BeanT bean) throws AccessorException {
   426             throw new AccessorException(Messages.NO_GETTER.format(setter.toString()));
   427         }
   428     }
   430     /**
   431      * Gets the special {@link Accessor} used to recover from errors.
   432      */
   433     @SuppressWarnings("unchecked")
   434     public static <A, B> Accessor<A, B> getErrorInstance() {
   435         return ERROR;
   436     }
   438     private static final Accessor ERROR = new Accessor<Object, Object>(Object.class) {
   439         public Object get(Object o) {
   440             return null;
   441         }
   443         public void set(Object o, Object o1) {
   444         }
   445     };
   447     /**
   448      * {@link Accessor} for {@link JAXBElement#getValue()}.
   449      */
   450     public static final Accessor<JAXBElement, Object> JAXB_ELEMENT_VALUE = new Accessor<JAXBElement, Object>(Object.class) {
   451         public Object get(JAXBElement jaxbElement) {
   452             return jaxbElement.getValue();
   453         }
   455         public void set(JAXBElement jaxbElement, Object o) {
   456             jaxbElement.setValue(o);
   457         }
   458     };
   460     /**
   461      * Uninitialized map keyed by their classes.
   462      */
   463     private static final Map<Class, Object> uninitializedValues = new HashMap<Class, Object>();
   465     static {
   466 /*
   467     static byte default_value_byte = 0;
   468     static boolean default_value_boolean = false;
   469     static char default_value_char = 0;
   470     static float default_value_float = 0;
   471     static double default_value_double = 0;
   472     static int default_value_int = 0;
   473     static long default_value_long = 0;
   474     static short default_value_short = 0;
   475 */
   476         uninitializedValues.put(byte.class, Byte.valueOf((byte) 0));
   477         uninitializedValues.put(boolean.class, false);
   478         uninitializedValues.put(char.class, Character.valueOf((char) 0));
   479         uninitializedValues.put(float.class, Float.valueOf(0));
   480         uninitializedValues.put(double.class, Double.valueOf(0));
   481         uninitializedValues.put(int.class, Integer.valueOf(0));
   482         uninitializedValues.put(long.class, Long.valueOf(0));
   483         uninitializedValues.put(short.class, Short.valueOf((short) 0));
   484     }
   486 }

mercurial