/* * Copyright (C) 2022 Google Inc. * * Licensed 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 com.google.gson; import com.google.gson.internal.ReflectionAccessFilterHelper; import java.lang.reflect.AccessibleObject; /** * Filter for determining whether reflection based serialization and deserialization is allowed for * a class. * *

A filter can be useful in multiple scenarios, for example when upgrading to newer Java * versions which use the Java Platform Module System (JPMS). A filter then allows to {@linkplain * FilterResult#BLOCK_INACCESSIBLE prevent making inaccessible members accessible}, even if the used * Java version might still allow illegal access (but logs a warning), or if {@code java} command * line arguments are used to open the inaccessible packages to other parts of the application. This * interface defines some convenience filters for this task, such as {@link * #BLOCK_INACCESSIBLE_JAVA}. * *

A filter can also be useful to prevent mixing model classes of a project with other non-model * classes; the filter could {@linkplain FilterResult#BLOCK_ALL block all reflective access} to * non-model classes. * *

A reflection access filter is similar to an {@link ExclusionStrategy} with the major * difference that a filter will cause an exception to be thrown when access is disallowed while an * exclusion strategy just skips fields and classes. * * @see GsonBuilder#addReflectionAccessFilter(ReflectionAccessFilter) * @since 2.9.1 */ public interface ReflectionAccessFilter { /** * Result of a filter check. * * @since 2.9.1 */ enum FilterResult { /** * Reflection access for the class is allowed. * *

Note that this does not affect the Java access checks in any way, it only permits Gson to * try using reflection for a class. The Java runtime might still deny such access. */ ALLOW, /** * The filter is indecisive whether reflection access should be allowed. The next registered * filter will be consulted to get the result. If there is no next filter, this result acts like * {@link #ALLOW}. */ INDECISIVE, /** * Blocks reflection access if a member of the class is not accessible by default and would have * to be made accessible. This is unaffected by any {@code java} command line arguments being * used to make packages accessible, or by module declaration directives which open the * complete module or certain packages for reflection and will consider such packages * inaccessible. * *

Note that this only works for Java 9 and higher, for older Java versions its * functionality will be limited and it might behave like {@link #ALLOW}. Access checks are only * performed as defined by the Java Language Specification (JLS 11 * §6.6), restrictions imposed by a {@link SecurityManager} are not considered. * *

This result type is mainly intended to help enforce the access checks of the Java Platform * Module System. It allows detecting illegal access, even if the used Java version would only * log a warning, or is configured to open packages for reflection using command line arguments. * * @see AccessibleObject#canAccess(Object) */ BLOCK_INACCESSIBLE, /** * Blocks all reflection access for the class. Other means for serializing and deserializing the * class, such as a {@link TypeAdapter}, have to be used. */ BLOCK_ALL } /** * Blocks all reflection access to members of standard Java classes which are not accessible by * default. However, reflection access is still allowed for classes for which all fields are * accessible and which have an accessible no-args constructor (or for which an {@link * InstanceCreator} has been registered). * *

If this filter encounters a class other than a standard Java class it returns {@link * FilterResult#INDECISIVE}. * *

This filter is mainly intended to help enforcing the access checks of Java Platform Module * System. It allows detecting illegal access, even if the used Java version would only log a * warning, or is configured to open packages for reflection. However, this filter only works * for Java 9 and higher, when using an older Java version its functionality will be limited. * *

Note that this filter might not cover all standard Java classes. Currently only classes in a * {@code java.*} or {@code javax.*} package are considered. The set of detected classes might be * expanded in the future without prior notice. * * @see FilterResult#BLOCK_INACCESSIBLE */ ReflectionAccessFilter BLOCK_INACCESSIBLE_JAVA = new ReflectionAccessFilter() { @Override public FilterResult check(Class rawClass) { return ReflectionAccessFilterHelper.isJavaType(rawClass) ? FilterResult.BLOCK_INACCESSIBLE : FilterResult.INDECISIVE; } @Override public String toString() { return "ReflectionAccessFilter#BLOCK_INACCESSIBLE_JAVA"; } }; /** * Blocks all reflection access to members of standard Java classes. * *

If this filter encounters a class other than a standard Java class it returns {@link * FilterResult#INDECISIVE}. * *

This filter is mainly intended to prevent depending on implementation details of the Java * platform and to help applications prepare for upgrading to the Java Platform Module System. * *

Note that this filter might not cover all standard Java classes. Currently only classes in a * {@code java.*} or {@code javax.*} package are considered. The set of detected classes might be * expanded in the future without prior notice. * * @see #BLOCK_INACCESSIBLE_JAVA * @see FilterResult#BLOCK_ALL */ ReflectionAccessFilter BLOCK_ALL_JAVA = new ReflectionAccessFilter() { @Override public FilterResult check(Class rawClass) { return ReflectionAccessFilterHelper.isJavaType(rawClass) ? FilterResult.BLOCK_ALL : FilterResult.INDECISIVE; } @Override public String toString() { return "ReflectionAccessFilter#BLOCK_ALL_JAVA"; } }; /** * Blocks all reflection access to members of standard Android classes. * *

If this filter encounters a class other than a standard Android class it returns {@link * FilterResult#INDECISIVE}. * *

This filter is mainly intended to prevent depending on implementation details of the Android * platform. * *

Note that this filter might not cover all standard Android classes. Currently only classes * in an {@code android.*} or {@code androidx.*} package, and standard Java classes in a {@code * java.*} or {@code javax.*} package are considered. The set of detected classes might be * expanded in the future without prior notice. * * @see FilterResult#BLOCK_ALL */ ReflectionAccessFilter BLOCK_ALL_ANDROID = new ReflectionAccessFilter() { @Override public FilterResult check(Class rawClass) { return ReflectionAccessFilterHelper.isAndroidType(rawClass) ? FilterResult.BLOCK_ALL : FilterResult.INDECISIVE; } @Override public String toString() { return "ReflectionAccessFilter#BLOCK_ALL_ANDROID"; } }; /** * Blocks all reflection access to members of classes belonging to programming language platforms, * such as Java, Android, Kotlin or Scala. * *

If this filter encounters a class other than a standard platform class it returns {@link * FilterResult#INDECISIVE}. * *

This filter is mainly intended to prevent depending on implementation details of the * platform classes. * *

Note that this filter might not cover all platform classes. Currently it combines the * filters {@link #BLOCK_ALL_JAVA} and {@link #BLOCK_ALL_ANDROID}, and checks for other * language-specific platform classes like {@code kotlin.*}. The set of detected classes might be * expanded in the future without prior notice. * * @see FilterResult#BLOCK_ALL */ ReflectionAccessFilter BLOCK_ALL_PLATFORM = new ReflectionAccessFilter() { @Override public FilterResult check(Class rawClass) { return ReflectionAccessFilterHelper.isAnyPlatformType(rawClass) ? FilterResult.BLOCK_ALL : FilterResult.INDECISIVE; } @Override public String toString() { return "ReflectionAccessFilter#BLOCK_ALL_PLATFORM"; } }; /** * Checks if reflection access should be allowed for a class. * * @param rawClass Class to check * @return Result indicating whether reflection access is allowed */ FilterResult check(Class rawClass); }