All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.ibatis.ognl.AccessibleObjectHandlerJDK9Plus Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * and/or LICENSE file distributed with this work for additional
 * information regarding copyright ownership.  The ASF licenses
 * this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.ibatis.ognl;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Utilizes a JDK 9 and later mechanism for changing the accessibility level of a given
 * AccessibleObject.
 * 

* If the JDK 9+ mechanism fails, this class will fall back to a standard pre-JDK 9 reflection mechanism. * Note: That may cause "WARNING: Illegal reflective access" output to be generated to stdout/stderr. *

* For reference, this class draws on information from the following locations: * - Post about Illegal Reflective Access what is an illegal reflective access * - Blog on Unsafe Java Magic. Part 4: sun.misc.Unsafe * - Blog on Unsafe Guide to sun.misc.Unsafe * - JEP about access to Unsafe being retained in JDK 9 JEP 260: Encapsulate Most Internal APIs *

* In addition to the above, inspiration was drawn from Gson: PR 1218, * PR 1306. *

* Appreciation and credit to the authors, contributors and commenters for the information contained in the preceding links. * * @since 3.1.24 */ class AccessibleObjectHandlerJDK9Plus implements AccessibleObjectHandler { private static final Class CLAZZ_UNSAFE = instantiateClazzUnsafe(); private static final Object UNSAFE_INSTANCE = instantiateUnsafeInstance(); private static final Method UNSAFE_OBJECT_FIELD_OFFSET_METHOD = instantiateUnsafeObjectFieldOffsetMethod(); private static final Method UNSAFE_PUT_BOOLEAN_METHOD = instantiateUnsafePutBooleanMethod(); private static final Field ACCESSIBLE_OBJECT_OVERRIDE_FIELD = instantiateAccessibleObjectOverrideField(); private static final long ACCESSIBLE_OBJECT_OVERRIDE_FIELD_OFFSET = determineAccessibleObjectOverrideFieldOffset(); /** * Private constructor */ private AccessibleObjectHandlerJDK9Plus() { } /** * Package-accessible method to determine if a given class is Unsafe or a descendant * of Unsafe. * * @param clazz the Class upon which to perform the unsafe check. * @return true if parameter is Unsafe or a descendant, false otherwise */ static boolean unsafeOrDescendant(final Class clazz) { return (CLAZZ_UNSAFE != null && CLAZZ_UNSAFE.isAssignableFrom(clazz)); } /** * Instantiate an instance of the Unsafe class. * * @return class if available, null otherwise */ private static Class instantiateClazzUnsafe() { Class clazz; try { clazz = Class.forName("sun.misc.Unsafe"); } catch (Throwable t) { clazz = null; } return clazz; } /** * Instantiate an instance of Unsafe object. * * @return instance if available, null otherwise */ private static Object instantiateUnsafeInstance() { Object unsafe; if (AccessibleObjectHandlerJDK9Plus.CLAZZ_UNSAFE != null) { Field field = null; try { field = AccessibleObjectHandlerJDK9Plus.CLAZZ_UNSAFE.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = field.get(null); } catch (Throwable t) { unsafe = null; } finally { if (field != null) { try { field.setAccessible(false); } catch (Throwable t) { // Don't care } } } } else { unsafe = null; } return unsafe; } /** * Instantiate an Unsafe.objectFieldOffset() method instance. * * @return method if available, null otherwise */ private static Method instantiateUnsafeObjectFieldOffsetMethod() { Method method; if (AccessibleObjectHandlerJDK9Plus.CLAZZ_UNSAFE != null) { try { method = AccessibleObjectHandlerJDK9Plus.CLAZZ_UNSAFE.getMethod("objectFieldOffset", Field.class); } catch (Throwable t) { method = null; } } else { method = null; } return method; } /** * Instantiate an Unsafe.putBoolean() method instance. * * @return method if available, null otherwise */ private static Method instantiateUnsafePutBooleanMethod() { Method method; if (AccessibleObjectHandlerJDK9Plus.CLAZZ_UNSAFE != null) { try { method = AccessibleObjectHandlerJDK9Plus.CLAZZ_UNSAFE.getMethod("putBoolean", Object.class, long.class, boolean.class); } catch (Throwable t) { method = null; } } else { method = null; } return method; } /** * Instantiate an AccessibleObject override field instance. * * @return field if available, null otherwise */ private static Field instantiateAccessibleObjectOverrideField() { Field field; try { field = AccessibleObject.class.getDeclaredField("override"); } catch (Throwable t) { field = null; } return field; } /** * Attempt to determine the AccessibleObject override field offset. * * @return field offset if available, -1 otherwise */ private static long determineAccessibleObjectOverrideFieldOffset() { long offset = -1; if (ACCESSIBLE_OBJECT_OVERRIDE_FIELD != null && UNSAFE_OBJECT_FIELD_OFFSET_METHOD != null && UNSAFE_INSTANCE != null) { try { offset = (Long) UNSAFE_OBJECT_FIELD_OFFSET_METHOD.invoke(UNSAFE_INSTANCE, ACCESSIBLE_OBJECT_OVERRIDE_FIELD); } catch (Throwable t) { // Don't care (offset already -1) } } return offset; } /** * Package-level generator of an AccessibleObjectHandlerJDK9Plus instance. *

* Not intended for use outside of the package. *

* Note: An AccessibleObjectHandlerJDK9Plus will only be created if running on a * JDK9+ and the environment flag is set. Otherwise this method will return * an AccessibleHandlerPreJDK9 instance instead, * * @return an AccessibleObjectHandler instance * @since 3.1.24 */ static AccessibleObjectHandler createHandler() { if (OgnlRuntime.usingJDK9PlusAccessHandler()) { return new AccessibleObjectHandlerJDK9Plus(); } else { return AccessibleObjectHandlerPreJDK9.createHandler(); } } /** * Utilize accessibility modification mechanism for JDK 9 (Java Major Version 9) and later. * Should that mechanism fail, attempt a standard pre-JDK9 accessibility modification. * * @param accessibleObject the AccessibleObject upon which to apply the flag. * @param flag the new accessible flag value. */ public void setAccessible(AccessibleObject accessibleObject, boolean flag) { boolean operationComplete = false; if (UNSAFE_INSTANCE != null && UNSAFE_PUT_BOOLEAN_METHOD != null && ACCESSIBLE_OBJECT_OVERRIDE_FIELD_OFFSET != -1) { try { UNSAFE_PUT_BOOLEAN_METHOD.invoke(UNSAFE_INSTANCE, accessibleObject, ACCESSIBLE_OBJECT_OVERRIDE_FIELD_OFFSET, flag); operationComplete = true; } catch (Throwable t) { // Don't care (operationComplete already false) } } if (!operationComplete) { // Fallback to standard reflection if Unsafe processing fails accessibleObject.setAccessible(flag); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy