-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for reflection access filter #1905
Merged
eamonnmcmanus
merged 13 commits into
google:master
from
Marcono1234:marcono1234/reflection-access-filter
Apr 17, 2022
Merged
Changes from 10 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
6786766
Add support for reflection access filter
Marcono1234 153380f
Merge branch 'master' into marcono1234/reflection-access-filter
Marcono1234 1dbca2b
Improve documentation
Marcono1234 37e1ea8
Fix compilation errors
Marcono1234 9eb5fa2
Relax handling for BLOCK_ALL when invoking default constructor
Marcono1234 bb42ff9
Improve handling for inherited fields
Marcono1234 988c68c
Fix accessible test failing for static fields
Marcono1234 dd2ba4e
Simplify ReflectiveTypeAdapterFactory field writing
Marcono1234 5298957
Fix GsonBuilder changes affecting created Gson instances
Marcono1234 870496e
Improve documentation
Marcono1234 837b21f
Improve handling for IllegalAccessException
Marcono1234 f4e0ecd
Merge remote-tracking branch 'remotes/origin/master' into marcono1234…
Marcono1234 8acf2a9
Fix incorrect GsonBuilder.addReflectionAccessFilter documentation
Marcono1234 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
194 changes: 194 additions & 0 deletions
194
gson/src/main/java/com/google/gson/ReflectionAccessFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
package com.google.gson; | ||
|
||
import java.lang.reflect.AccessibleObject; | ||
|
||
import com.google.gson.internal.ReflectionAccessFilterHelper; | ||
|
||
/** | ||
* Filter for determining whether reflection based serialization and | ||
* deserialization is allowed for a class. | ||
* | ||
* <p>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}. | ||
* | ||
* <p>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. | ||
* | ||
* <p>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) | ||
*/ | ||
public interface ReflectionAccessFilter { | ||
/** | ||
* Result of a filter check. | ||
*/ | ||
enum FilterResult { | ||
/** | ||
* Reflection access for the class is allowed. | ||
* | ||
* <p>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 <i>open</i> the | ||
* complete module or certain packages for reflection and will consider | ||
* such packages inaccessible. | ||
* | ||
* <p>Note that this <b>only works for Java 9 and higher</b>, 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 (<a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html#jls-6.6">JLS 11 §6.6</a>), | ||
* restrictions imposed by a {@link SecurityManager} are not considered. | ||
* | ||
* <p>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, | ||
Marcono1234 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/** | ||
* 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). | ||
Marcono1234 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* | ||
* <p>If this filter encounters a class other than a standard Java class it | ||
* returns {@link FilterResult#INDECISIVE}. | ||
* | ||
* <p>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 <b>only works for Java 9 and | ||
* higher</b>, when using an older Java version its functionality will be | ||
* limited. | ||
* | ||
* <p>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; | ||
} | ||
}; | ||
|
||
/** | ||
* Blocks all reflection access to members of standard Java classes. | ||
Marcono1234 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* | ||
* <p>If this filter encounters a class other than a standard Java class it | ||
* returns {@link FilterResult#INDECISIVE}. | ||
* | ||
* <p>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. | ||
* | ||
* <p>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; | ||
} | ||
}; | ||
|
||
/** | ||
* Blocks all reflection access to members of standard Android classes. | ||
Marcono1234 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* | ||
* <p>If this filter encounters a class other than a standard Android class it | ||
* returns {@link FilterResult#INDECISIVE}. | ||
* | ||
* <p>This filter is mainly intended to prevent depending on implementation | ||
* details of the Android platform. | ||
* | ||
* <p>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; | ||
} | ||
}; | ||
|
||
/** | ||
* Blocks all reflection access to members of classes belonging to programming | ||
* language platforms, such as Java, Android, Kotlin or Scala. | ||
Marcono1234 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* | ||
* <p>If this filter encounters a class other than a standard platform class it | ||
* returns {@link FilterResult#INDECISIVE}. | ||
* | ||
* <p>This filter is mainly intended to prevent depending on implementation | ||
* details of the platform classes. | ||
* | ||
* <p>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; | ||
} | ||
}; | ||
|
||
/** | ||
* 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); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're on Java 7 now, right? So we should be able to use
new LinkedList<>()
, and similarly in other places in the PR.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! I completely forgot that Java 7 added that feature already. Would you mind if I create a separate PR which replaces all redundant type arguments with the diamond operator, and include these changes there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems fair.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Have created #2104 for that.