class RetryOperationsInterceptor implements MethodInterceptor {

	private RetryOperations retryOperations = new RetryTemplate();

	@Nullable
	private MethodInvocationRecoverer<?> recoverer;

	private String label;

	public void setLabel(String label) {
		this.label = label;
	}

	public void setRetryOperations(RetryOperations retryTemplate) {
		Assert.notNull(retryTemplate, "'retryOperations' cannot be null.");
		this.retryOperations = retryTemplate;
	}

	public void setRecoverer(MethodInvocationRecoverer<?> recoverer) {
		this.recoverer = recoverer;
	}

	@Override
	public Object invoke(final MethodInvocation invocation) throws Throwable {
		RetryCallback<Object, Throwable> retryCallback = new MethodInvocationRetryCallback<>(invocation, this.label) {

			@Override
			public Object doWithRetry(RetryContext context) throws Exception {<FILL_FUNCTION_BODY>}

		};

		RecoveryCallback<Object> recoveryCallback = (this.recoverer != null)
				? new ItemRecovererCallback(invocation.getArguments(), this.recoverer) : null;
		try {
			return this.retryOperations.execute(retryCallback, recoveryCallback);
		}
		finally {
			RetryContext context = RetrySynchronizationManager.getContext();
			if (context != null) {
				context.removeAttribute("__proxy__");
			}
		}
	}

	private record ItemRecovererCallback(Object[] args,
			MethodInvocationRecoverer<?> recoverer) implements RecoveryCallback<Object> {

		@Override
		public Object recover(RetryContext context) {
			return this.recoverer.recover(this.args, context.getLastThrowable());
		}

	}

}


				context.setAttribute(RetryContext.NAME, this.label);
				context.setAttribute("ARGS", new Args(invocation.getArguments()));

				/*
				 * If we don't copy the invocation carefully it won't keep a reference to
				 * the other interceptors in the chain. We don't have a choice here but to
				 * specialise to ReflectiveMethodInvocation (but how often would another
				 * implementation come along?).
				 */
				if (this.invocation instanceof ProxyMethodInvocation) {
					context.setAttribute("___proxy___", ((ProxyMethodInvocation) this.invocation).getProxy());
					try {
						return ((ProxyMethodInvocation) this.invocation).invocableClone().proceed();
					}
					catch (Exception | Error e) {
						throw e;
					}
					catch (Throwable e) {
						throw new IllegalStateException(e);
					}
				}
				else {
					throw new IllegalStateException(
							"MethodInvocation of the wrong type detected - this should not happen with Spring AOP, "
									+ "so please raise an issue if you see this exception");
				}
			
<no_super_class>