Returns the type adapter for type. When calling this method concurrently from multiple threads and requesting an adapter for the same type this method may return different TypeAdapter instances. However, that should normally not be an issue because TypeAdapter implementat
(TypeToken<T> type)
| 317 | * type}. |
| 318 | */ |
| 319 | public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) { |
| 320 | Objects.requireNonNull(type, "type must not be null"); |
| 321 | TypeAdapter<?> cached = typeTokenCache.get(type); |
| 322 | if (cached != null) { |
| 323 | @SuppressWarnings("unchecked") |
| 324 | TypeAdapter<T> adapter = (TypeAdapter<T>) cached; |
| 325 | return adapter; |
| 326 | } |
| 327 | |
| 328 | Map<TypeToken<?>, TypeAdapter<?>> threadCalls = threadLocalAdapterResults.get(); |
| 329 | boolean isInitialAdapterRequest = false; |
| 330 | if (threadCalls == null) { |
| 331 | threadCalls = new HashMap<>(); |
| 332 | threadLocalAdapterResults.set(threadCalls); |
| 333 | isInitialAdapterRequest = true; |
| 334 | } else { |
| 335 | // the key and value type parameters always agree |
| 336 | @SuppressWarnings("unchecked") |
| 337 | TypeAdapter<T> ongoingCall = (TypeAdapter<T>) threadCalls.get(type); |
| 338 | if (ongoingCall != null) { |
| 339 | return ongoingCall; |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | TypeAdapter<T> candidate = null; |
| 344 | try { |
| 345 | FutureTypeAdapter<T> call = new FutureTypeAdapter<>(); |
| 346 | threadCalls.put(type, call); |
| 347 | |
| 348 | for (TypeAdapterFactory factory : factories) { |
| 349 | candidate = factory.create(this, type); |
| 350 | if (candidate != null) { |
| 351 | call.setDelegate(candidate); |
| 352 | // Replace future adapter with actual adapter |
| 353 | threadCalls.put(type, candidate); |
| 354 | break; |
| 355 | } |
| 356 | } |
| 357 | } finally { |
| 358 | if (isInitialAdapterRequest) { |
| 359 | threadLocalAdapterResults.remove(); |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | if (candidate == null) { |
| 364 | throw new IllegalArgumentException( |
| 365 | "GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type); |
| 366 | } |
| 367 | |
| 368 | if (isInitialAdapterRequest) { |
| 369 | /* |
| 370 | * Publish resolved adapters to all threads |
| 371 | * Can only do this for the initial request because cyclic dependency TypeA -> TypeB -> TypeA |
| 372 | * would otherwise publish adapter for TypeB which uses not yet resolved adapter for TypeA |
| 373 | * See https://github.com/google/gson/issues/625 |
| 374 | */ |
| 375 | typeTokenCache.putAll(threadCalls); |
| 376 | } |