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

Fri, 23 Aug 2013 09:57:21 +0100

author
mkos
date
Fri, 23 Aug 2013 09:57:21 +0100
changeset 397
b99d7e355d4b
parent 368
0989ad8c0860
child 450
b0c2840e2513
permissions
-rw-r--r--

8022885: Update JAX-WS RI integration to 2.2.9-b14140
8013016: Rebase 8009009 against the latest jdk8/jaxws
Reviewed-by: alanb, chegar

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

mercurial