Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent running AfterSaveCallback on save

How to prevent running AfterSaveCallback on save on certain conditions (say AfterSaveCallback<Foo>). We would like to avoid triggering AfterSaveCallback even when its present and registered. How to achieve this?

Refer https://docs.spring.io/spring-data/elasticsearch/docs/4.0.1.RELEASE/api/index.html?org/springframework/data/elasticsearch/core/event/AfterSaveCallback.html

like image 231
Rpj Avatar asked Jul 21 '21 04:07

Rpj


1 Answers

AFAIK, Spring Data does not provide such functionality out-of-the-box, but you can probably achieve the desired behavior by implementing it on your own.

The AfterSaveCallback callback is invoked by the method maybeCallbackAfterSave defined in AbstractElasticsearchTemplate:

protected <T> T maybeCallbackAfterSave(T entity, IndexCoordinates index) {

  if (entityCallbacks != null) {
    return entityCallbacks.callback(AfterSaveCallback.class, entity, index);
  }

  return entity;
}

The idea is to provide a custom implementation for this method by extending ElasticsearchRestTemplate. For instance:

public class CustomElasticsearchRestTemplate extends ElasticsearchRestTemplate {

  public CustomElasticsearchRestTemplate(RestHighLevelClient client) {
    super(client);
  }

  public CustomElasticsearchRestTemplate(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter) {
    super(client, elasticsearchConverter);
  }

  @Override
  protected <T> T maybeCallbackAfterSave(T entity, IndexCoordinates index) {
    // compute as necessary
    boolean shouldSkipCallback = ...; 
    // if the conditions are met for the callback not to be applied,
    // just return the entity
    if (shouldSkipCallback) {
      return entity;
    }
  
    // else, proceed with the default implementation
    return super.maybeCallbackAfterSave(entity);
  }
}

Depending on the use case an anonymous class that overwrites maybeCallbackAfterSave will be suitable as well.

Then, use this custom ElasticsearchRestTemplate on its own or register it as the application default in the way you consider appropriate, for example, by extending AbstractElasticsearchConfiguration - see this great article - or by providing your own configuration directly - see this for an example.

The solution has a drawback, which is dealing with the generic T entity argument. For that purpose it may be of help and we can take as reference the code defined in DefaultEntityCallbacks defined for the callback processing, especially this lines:

Class<T> entityType = (Class<T>) (entity != null ? ClassUtils.getUserClass(entity.getClass())
                : callbackDiscoverer.resolveDeclaredEntityType(callbackType).getRawClass());

As you can see they use the functionality implemented in ClassUtils in order to detect the actual class type.

Maybe you can take advantage of this knowledge and do something similar to the following code to determine if the callback should be or not applied:

// Determine the class using one Spring magic
Class<T> entityType = (Class<T>) 
ClassUtils.getUserClass(entity.getClass());
// Then, compare with the appropriate types that should be excluded
boolean shouldSkipCallback = entityType.isAssignableFrom(Foo.class);

As an alternative, you can provide the class of the parameterized type T information to your AfterSaveCallback<T> implementation: this will allow you to determine whether the callback should or not applied based on the concrete class upon the onAfterSave method invocation.

like image 104
jccampanero Avatar answered Oct 19 '22 12:10

jccampanero