Fix misuse of Drafted interface in tests. WIP fixing use of immutable collections in UPDATE/draft logic.
This commit is contained in:
parent
33d2459538
commit
7a56059036
14 changed files with 96 additions and 101 deletions
|
@ -51,15 +51,10 @@ public abstract class AbstractEntityDraft<E> implements Drafted<E> {
|
|||
} else {
|
||||
// Collections fetched from the entityMap
|
||||
if (value instanceof Collection) {
|
||||
try {
|
||||
value = MappingUtil.<T>clone(value);
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// TODO(gburd): deep?shallow? copy of List, Map, Set to a mutable collection.
|
||||
value = (T) SerializationUtils.<Serializable>clone((Serializable) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.google.common.base.Stopwatch;
|
|||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Table;
|
||||
import com.google.common.collect.TreeTraverser;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
@ -30,9 +31,9 @@ import net.helenus.core.cache.CacheUtil;
|
|||
import net.helenus.core.cache.Facet;
|
||||
import net.helenus.core.operation.AbstractOperation;
|
||||
import net.helenus.core.operation.BatchOperation;
|
||||
import net.helenus.core.reflect.Drafted;
|
||||
import net.helenus.mapping.MappingUtil;
|
||||
import net.helenus.support.Either;
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -218,15 +219,11 @@ public abstract class AbstractUnitOfWork<E extends Exception>
|
|||
result = checkParentCache(facets);
|
||||
if (result.isPresent()) {
|
||||
Object r = result.get();
|
||||
try {
|
||||
Class<?> iface = MappingUtil.getMappingInterface(r);
|
||||
if (Drafted.class.isAssignableFrom(iface)) {
|
||||
if (Helenus.entity(iface).isDraftable()) {
|
||||
cacheUpdate(r, facets);
|
||||
} else {
|
||||
cacheUpdate(MappingUtil.clone(r), facets);
|
||||
}
|
||||
} catch (CloneNotSupportedException e) {
|
||||
result = Optional.empty();
|
||||
cacheUpdate(SerializationUtils.<Serializable>clone((Serializable) r), facets);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -24,18 +24,20 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import net.helenus.core.AbstractSessionOperations;
|
||||
import net.helenus.core.Helenus;
|
||||
import net.helenus.core.UnitOfWork;
|
||||
import net.helenus.core.cache.CacheUtil;
|
||||
import net.helenus.core.cache.Facet;
|
||||
import net.helenus.core.reflect.Drafted;
|
||||
import net.helenus.mapping.MappingUtil;
|
||||
import net.helenus.support.Fun;
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
|
||||
public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOperation<E, O>>
|
||||
extends AbstractStatementOperation<E, O> {
|
||||
|
@ -153,27 +155,23 @@ public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOpe
|
|||
cachedResult = (E) sessionOps.checkCache(tableName, facets);
|
||||
if (cachedResult != null) {
|
||||
Class<?> iface = MappingUtil.getMappingInterface(cachedResult);
|
||||
try {
|
||||
if (Drafted.class.isAssignableFrom(iface)) {
|
||||
if (Helenus.entity(iface).isDraftable()) {
|
||||
result = Optional.of(cachedResult);
|
||||
} else {
|
||||
result = Optional.of(MappingUtil.clone(cachedResult));
|
||||
result =
|
||||
Optional.of(
|
||||
(E)
|
||||
SerializationUtils.<Serializable>clone(
|
||||
(Serializable) cachedResult));
|
||||
}
|
||||
sessionCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(1, 0);
|
||||
} catch (CloneNotSupportedException e) {
|
||||
result = Optional.empty();
|
||||
sessionCacheMiss.mark();
|
||||
cacheMiss.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(-1, 0);
|
||||
} finally {
|
||||
if (result.isPresent()) {
|
||||
updateCache = true;
|
||||
} else {
|
||||
updateCache = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateCache = false;
|
||||
sessionCacheMiss.mark();
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
@ -31,12 +32,13 @@ import java.util.concurrent.CompletionException;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Stream;
|
||||
import net.helenus.core.AbstractSessionOperations;
|
||||
import net.helenus.core.Helenus;
|
||||
import net.helenus.core.UnitOfWork;
|
||||
import net.helenus.core.cache.CacheUtil;
|
||||
import net.helenus.core.cache.Facet;
|
||||
import net.helenus.core.reflect.Drafted;
|
||||
import net.helenus.mapping.MappingUtil;
|
||||
import net.helenus.support.Fun;
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
|
||||
public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperation<E, O>>
|
||||
extends AbstractStatementOperation<E, O> {
|
||||
|
@ -160,27 +162,21 @@ public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperati
|
|||
if (cachedResult != null) {
|
||||
Class<?> iface = MappingUtil.getMappingInterface(cachedResult);
|
||||
E result = null;
|
||||
try {
|
||||
if (Drafted.class.isAssignableFrom(iface)) {
|
||||
if (Helenus.entity(iface).isDraftable()) {
|
||||
result = cachedResult;
|
||||
} else {
|
||||
result = MappingUtil.clone(cachedResult);
|
||||
result =
|
||||
(E) SerializationUtils.<Serializable>clone((Serializable) cachedResult);
|
||||
}
|
||||
resultStream = Stream.of(result);
|
||||
sessionCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(1, 0);
|
||||
} catch (CloneNotSupportedException e) {
|
||||
resultStream = null;
|
||||
sessionCacheMiss.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(-1, 0);
|
||||
} finally {
|
||||
if (result != null) {
|
||||
updateCache = true;
|
||||
} else {
|
||||
updateCache = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateCache = false;
|
||||
sessionCacheMiss.mark();
|
||||
|
|
|
@ -31,7 +31,6 @@ import net.helenus.core.cache.CacheUtil;
|
|||
import net.helenus.core.cache.Facet;
|
||||
import net.helenus.core.cache.UnboundFacet;
|
||||
import net.helenus.core.reflect.DefaultPrimitiveTypes;
|
||||
import net.helenus.core.reflect.Drafted;
|
||||
import net.helenus.core.reflect.HelenusPropertyNode;
|
||||
import net.helenus.core.reflect.MapExportable;
|
||||
import net.helenus.mapping.HelenusEntity;
|
||||
|
@ -211,7 +210,7 @@ public final class InsertOperation<T> extends AbstractOperation<T, InsertOperati
|
|||
|
||||
private T newInstance(Class<?> iface) {
|
||||
if (values.size() > 0) {
|
||||
boolean immutable = iface.isAssignableFrom(Drafted.class);
|
||||
boolean immutable = entity.isDraftable();
|
||||
Collection<HelenusProperty> properties = entity.getOrderedProperties();
|
||||
Map<String, Object> backingMap = new HashMap<String, Object>(properties.size());
|
||||
|
||||
|
|
|
@ -203,7 +203,9 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
|
|||
facet = new BoundFacet(prop, list);
|
||||
} else if (draft != null) {
|
||||
String key = prop.getPropertyName();
|
||||
list = (List<V>) draftMap.get(key);
|
||||
list =
|
||||
(List<V>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
|
||||
draft.put(key, list);
|
||||
list.add(0, value);
|
||||
facet = new BoundFacet(prop, list);
|
||||
} else {
|
||||
|
@ -235,7 +237,9 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
|
|||
facet = new BoundFacet(prop, list);
|
||||
} else if (draft != null && value.size() > 0) {
|
||||
String key = p.getProperty().getPropertyName();
|
||||
list = (List<V>) draftMap.get(key);
|
||||
list =
|
||||
(List<V>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
|
||||
draft.put(key, list);
|
||||
list.addAll(0, value);
|
||||
facet = new BoundFacet(prop, list);
|
||||
} else {
|
||||
|
@ -266,7 +270,10 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
|
|||
list = (List<V>) BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
|
||||
} else {
|
||||
String key = prop.getPropertyName();
|
||||
list = (List<V>) draftMap.get(key);
|
||||
list =
|
||||
(List<V>)
|
||||
new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
|
||||
draft.put(key, list);
|
||||
}
|
||||
if (idx < 0) {
|
||||
list.add(0, value);
|
||||
|
@ -305,7 +312,9 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
|
|||
facet = new BoundFacet(prop, list);
|
||||
} else if (draft != null) {
|
||||
String key = prop.getPropertyName();
|
||||
list = (List<V>) draftMap.get(key);
|
||||
list =
|
||||
(List<V>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
|
||||
draft.put(key, list);
|
||||
list.add(value);
|
||||
facet = new BoundFacet(prop, list);
|
||||
} else {
|
||||
|
@ -336,7 +345,9 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
|
|||
facet = new BoundFacet(prop, list);
|
||||
} else if (draft != null && value.size() > 0) {
|
||||
String key = prop.getPropertyName();
|
||||
list = (List<V>) draftMap.get(key);
|
||||
list =
|
||||
(List<V>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
|
||||
draft.put(key, list);
|
||||
list.addAll(value);
|
||||
facet = new BoundFacet(prop, list);
|
||||
} else {
|
||||
|
@ -367,7 +378,9 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
|
|||
facet = new BoundFacet(prop, list);
|
||||
} else if (draft != null) {
|
||||
String key = prop.getPropertyName();
|
||||
list = (List<V>) draftMap.get(key);
|
||||
list =
|
||||
(List<V>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
|
||||
draft.put(key, list);
|
||||
list.remove(value);
|
||||
facet = new BoundFacet(prop, list);
|
||||
} else {
|
||||
|
@ -398,7 +411,9 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
|
|||
facet = new BoundFacet(prop, list);
|
||||
} else if (draft != null) {
|
||||
String key = prop.getPropertyName();
|
||||
list = (List<V>) draftMap.get(key);
|
||||
list =
|
||||
(List<V>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
|
||||
draft.put(key, list);
|
||||
list.removeAll(value);
|
||||
facet = new BoundFacet(prop, list);
|
||||
} else {
|
||||
|
@ -467,7 +482,8 @@ public final class UpdateOperation<E> extends AbstractFilterOperation<E, UpdateO
|
|||
facet = new BoundFacet(prop, set);
|
||||
} else if (draft != null) {
|
||||
String key = prop.getPropertyName();
|
||||
set = (Set<V>) draftMap.get(key);
|
||||
set = (Set<V>) new HashSet<V>((Set<V>) draftMap.get(key));
|
||||
draft.put(key, set);
|
||||
set.add(value);
|
||||
facet = new BoundFacet(prop, set);
|
||||
} else {
|
||||
|
|
|
@ -34,4 +34,6 @@ public interface HelenusEntity {
|
|||
HelenusProperty getProperty(String name);
|
||||
|
||||
List<Facet> getFacets();
|
||||
|
||||
boolean isDraftable();
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ public final class HelenusMappingEntity implements HelenusEntity {
|
|||
private final HelenusEntityType type;
|
||||
private final IdentityName name;
|
||||
private final boolean cacheable;
|
||||
private final boolean draftable;
|
||||
private final ImmutableMap<String, Method> methods;
|
||||
private final ImmutableMap<String, HelenusProperty> props;
|
||||
private final ImmutableList<HelenusProperty> orderedProps;
|
||||
|
@ -112,6 +113,16 @@ public final class HelenusMappingEntity implements HelenusEntity {
|
|||
// Caching
|
||||
cacheable = (null != iface.getDeclaredAnnotation(Cacheable.class));
|
||||
|
||||
// Draft
|
||||
Class<?> draft;
|
||||
try {
|
||||
draft = Class.forName(iface.getName() + "$Draft");
|
||||
} catch (Exception ignored) {
|
||||
draft = null;
|
||||
}
|
||||
draftable = (draft != null);
|
||||
|
||||
// Materialized view
|
||||
List<HelenusProperty> primaryKeyProperties = new ArrayList<>();
|
||||
ImmutableList.Builder<Facet> facetsBuilder = ImmutableList.builder();
|
||||
if (iface.getDeclaredAnnotation(MaterializedView.class) == null) {
|
||||
|
@ -212,6 +223,11 @@ public final class HelenusMappingEntity implements HelenusEntity {
|
|||
return cacheable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDraftable() {
|
||||
return draftable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getMappingInterface() {
|
||||
return iface;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package net.helenus.mapping;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -305,28 +304,6 @@ public final class MappingUtil {
|
|||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/4882306/366692
|
||||
public static <T> T clone(T object) throws CloneNotSupportedException {
|
||||
Object clone = null;
|
||||
|
||||
// Use reflection, because there is no other way
|
||||
try {
|
||||
Method method = object.getClass().getMethod("clone");
|
||||
clone = method.invoke(object);
|
||||
} catch (InvocationTargetException e) {
|
||||
rethrow(e.getCause());
|
||||
} catch (Exception cause) {
|
||||
rethrow(cause);
|
||||
}
|
||||
if (object.getClass().isInstance(clone)) {
|
||||
@SuppressWarnings("unchecked") // clone class <= object class <= T
|
||||
T t = (T) clone;
|
||||
return t;
|
||||
} else {
|
||||
throw new ClassCastException(clone.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void rethrow(Throwable cause) throws CloneNotSupportedException {
|
||||
if (cause instanceof RuntimeException) {
|
||||
throw (RuntimeException) cause;
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.util.Collection;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import net.helenus.core.reflect.Drafted;
|
||||
import net.helenus.mapping.HelenusEntity;
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
import net.helenus.support.HelenusMappingException;
|
||||
|
@ -35,7 +34,7 @@ public final class ValueProviderMap implements Map<String, Object> {
|
|||
this.source = source;
|
||||
this.valueProvider = valueProvider;
|
||||
this.entity = entity;
|
||||
this.immutable = entity.getMappingInterface().isAssignableFrom(Drafted.class);
|
||||
this.immutable = entity.isDraftable();
|
||||
}
|
||||
|
||||
private static void throwShouldNeverCall(String methodName) {
|
||||
|
|
|
@ -9,7 +9,7 @@ import net.helenus.core.reflect.MapExportable;
|
|||
import net.helenus.mapping.annotation.*;
|
||||
|
||||
@Table
|
||||
public interface Inventory extends Entity, Drafted<Inventory> {
|
||||
public interface Inventory extends Entity {
|
||||
|
||||
static Inventory inventory = Helenus.dsl(Inventory.class);
|
||||
|
||||
|
@ -38,7 +38,7 @@ public interface Inventory extends Entity, Drafted<Inventory> {
|
|||
return new Draft(this);
|
||||
}
|
||||
|
||||
class Draft extends AbstractAuditedEntityDraft<Inventory> {
|
||||
class Draft extends AbstractAuditedEntityDraft<Inventory> implements Drafted<Inventory> {
|
||||
|
||||
// Entity/Draft pattern-enabling methods:
|
||||
Draft(UUID id) {
|
||||
|
|
|
@ -15,7 +15,7 @@ import net.helenus.mapping.annotation.*;
|
|||
|
||||
@Table
|
||||
@Cacheable
|
||||
public interface Supply extends Entity, Drafted<Supply> {
|
||||
public interface Supply extends Entity {
|
||||
|
||||
static Supply supply = Helenus.dsl(Supply.class);
|
||||
|
||||
|
@ -52,8 +52,7 @@ public interface Supply extends Entity, Drafted<Supply> {
|
|||
return new Draft(this);
|
||||
}
|
||||
|
||||
class Draft extends AbstractEntityDraft<Supply> {
|
||||
|
||||
class Draft extends AbstractEntityDraft<Supply> implements Drafted<Supply> {
|
||||
// Entity/Draft pattern-enabling methods:
|
||||
Draft(String region) {
|
||||
super(null);
|
||||
|
|
|
@ -19,6 +19,7 @@ import static net.helenus.core.Query.eq;
|
|||
|
||||
import com.datastax.driver.core.ConsistencyLevel;
|
||||
import com.datastax.driver.core.utils.UUIDs;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
import net.bytebuddy.utility.RandomString;
|
||||
|
@ -38,7 +39,7 @@ import org.junit.Test;
|
|||
|
||||
@Table
|
||||
@Cacheable
|
||||
interface Widget extends Entity {
|
||||
interface Widget extends Entity, Serializable {
|
||||
@PartitionKey
|
||||
UUID id();
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ public interface Account {
|
|||
return new Draft();
|
||||
}
|
||||
|
||||
class Draft implements Drafted { // TODO
|
||||
class Draft implements Drafted<Account> {
|
||||
|
||||
@Override
|
||||
public Set<String> mutated() {
|
||||
|
@ -47,7 +47,7 @@ public interface Account {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object build() {
|
||||
public Account build() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue