Skip to content

Commit 2dc29f7

Browse files
Replace anonymous class creation with lambdas in ConstructorConstructor (#2763)
Replace anonymous class creation with lambdas in ConstructorConstructor Replace anonymous class creation with lambdas in ConstructorConstructor Replace anonymous class creation with lambdas in ConstructorConstructor Co-authored-by: Éamonn McManus <[email protected]>
1 parent 73768be commit 2dc29f7

File tree

1 file changed

+79
-161
lines changed

1 file changed

+79
-161
lines changed

gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java

Lines changed: 79 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -103,24 +103,14 @@ public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {
103103
@SuppressWarnings("unchecked") // types must agree
104104
InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);
105105
if (typeCreator != null) {
106-
return new ObjectConstructor<T>() {
107-
@Override
108-
public T construct() {
109-
return typeCreator.createInstance(type);
110-
}
111-
};
106+
return () -> typeCreator.createInstance(type);
112107
}
113108

114109
// Next try raw type match for instance creators
115110
@SuppressWarnings("unchecked") // types must agree
116111
InstanceCreator<T> rawTypeCreator = (InstanceCreator<T>) instanceCreators.get(rawType);
117112
if (rawTypeCreator != null) {
118-
return new ObjectConstructor<T>() {
119-
@Override
120-
public T construct() {
121-
return rawTypeCreator.createInstance(type);
122-
}
123-
};
113+
return () -> rawTypeCreator.createInstance(type);
124114
}
125115

126116
// First consider special constructors before checking for no-args constructors
@@ -147,11 +137,8 @@ public T construct() {
147137
// of adjusting filter suggested below is irrelevant since it would not solve the problem
148138
String exceptionMessage = checkInstantiable(rawType);
149139
if (exceptionMessage != null) {
150-
return new ObjectConstructor<T>() {
151-
@Override
152-
public T construct() {
153-
throw new JsonIOException(exceptionMessage);
154-
}
140+
return () -> {
141+
throw new JsonIOException(exceptionMessage);
155142
};
156143
}
157144

@@ -167,11 +154,8 @@ public T construct() {
167154
+ "; ReflectionAccessFilter does not permit using reflection or Unsafe. Register an"
168155
+ " InstanceCreator or a TypeAdapter for this type or adjust the access filter to"
169156
+ " allow using reflection.";
170-
return new ObjectConstructor<T>() {
171-
@Override
172-
public T construct() {
173-
throw new JsonIOException(message);
174-
}
157+
return () -> {
158+
throw new JsonIOException(message);
175159
};
176160
}
177161
}
@@ -183,42 +167,36 @@ public T construct() {
183167
private static <T> ObjectConstructor<T> newSpecialCollectionConstructor(
184168
Type type, Class<? super T> rawType) {
185169
if (EnumSet.class.isAssignableFrom(rawType)) {
186-
return new ObjectConstructor<T>() {
187-
@Override
188-
public T construct() {
189-
if (type instanceof ParameterizedType) {
190-
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
191-
if (elementType instanceof Class) {
192-
@SuppressWarnings({"unchecked", "rawtypes"})
193-
T set = (T) EnumSet.noneOf((Class) elementType);
194-
return set;
195-
} else {
196-
throw new JsonIOException("Invalid EnumSet type: " + type.toString());
197-
}
170+
return () -> {
171+
if (type instanceof ParameterizedType) {
172+
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
173+
if (elementType instanceof Class) {
174+
@SuppressWarnings({"unchecked", "rawtypes"})
175+
T set = (T) EnumSet.noneOf((Class) elementType);
176+
return set;
198177
} else {
199178
throw new JsonIOException("Invalid EnumSet type: " + type.toString());
200179
}
180+
} else {
181+
throw new JsonIOException("Invalid EnumSet type: " + type.toString());
201182
}
202183
};
203184
}
204185
// Only support creation of EnumMap, but not of custom subtypes; for them type parameters
205186
// and constructor parameter might have completely different meaning
206187
else if (rawType == EnumMap.class) {
207-
return new ObjectConstructor<T>() {
208-
@Override
209-
public T construct() {
210-
if (type instanceof ParameterizedType) {
211-
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
212-
if (elementType instanceof Class) {
213-
@SuppressWarnings({"unchecked", "rawtypes"})
214-
T map = (T) new EnumMap((Class) elementType);
215-
return map;
216-
} else {
217-
throw new JsonIOException("Invalid EnumMap type: " + type.toString());
218-
}
188+
return () -> {
189+
if (type instanceof ParameterizedType) {
190+
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
191+
if (elementType instanceof Class) {
192+
@SuppressWarnings({"unchecked", "rawtypes"})
193+
T map = (T) new EnumMap((Class) elementType);
194+
return map;
219195
} else {
220196
throw new JsonIOException("Invalid EnumMap type: " + type.toString());
221197
}
198+
} else {
199+
throw new JsonIOException("Invalid EnumMap type: " + type.toString());
222200
}
223201
};
224202
}
@@ -256,11 +234,8 @@ private static <T> ObjectConstructor<T> newDefaultConstructor(
256234
+ " constructor is not accessible and ReflectionAccessFilter does not permit making"
257235
+ " it accessible. Register an InstanceCreator or a TypeAdapter for this type, change"
258236
+ " the visibility of the constructor or adjust the access filter.";
259-
return new ObjectConstructor<T>() {
260-
@Override
261-
public T construct() {
262-
throw new JsonIOException(message);
263-
}
237+
return () -> {
238+
throw new JsonIOException(message);
264239
};
265240
}
266241

@@ -277,45 +252,39 @@ public T construct() {
277252
* (compared to directly throwing exception here), e.g. when runtime type
278253
* of object is inaccessible, but compile-time type is accessible.
279254
*/
280-
return new ObjectConstructor<T>() {
281-
@Override
282-
public T construct() {
283-
// New exception is created every time to avoid keeping reference
284-
// to exception with potentially long stack trace, causing a
285-
// memory leak
286-
throw new JsonIOException(exceptionMessage);
287-
}
255+
return () -> {
256+
// New exception is created every time to avoid keeping reference
257+
// to exception with potentially long stack trace, causing a
258+
// memory leak
259+
throw new JsonIOException(exceptionMessage);
288260
};
289261
}
290262
}
291263

292-
return new ObjectConstructor<T>() {
293-
@Override
294-
public T construct() {
295-
try {
296-
@SuppressWarnings("unchecked") // T is the same raw type as is requested
297-
T newInstance = (T) constructor.newInstance();
298-
return newInstance;
299-
}
300-
// Note: InstantiationException should be impossible because check at start of method made
301-
// sure that class is not abstract
302-
catch (InstantiationException e) {
303-
throw new RuntimeException(
304-
"Failed to invoke constructor '"
305-
+ ReflectionHelper.constructorToString(constructor)
306-
+ "' with no args",
307-
e);
308-
} catch (InvocationTargetException e) {
309-
// TODO: don't wrap if cause is unchecked?
310-
// TODO: JsonParseException ?
311-
throw new RuntimeException(
312-
"Failed to invoke constructor '"
313-
+ ReflectionHelper.constructorToString(constructor)
314-
+ "' with no args",
315-
e.getCause());
316-
} catch (IllegalAccessException e) {
317-
throw ReflectionHelper.createExceptionForUnexpectedIllegalAccess(e);
318-
}
264+
return () -> {
265+
try {
266+
@SuppressWarnings("unchecked") // T is the same raw type as is requested
267+
T newInstance = (T) constructor.newInstance();
268+
return newInstance;
269+
}
270+
// Note: InstantiationException should be impossible because check at start of method made
271+
// sure that class is not abstract
272+
catch (InstantiationException e) {
273+
throw new RuntimeException(
274+
"Failed to invoke constructor '"
275+
+ ReflectionHelper.constructorToString(constructor)
276+
+ "' with no args",
277+
e);
278+
} catch (InvocationTargetException e) {
279+
// TODO: don't wrap if cause is unchecked?
280+
// TODO: JsonParseException ?
281+
throw new RuntimeException(
282+
"Failed to invoke constructor '"
283+
+ ReflectionHelper.constructorToString(constructor)
284+
+ "' with no args",
285+
e.getCause());
286+
} catch (IllegalAccessException e) {
287+
throw ReflectionHelper.createExceptionForUnexpectedIllegalAccess(e);
319288
}
320289
};
321290
}
@@ -335,74 +304,29 @@ private static <T> ObjectConstructor<T> newDefaultImplementationConstructor(
335304

336305
if (Collection.class.isAssignableFrom(rawType)) {
337306
if (SortedSet.class.isAssignableFrom(rawType)) {
338-
return new ObjectConstructor<T>() {
339-
@Override
340-
public T construct() {
341-
return (T) new TreeSet<>();
342-
}
343-
};
307+
return () -> (T) new TreeSet<>();
344308
} else if (Set.class.isAssignableFrom(rawType)) {
345-
return new ObjectConstructor<T>() {
346-
@Override
347-
public T construct() {
348-
return (T) new LinkedHashSet<>();
349-
}
350-
};
309+
return () -> (T) new LinkedHashSet<>();
351310
} else if (Queue.class.isAssignableFrom(rawType)) {
352-
return new ObjectConstructor<T>() {
353-
@Override
354-
public T construct() {
355-
return (T) new ArrayDeque<>();
356-
}
357-
};
311+
return () -> (T) new ArrayDeque<>();
358312
} else {
359-
return new ObjectConstructor<T>() {
360-
@Override
361-
public T construct() {
362-
return (T) new ArrayList<>();
363-
}
364-
};
313+
return () -> (T) new ArrayList<>();
365314
}
366315
}
367316

368317
if (Map.class.isAssignableFrom(rawType)) {
369318
if (ConcurrentNavigableMap.class.isAssignableFrom(rawType)) {
370-
return new ObjectConstructor<T>() {
371-
@Override
372-
public T construct() {
373-
return (T) new ConcurrentSkipListMap<>();
374-
}
375-
};
319+
return () -> (T) new ConcurrentSkipListMap<>();
376320
} else if (ConcurrentMap.class.isAssignableFrom(rawType)) {
377-
return new ObjectConstructor<T>() {
378-
@Override
379-
public T construct() {
380-
return (T) new ConcurrentHashMap<>();
381-
}
382-
};
321+
return () -> (T) new ConcurrentHashMap<>();
383322
} else if (SortedMap.class.isAssignableFrom(rawType)) {
384-
return new ObjectConstructor<T>() {
385-
@Override
386-
public T construct() {
387-
return (T) new TreeMap<>();
388-
}
389-
};
323+
return () -> (T) new TreeMap<>();
390324
} else if (type instanceof ParameterizedType
391325
&& !String.class.isAssignableFrom(
392326
TypeToken.get(((ParameterizedType) type).getActualTypeArguments()[0]).getRawType())) {
393-
return new ObjectConstructor<T>() {
394-
@Override
395-
public T construct() {
396-
return (T) new LinkedHashMap<>();
397-
}
398-
};
327+
return () -> (T) new LinkedHashMap<>();
399328
} else {
400-
return new ObjectConstructor<T>() {
401-
@Override
402-
public T construct() {
403-
return (T) new LinkedTreeMap<>();
404-
}
405-
};
329+
return () -> (T) new LinkedTreeMap<>();
406330
}
407331
}
408332

@@ -411,21 +335,18 @@ public T construct() {
411335

412336
private <T> ObjectConstructor<T> newUnsafeAllocator(Class<? super T> rawType) {
413337
if (useJdkUnsafe) {
414-
return new ObjectConstructor<T>() {
415-
@Override
416-
public T construct() {
417-
try {
418-
@SuppressWarnings("unchecked")
419-
T newInstance = (T) UnsafeAllocator.INSTANCE.newInstance(rawType);
420-
return newInstance;
421-
} catch (Exception e) {
422-
throw new RuntimeException(
423-
("Unable to create instance of "
424-
+ rawType
425-
+ ". Registering an InstanceCreator or a TypeAdapter for this type, or adding a"
426-
+ " no-args constructor may fix this problem."),
427-
e);
428-
}
338+
return () -> {
339+
try {
340+
@SuppressWarnings("unchecked")
341+
T newInstance = (T) UnsafeAllocator.INSTANCE.newInstance(rawType);
342+
return newInstance;
343+
} catch (Exception e) {
344+
throw new RuntimeException(
345+
("Unable to create instance of "
346+
+ rawType
347+
+ ". Registering an InstanceCreator or a TypeAdapter for this type, or adding a"
348+
+ " no-args constructor may fix this problem."),
349+
e);
429350
}
430351
};
431352
} else {
@@ -444,14 +365,11 @@ public T construct() {
444365
" Or adjust your R8 configuration to keep the no-args constructor of the class.";
445366
}
446367

447-
// Separate effectively final variable to allow usage in the anonymous class below
368+
// Separate effectively final variable to allow usage in the lambda below
448369
String exceptionMessageF = exceptionMessage;
449370

450-
return new ObjectConstructor<T>() {
451-
@Override
452-
public T construct() {
453-
throw new JsonIOException(exceptionMessageF);
454-
}
371+
return () -> {
372+
throw new JsonIOException(exceptionMessageF);
455373
};
456374
}
457375
}

0 commit comments

Comments
 (0)