Returns the type adapter for {@code type}. <p>When calling this method concurrently from multiple threads and requesting an adapter for the same type this method may return different {@code TypeAdapter} instances. However, that should normally not be an issue because {@code TypeAdapter} implementat
(TypeToken<T> type)
| 317 | * type}. |
| 318 | */ |
| 319 | public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) { |
| 320 | Objects.requireNonNull(type, class="st">"type must not be null"); |
| 321 | TypeAdapter<?> cached = typeTokenCache.get(type); |
| 322 | if (cached != null) { |
| 323 | @SuppressWarnings(class="st">"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 | class="cm">// the key and value type parameters always agree |
| 336 | @SuppressWarnings(class="st">"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 | class="cm">// 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 | class="st">"GSON (" + GsonBuildConfig.VERSION + class="st">") 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:class="cm">//github.com/google/gson/issues/625 |
| 374 | */ |
| 375 | typeTokenCache.putAll(threadCalls); |
| 376 | } |