Finish second-to-last commit
[unical.git] / gson / com / google / gson / internal / Excluder.java
1 /*
2 * Copyright (C) 2008 Google Inc.
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 package com.google.gson.internal;
18
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;
36
37 /**
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.
42 *
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.
46 *
47 * @author Joel Leitch
48 * @author Jesse Wilson
49 */
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();
53
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();
60
61 @Override protected Excluder clone() {
62 try {
63 return (Excluder) super.clone();
64 } catch (CloneNotSupportedException e) {
65 throw new AssertionError();
66 }
67 }
68
69 public Excluder withVersion(double ignoreVersionsAfter) {
70 Excluder result = clone();
71 result.version = ignoreVersionsAfter;
72 return result;
73 }
74
75 public Excluder withModifiers(int... modifiers) {
76 Excluder result = clone();
77 result.modifiers = 0;
78 for (int modifier : modifiers) {
79 result.modifiers |= modifier;
80 }
81 return result;
82 }
83
84 public Excluder disableInnerClassSerialization() {
85 Excluder result = clone();
86 result.serializeInnerClasses = false;
87 return result;
88 }
89
90 public Excluder excludeFieldsWithoutExposeAnnotation() {
91 Excluder result = clone();
92 result.requireExpose = true;
93 return result;
94 }
95
96 public Excluder withExclusionStrategy(ExclusionStrategy exclusionStrategy,
97 boolean serialization, boolean deserialization) {
98 Excluder result = clone();
99 if (serialization) {
100 result.serializationStrategies = new ArrayList<ExclusionStrategy>(serializationStrategies);
101 result.serializationStrategies.add(exclusionStrategy);
102 }
103 if (deserialization) {
104 result.deserializationStrategies
105 = new ArrayList<ExclusionStrategy>(deserializationStrategies);
106 result.deserializationStrategies.add(exclusionStrategy);
107 }
108 return result;
109 }
110
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);
115
116 if (!skipSerialize && !skipDeserialize) {
117 return null;
118 }
119
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;
123
124 @Override public T read(JsonReader in) throws IOException {
125 if (skipDeserialize) {
126 in.skipValue();
127 return null;
128 }
129 return delegate().read(in);
130 }
131
132 @Override public void write(JsonWriter out, T value) throws IOException {
133 if (skipSerialize) {
134 out.nullValue();
135 return;
136 }
137 delegate().write(out, value);
138 }
139
140 private TypeAdapter<T> delegate() {
141 TypeAdapter<T> d = delegate;
142 return d != null
143 ? d
144 : (delegate = gson.getDelegateAdapter(Excluder.this, type));
145 }
146 };
147 }
148
149 public boolean excludeField(Field field, boolean serialize) {
150 if ((modifiers & field.getModifiers()) != 0) {
151 return true;
152 }
153
154 if (version != Excluder.IGNORE_VERSIONS
155 && !isValidVersion(field.getAnnotation(Since.class), field.getAnnotation(Until.class))) {
156 return true;
157 }
158
159 if (field.isSynthetic()) {
160 return true;
161 }
162
163 if (requireExpose) {
164 Expose annotation = field.getAnnotation(Expose.class);
165 if (annotation == null || (serialize ? !annotation.serialize() : !annotation.deserialize())) {
166 return true;
167 }
168 }
169
170 if (!serializeInnerClasses && isInnerClass(field.getType())) {
171 return true;
172 }
173
174 if (isAnonymousOrLocal(field.getType())) {
175 return true;
176 }
177
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)) {
183 return true;
184 }
185 }
186 }
187
188 return false;
189 }
190
191 public boolean excludeClass(Class<?> clazz, boolean serialize) {
192 if (version != Excluder.IGNORE_VERSIONS
193 && !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) {
194 return true;
195 }
196
197 if (!serializeInnerClasses && isInnerClass(clazz)) {
198 return true;
199 }
200
201 if (isAnonymousOrLocal(clazz)) {
202 return true;
203 }
204
205 List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;
206 for (ExclusionStrategy exclusionStrategy : list) {
207 if (exclusionStrategy.shouldSkipClass(clazz)) {
208 return true;
209 }
210 }
211
212 return false;
213 }
214
215 private boolean isAnonymousOrLocal(Class<?> clazz) {
216 return !Enum.class.isAssignableFrom(clazz)
217 && (clazz.isAnonymousClass() || clazz.isLocalClass());
218 }
219
220 private boolean isInnerClass(Class<?> clazz) {
221 return clazz.isMemberClass() && !isStatic(clazz);
222 }
223
224 private boolean isStatic(Class<?> clazz) {
225 return (clazz.getModifiers() & Modifier.STATIC) != 0;
226 }
227
228 private boolean isValidVersion(Since since, Until until) {
229 return isValidSince(since) && isValidUntil(until);
230 }
231
232 private boolean isValidSince(Since annotation) {
233 if (annotation != null) {
234 double annotationVersion = annotation.value();
235 if (annotationVersion > version) {
236 return false;
237 }
238 }
239 return true;
240 }
241
242 private boolean isValidUntil(Until annotation) {
243 if (annotation != null) {
244 double annotationVersion = annotation.value();
245 if (annotationVersion <= version) {
246 return false;
247 }
248 }
249 return true;
250 }
251 }
This page took 0.029073 seconds and 4 git commands to generate.