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 }