Fix misuse of Drafted interface in tests. WIP fixing use of immutable collections in UPDATE/draft logic.

This commit is contained in:
Greg Burd 2017-11-13 15:55:24 -05:00
parent 33d2459538
commit 7a56059036
14 changed files with 96 additions and 101 deletions

View file

@ -51,12 +51,7 @@ 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);
}
value = (T) SerializationUtils.<Serializable>clone((Serializable) value);
}
}
}

View file

@ -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)) {
cacheUpdate(r, facets);
} else {
cacheUpdate(MappingUtil.clone(r), facets);
}
} catch (CloneNotSupportedException e) {
result = Optional.empty();
Class<?> iface = MappingUtil.getMappingInterface(r);
if (Helenus.entity(iface).isDraftable()) {
cacheUpdate(r, facets);
} else {
cacheUpdate(SerializationUtils.<Serializable>clone((Serializable) r), facets);
}
}
return result;

View file

@ -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,26 +155,22 @@ 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)) {
result = Optional.of(cachedResult);
} else {
result = Optional.of(MappingUtil.clone(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;
}
if (Helenus.entity(iface).isDraftable()) {
result = Optional.of(cachedResult);
} else {
result =
Optional.of(
(E)
SerializationUtils.<Serializable>clone(
(Serializable) cachedResult));
}
sessionCacheHits.mark();
cacheHits.mark();
uow.recordCacheAndDatabaseOperationCount(1, 0);
if (result.isPresent()) {
updateCache = true;
} else {
updateCache = false;
}
} else {
updateCache = false;

View file

@ -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,26 +162,20 @@ 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)) {
result = cachedResult;
} else {
result = MappingUtil.clone(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;
}
if (Helenus.entity(iface).isDraftable()) {
result = cachedResult;
} else {
result =
(E) SerializationUtils.<Serializable>clone((Serializable) cachedResult);
}
resultStream = Stream.of(result);
sessionCacheHits.mark();
cacheHits.mark();
uow.recordCacheAndDatabaseOperationCount(1, 0);
if (result != null) {
updateCache = true;
} else {
updateCache = false;
}
} else {
updateCache = false;

View file

@ -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());

View file

@ -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 {

View file

@ -34,4 +34,6 @@ public interface HelenusEntity {
HelenusProperty getProperty(String name);
List<Facet> getFacets();
boolean isDraftable();
}

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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) {

View file

@ -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);

View file

@ -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();

View file

@ -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;
}