EntityIsManagedByPersisterAsserter.java
package org.codefilarete.stalactite.engine.runtime;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.codefilarete.tool.Duo;
import org.codefilarete.tool.Reflections;
import org.codefilarete.tool.VisibleForTesting;
import org.codefilarete.tool.collection.Iterables;
/**
* Persister which checks that given instances can be persisted by itself, throws exception if that's not the case.
* Done in particular for inheritance cases where subtypes may have not been mapped but their entities are accepted (due to usual inheritance), this
* would have resulted in partial persistence : only common (upper) part was took into account without warning user.
*
* Designed as a wrapper of an underlying delegate which really persists instances. Made as such for single responsibility consideration.
*
* @author Guillaume Mary
*/
public class EntityIsManagedByPersisterAsserter<C, I> extends PersisterWrapper<C, I> {
private final Consumer<C> asserter;
public EntityIsManagedByPersisterAsserter(ConfiguredRelationalPersister<C, I> delegate) {
super(delegate);
if (getDeepestDelegate() instanceof PolymorphicPersister) {
Set<Class<? extends C>> supportedEntityTypes = ((PolymorphicPersister<C>) getDeepestDelegate()).getSupportedEntityTypes();
asserter = entity -> {
if (!supportedEntityTypes.contains(entity.getClass())) {
throw newAssertException(entity);
}
};
} else {
asserter = entity -> {
if (!getClassToPersist().equals(entity.getClass()))
throw newAssertException(entity);
};
}
}
private UnsupportedOperationException newAssertException(C entity) {
return new UnsupportedOperationException("Persister of " + Reflections.toString(getClassToPersist())
+ " is not configured to persist " + Reflections.toString(entity.getClass()));
}
@VisibleForTesting
void assertPersisterManagesEntities(Iterable<? extends C> entity) {
entity.forEach(this::assertPersisterManagesEntity);
}
@VisibleForTesting
void assertPersisterManagesEntity(C entity) {
asserter.accept(entity);
}
/* Please note that some methods were not overridden for calling assertion because the super implementation invokes some methods that do it,
* hence in such a way we avoid multiple calls to assertion. Meanwhile, a Unit Test checks all of them.
* Here they are:
* - persist(entity)
* - insert(C entity)
* - update(C modified, C unmodified, boolean allColumnsStatement)
* - update(C entity)
* - update(Iterable<C> entities)
* - updateById(C entity)
* - delete(C entity)
* - deleteById(C entity)
*/
@Override
public void persist(Iterable<? extends C> entities) {
assertPersisterManagesEntities(entities);
super.persist(entities);
}
@Override
public void insert(Iterable<? extends C> entities) {
assertPersisterManagesEntities(entities);
super.insert(entities);
}
@Override
public void update(Iterable<? extends Duo<C, C>> differencesIterable, boolean allColumnsStatement) {
// we clear asserter input from null because it doesn't support it, and it may happen in update cases of nullified one-to-one relation
List<C> nonNullEntities = Iterables.stream(differencesIterable).map(Duo::getLeft).filter(Objects::nonNull).collect(Collectors.toList());
assertPersisterManagesEntities(nonNullEntities);
super.update(differencesIterable, allColumnsStatement);
}
@Override
public void updateById(Iterable<? extends C> entities) {
assertPersisterManagesEntities(entities);
super.updateById(entities);
}
@Override
public void delete(Iterable<? extends C> entities) {
// we clear asserter input from null because it doesn't support it, and it may happen in update cases of nullified one-to-one relation
List<C> nonNullEntities = Iterables.stream(entities).filter(Objects::nonNull).collect(Collectors.toList());
assertPersisterManagesEntities(nonNullEntities);
super.delete(nonNullEntities);
}
@Override
public void deleteById(Iterable<? extends C> entities) {
assertPersisterManagesEntities(entities);
super.deleteById(entities);
}
}