Draft instances map is mutable and so are collection values inside the map, this makes the UPDATE logic straight forward when mutating in-cache draft objects. Also, fix one or two logic bugs with isAssignableFrom().

This commit is contained in:
Greg Burd 2017-11-14 09:55:03 -05:00
parent 7a56059036
commit 618a7ea380
5 changed files with 52 additions and 45 deletions

View file

@ -17,7 +17,8 @@ public abstract class AbstractEntityDraft<E> implements Drafted<E> {
public AbstractEntityDraft(MapExportable entity) {
this.entity = entity;
this.entityMap = entity != null ? entity.toMap() : new HashMap<String, Object>();
// Entities can mutate their map.
this.entityMap = entity != null ? entity.toMap(true) : new HashMap<String, Object>();
}
public abstract Class<E> getEntityClass();

View file

@ -203,9 +203,7 @@ 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>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
draft.put(key, list);
list = (List<V>) draftMap.get(key);
list.add(0, value);
facet = new BoundFacet(prop, list);
} else {
@ -237,9 +235,7 @@ 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>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
draft.put(key, list);
list = (List<V>) draftMap.get(key);
list.addAll(0, value);
facet = new BoundFacet(prop, list);
} else {
@ -270,10 +266,7 @@ 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>)
new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
draft.put(key, list);
list = (List<V>) draftMap.get(key);
}
if (idx < 0) {
list.add(0, value);
@ -312,9 +305,7 @@ 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>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
draft.put(key, list);
list = (List<V>) draftMap.get(key);
list.add(value);
facet = new BoundFacet(prop, list);
} else {
@ -345,9 +336,7 @@ 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>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
draft.put(key, list);
list = (List<V>) draftMap.get(key);
list.addAll(value);
facet = new BoundFacet(prop, list);
} else {
@ -378,9 +367,7 @@ 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>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
draft.put(key, list);
list = (List<V>) draftMap.get(key);
list.remove(value);
facet = new BoundFacet(prop, list);
} else {
@ -411,9 +398,7 @@ 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>) new ArrayList<V>((List<V>) draftMap.get(key)); // copy immutable -> mutable list
draft.put(key, list);
list = (List<V>) draftMap.get(key);
list.removeAll(value);
facet = new BoundFacet(prop, list);
} else {
@ -482,8 +467,7 @@ 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>) new HashSet<V>((Set<V>) draftMap.get(key));
draft.put(key, set);
set = (Set<V>) draftMap.get(key);
set.add(value);
facet = new BoundFacet(prop, set);
} else {

View file

@ -15,6 +15,9 @@
*/
package net.helenus.core.reflect;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
@ -24,10 +27,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.*;
import net.helenus.core.Getter;
import net.helenus.core.Helenus;
import net.helenus.core.cache.CacheUtil;
@ -168,6 +168,15 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
return 0;
}
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
if (method.getParameterCount() == 1 && args[0] instanceof Boolean) {
if ((boolean) args[0] == true) {
return fromValueProviderMap(src, true);
}
}
return Collections.unmodifiableMap(src);
}
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new HelenusException("invalid getter method " + method);
}
@ -192,15 +201,6 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
return Helenus.dsl(iface);
}
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
if (method.getParameterCount() == 1 && args[0] instanceof Boolean) {
if ((boolean) args[0] == true) {
return src;
}
}
return Collections.unmodifiableMap(src);
}
final Object value = src.get(methodName);
if (value == null) {
@ -228,13 +228,33 @@ public class MapperInvocationHandler<E> implements InvocationHandler, Serializab
}
static Map<String, Object> fromValueProviderMap(Map v) {
return fromValueProviderMap(v, false);
}
static Map<String, Object> fromValueProviderMap(Map v, boolean mutable) {
if (v instanceof ValueProviderMap) {
Map<String, Object> m = new HashMap<String, Object>(v.size());
Set<String> keys = v.keySet();
for (String key : keys) {
m.put(key, v.get(key));
Object value = v.get(key);
if (mutable) {
if (ImmutableList.class.isAssignableFrom(value.getClass())) {
m.put(key, new ArrayList((List) value));
} else if (ImmutableMap.class.isAssignableFrom(value.getClass())) {
m.put(key, new HashMap((Map) value));
} else if (ImmutableSet.class.isAssignableFrom(value.getClass())) {
m.put(key, new HashSet((Set) value));
} else {
m.put(key, value);
}
} else {
m.put(key, value);
}
}
return m;
}
return v;
}
static class SerializationProxy<E> implements Serializable {

View file

@ -145,7 +145,7 @@ public final class HelenusMappingEntity implements HelenusEntity {
}
for (ConstraintValidator<?, ?> constraint :
MappingUtil.getValidators(prop.getGetterMethod())) {
if (constraint.getClass().isAssignableFrom(DistinctValidator.class)) {
if (constraint instanceof DistinctValidator) {
DistinctValidator validator = (DistinctValidator) constraint;
String[] values = validator.constraintAnnotation.value();
UnboundFacet facet;

View file

@ -15,6 +15,7 @@
*/
package net.helenus.mapping.value;
import com.google.common.collect.ImmutableMap;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
@ -153,7 +154,8 @@ public final class ValueProviderMap implements Map<String, Object> {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null
|| !(o.getClass().isAssignableFrom(Map.class)
|| !((Map.class.isAssignableFrom(o.getClass())
|| ImmutableMap.class.isAssignableFrom(o.getClass()))
|| o.getClass().getSimpleName().equals("UnmodifiableMap"))) return false;
Map that = (Map) o;