@@ -212,38 +212,53 @@ private void validateServiceInterface(Class<?> service) {
212
212
}
213
213
214
214
ServiceMethod <?> loadServiceMethod (Class <?> service , Method method ) {
215
- // Note: Once we are minSdk 24 this whole method can be replaced by computeIfAbsent.
216
- Object lookup = serviceMethodCache .get (method );
215
+ while (true ) {
216
+ // Note: Once we are minSdk 24 this whole method can be replaced by computeIfAbsent.
217
+ Object lookup = serviceMethodCache .get (method );
217
218
218
- if (lookup instanceof ServiceMethod <?>) {
219
- // Happy path: method is already parsed into the model.
220
- return (ServiceMethod <?>) lookup ;
221
- }
219
+ if (lookup instanceof ServiceMethod <?>) {
220
+ // Happy path: method is already parsed into the model.
221
+ return (ServiceMethod <?>) lookup ;
222
+ }
222
223
223
- if (lookup == null ) {
224
- // Map does not contain any value. Try to put in a lock for this method. We MUST synchronize
225
- // on the lock before it is visible to others via the map to signal we are doing the work.
226
- Object lock = new Object ();
227
- synchronized (lock ) {
228
- lookup = serviceMethodCache .putIfAbsent (method , lock );
229
- if (lookup == null ) {
230
- // On successful lock insertion, perform the work and update the map before releasing.
231
- // Other threads may be waiting on lock now and will expect the parsed model.
232
- ServiceMethod <Object > result = ServiceMethod .parseAnnotations (this , service , method );
233
- serviceMethodCache .put (method , result );
234
- return result ;
224
+ if (lookup == null ) {
225
+ // Map does not contain any value. Try to put in a lock for this method. We MUST synchronize
226
+ // on the lock before it is visible to others via the map to signal we are doing the work.
227
+ Object lock = new Object ();
228
+ synchronized (lock ) {
229
+ lookup = serviceMethodCache .putIfAbsent (method , lock );
230
+ if (lookup == null ) {
231
+ // On successful lock insertion, perform the work and update the map before releasing.
232
+ // Other threads may be waiting on lock now and will expect the parsed model.
233
+ ServiceMethod <Object > result ;
234
+ try {
235
+ result = ServiceMethod .parseAnnotations (this , service , method );
236
+ } catch (Throwable e ) {
237
+ // Remove the lock on failure. Any other locked threads will retry as a result.
238
+ serviceMethodCache .remove (method );
239
+ throw e ;
240
+ }
241
+ serviceMethodCache .put (method , result );
242
+ return result ;
243
+ }
235
244
}
236
245
}
237
- }
238
246
239
- // Either the initial lookup or the attempt to put our lock in the map has returned someone
240
- // else's lock. This means they are doing the parsing, and will update the map before releasing
241
- // the lock. Once we can take the lock, the map is guaranteed to contain the model.
242
- // Note: There's a chance that our effort to put a lock into the map has actually returned a
243
- // finished model instead of a lock. In that case this code will perform a pointless lock and
244
- // redundant lookup in the map of the same instance. This is rare, and ultimately harmless.
245
- synchronized (lookup ) {
246
- return (ServiceMethod <?>) serviceMethodCache .get (method );
247
+ // Either the initial lookup or the attempt to put our lock in the map has returned someone
248
+ // else's lock. This means they are doing the parsing, and will update the map before
249
+ // releasing
250
+ // the lock. Once we can take the lock, the map is guaranteed to contain the model or null.
251
+ // Note: There's a chance that our effort to put a lock into the map has actually returned a
252
+ // finished model instead of a lock. In that case this code will perform a pointless lock and
253
+ // redundant lookup in the map of the same instance. This is rare, and ultimately harmless.
254
+ synchronized (lookup ) {
255
+ Object result = serviceMethodCache .get (method );
256
+ if (result == null ) {
257
+ // The other thread failed its parsing. We will retry (and probably also fail).
258
+ continue ;
259
+ }
260
+ return (ServiceMethod <?>) result ;
261
+ }
247
262
}
248
263
}
249
264
0 commit comments