2 * Copyright (C) 2008 Google Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com
.google
.gson
.internal
;
19 import com
.google
.gson
.ExclusionStrategy
;
20 import com
.google
.gson
.FieldAttributes
;
21 import com
.google
.gson
.Gson
;
22 import com
.google
.gson
.TypeAdapter
;
23 import com
.google
.gson
.TypeAdapterFactory
;
24 import com
.google
.gson
.annotations
.Expose
;
25 import com
.google
.gson
.annotations
.Since
;
26 import com
.google
.gson
.annotations
.Until
;
27 import com
.google
.gson
.reflect
.TypeToken
;
28 import com
.google
.gson
.stream
.JsonReader
;
29 import com
.google
.gson
.stream
.JsonWriter
;
30 import java
.io
.IOException
;
31 import java
.lang
.reflect
.Field
;
32 import java
.lang
.reflect
.Modifier
;
33 import java
.util
.ArrayList
;
34 import java
.util
.Collections
;
35 import java
.util
.List
;
38 * This class selects which fields and types to omit. It is configurable,
39 * supporting version attributes {@link Since} and {@link Until}, modifiers,
40 * synthetic fields, anonymous and local classes, inner classes, and fields with
41 * the {@link Expose} annotation.
43 * <p>This class is a type adapter factory; types that are excluded will be
44 * adapted to null. It may delegate to another type adapter if only one
45 * direction is excluded.
48 * @author Jesse Wilson
50 public final class Excluder
implements TypeAdapterFactory
, Cloneable
{
51 private static final double IGNORE_VERSIONS
= -1.0d
;
52 public static final Excluder DEFAULT
= new Excluder();
54 private double version
= IGNORE_VERSIONS
;
55 private int modifiers
= Modifier
.TRANSIENT
| Modifier
.STATIC
;
56 private boolean serializeInnerClasses
= true;
57 private boolean requireExpose
;
58 private List
<ExclusionStrategy
> serializationStrategies
= Collections
.emptyList();
59 private List
<ExclusionStrategy
> deserializationStrategies
= Collections
.emptyList();
61 @Override protected Excluder
clone() {
63 return (Excluder
) super.clone();
64 } catch (CloneNotSupportedException e
) {
65 throw new AssertionError();
69 public Excluder
withVersion(double ignoreVersionsAfter
) {
70 Excluder result
= clone();
71 result
.version
= ignoreVersionsAfter
;
75 public Excluder
withModifiers(int... modifiers
) {
76 Excluder result
= clone();
78 for (int modifier
: modifiers
) {
79 result
.modifiers
|= modifier
;
84 public Excluder
disableInnerClassSerialization() {
85 Excluder result
= clone();
86 result
.serializeInnerClasses
= false;
90 public Excluder
excludeFieldsWithoutExposeAnnotation() {
91 Excluder result
= clone();
92 result
.requireExpose
= true;
96 public Excluder
withExclusionStrategy(ExclusionStrategy exclusionStrategy
,
97 boolean serialization
, boolean deserialization
) {
98 Excluder result
= clone();
100 result
.serializationStrategies
= new ArrayList
<ExclusionStrategy
>(serializationStrategies
);
101 result
.serializationStrategies
.add(exclusionStrategy
);
103 if (deserialization
) {
104 result
.deserializationStrategies
105 = new ArrayList
<ExclusionStrategy
>(deserializationStrategies
);
106 result
.deserializationStrategies
.add(exclusionStrategy
);
111 public <T
> TypeAdapter
<T
> create(final Gson gson
, final TypeToken
<T
> type
) {
112 Class
<?
> rawType
= type
.getRawType();
113 final boolean skipSerialize
= excludeClass(rawType
, true);
114 final boolean skipDeserialize
= excludeClass(rawType
, false);
116 if (!skipSerialize
&& !skipDeserialize
) {
120 return new TypeAdapter
<T
>() {
121 /** The delegate is lazily created because it may not be needed, and creating it may fail. */
122 private TypeAdapter
<T
> delegate
;
124 @Override public T
read(JsonReader in
) throws IOException
{
125 if (skipDeserialize
) {
129 return delegate().read(in
);
132 @Override public void write(JsonWriter out
, T value
) throws IOException
{
137 delegate().write(out
, value
);
140 private TypeAdapter
<T
> delegate() {
141 TypeAdapter
<T
> d
= delegate
;
144 : (delegate
= gson
.getDelegateAdapter(Excluder
.this, type
));
149 public boolean excludeField(Field field
, boolean serialize
) {
150 if ((modifiers
& field
.getModifiers()) != 0) {
154 if (version
!= Excluder
.IGNORE_VERSIONS
155 && !isValidVersion(field
.getAnnotation(Since
.class), field
.getAnnotation(Until
.class))) {
159 if (field
.isSynthetic()) {
164 Expose annotation
= field
.getAnnotation(Expose
.class);
165 if (annotation
== null || (serialize ?
!annotation
.serialize() : !annotation
.deserialize())) {
170 if (!serializeInnerClasses
&& isInnerClass(field
.getType())) {
174 if (isAnonymousOrLocal(field
.getType())) {
178 List
<ExclusionStrategy
> list
= serialize ? serializationStrategies
: deserializationStrategies
;
179 if (!list
.isEmpty()) {
180 FieldAttributes fieldAttributes
= new FieldAttributes(field
);
181 for (ExclusionStrategy exclusionStrategy
: list
) {
182 if (exclusionStrategy
.shouldSkipField(fieldAttributes
)) {
191 public boolean excludeClass(Class
<?
> clazz
, boolean serialize
) {
192 if (version
!= Excluder
.IGNORE_VERSIONS
193 && !isValidVersion(clazz
.getAnnotation(Since
.class), clazz
.getAnnotation(Until
.class))) {
197 if (!serializeInnerClasses
&& isInnerClass(clazz
)) {
201 if (isAnonymousOrLocal(clazz
)) {
205 List
<ExclusionStrategy
> list
= serialize ? serializationStrategies
: deserializationStrategies
;
206 for (ExclusionStrategy exclusionStrategy
: list
) {
207 if (exclusionStrategy
.shouldSkipClass(clazz
)) {
215 private boolean isAnonymousOrLocal(Class
<?
> clazz
) {
216 return !Enum
.class.isAssignableFrom(clazz
)
217 && (clazz
.isAnonymousClass() || clazz
.isLocalClass());
220 private boolean isInnerClass(Class
<?
> clazz
) {
221 return clazz
.isMemberClass() && !isStatic(clazz
);
224 private boolean isStatic(Class
<?
> clazz
) {
225 return (clazz
.getModifiers() & Modifier
.STATIC
) != 0;
228 private boolean isValidVersion(Since since
, Until until
) {
229 return isValidSince(since
) && isValidUntil(until
);
232 private boolean isValidSince(Since annotation
) {
233 if (annotation
!= null) {
234 double annotationVersion
= annotation
.value();
235 if (annotationVersion
> version
) {
242 private boolean isValidUntil(Until annotation
) {
243 if (annotation
!= null) {
244 double annotationVersion
= annotation
.value();
245 if (annotationVersion
<= version
) {