DATACMNS-1260 - Extract EvaluationContextProvider and corresponding SPIs into dedicated package.

We now have a refined replica of the EvaluationContextProvider API and SPIs in the org.springframework.data.spel package. It has seen a bit of a Java 8 overhaul by removing the SPI support class in favor of turning most methods in EvaluationContextExtension into default ones.

The already existing API has been renamed to QueryMethodEvaluationContextProvider to indicate it's working with additional semantics specific to query methods (i.e. the Parameters metadata). The internals have been refactored to use the new API but still detect implementations of the old EvaluationContextExtension interface. The implementations get wrapped into an adapting proxy to satisfy the new API so that the actual inspection and usage of the extension is now already done using the new APIs.

The repository configuration has slightly change so that the creation of the EvaluationContextProvider is now taking place within RepositoryFactoryBeanSupport's implementation of BeanFactoryAware.

AbstractMappingContext is now ApplicationContextAware and holds an ExtensionAwareEvaluationContextProvider using the configured ApplicationContext. That EvaluationContextProvider is forwarded to all MutablePersistentEntity instances. BasicPersistentEntity now exposes getEvaluationContext(…) to subclasses to easily create an EvaluationContext using the extension aware infrastructure.

Removed DefaultEvaluationContextProvider in favor of a simple constant in QueryMethodEvaluationContextProvider.

Related tickets: DATACMNS-1258, DATACMNS-1108.
This commit is contained in:
Oliver Gierke
2018-02-14 19:05:59 +01:00
parent 90337535d1
commit a6215fbe0f
25 changed files with 707 additions and 171 deletions

View File

@@ -37,6 +37,8 @@ import java.util.stream.Collectors;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.mapping.MappingException;
@@ -50,6 +52,8 @@ import org.springframework.data.mapping.model.MutablePersistentEntity;
import org.springframework.data.mapping.model.PersistentPropertyAccessorFactory;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.spel.EvaluationContextProvider;
import org.springframework.data.spel.ExtensionAwareEvaluationContextProvider;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.Optionals;
import org.springframework.data.util.Streamable;
@@ -79,7 +83,7 @@ import org.springframework.util.ReflectionUtils.FieldFilter;
* @author Christoph Strobl
*/
public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?, P>, P extends PersistentProperty<P>>
implements MappingContext<E, P>, ApplicationEventPublisherAware, InitializingBean {
implements MappingContext<E, P>, ApplicationEventPublisherAware, ApplicationContextAware, InitializingBean {
private final Optional<E> NONE = Optional.empty();
private final Map<TypeInformation<?>, Optional<E>> persistentEntities = new HashMap<>();
@@ -87,6 +91,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
private final PersistentPropertyPathFactory<E, P> persistentPropertyPathFactory;
private @Nullable ApplicationEventPublisher applicationEventPublisher;
private EvaluationContextProvider evaluationContextProvider = EvaluationContextProvider.DEFAULT;
private Set<? extends Class<?>> initialEntitySet = new HashSet<>();
private boolean strict = false;
@@ -109,6 +114,20 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
this.applicationEventPublisher = applicationEventPublisher;
}
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.evaluationContextProvider = new ExtensionAwareEvaluationContextProvider(applicationContext);
if (applicationEventPublisher == null) {
this.applicationEventPublisher = applicationContext;
}
}
/**
* Sets the {@link Set} of types to populate the context initially.
*
@@ -346,6 +365,8 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
entity = createPersistentEntity(typeInformation);
entity.setEvaluationContextProvider(evaluationContextProvider);
// Eagerly cache the entity as we might have to find it during recursive lookups.
persistentEntities.put(typeInformation, Optional.of(entity));

View File

@@ -47,8 +47,10 @@ import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.SimpleAssociationHandler;
import org.springframework.data.mapping.SimplePropertyHandler;
import org.springframework.data.mapping.TargetAwareIdentifierAccessor;
import org.springframework.data.spel.EvaluationContextProvider;
import org.springframework.data.util.Lazy;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.EvaluationContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -84,6 +86,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
private @Nullable P idProperty;
private @Nullable P versionProperty;
private PersistentPropertyAccessorFactory propertyAccessorFactory;
private EvaluationContextProvider evaluationContextProvider = EvaluationContextProvider.DEFAULT;
private final Lazy<Alias> typeAlias;
@@ -240,6 +243,15 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.MutablePersistentEntity#setEvaluationContextProvider(org.springframework.data.spel.EvaluationContextProvider)
*/
@Override
public void setEvaluationContextProvider(EvaluationContextProvider provider) {
this.evaluationContextProvider = provider;
}
/**
* Returns the given property if it is a better candidate for the id property than the current id property.
*
@@ -464,11 +476,19 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
return hasIdProperty() ? new IdPropertyIdentifierAccessor(this, bean) : new AbsentIdentifierAccessor(bean);
}
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<P> iterator() {
return Collections.unmodifiableList(properties).iterator();
}
protected EvaluationContext getEvaluationContext(Object rootObject) {
return evaluationContextProvider.getEvaluationContext(rootObject);
}
/**
* Calculates the {@link Alias} to be used for the given type.
*

View File

@@ -20,6 +20,7 @@ import org.springframework.data.mapping.MappingException;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.spel.EvaluationContextProvider;
/**
* Interface capturing mutator methods for {@link PersistentEntity}s.
@@ -58,4 +59,11 @@ public interface MutablePersistentEntity<T, P extends PersistentProperty<P>> ext
* @param factory must not be {@literal null}.
*/
void setPersistentPropertyAccessorFactory(PersistentPropertyAccessorFactory factory);
/**
* Sets the {@link EvaluationContextProvider} to be used by the entity.
*
* @param provider must not be {@literal null}.
*/
void setEvaluationContextProvider(EvaluationContextProvider provider);
}