Skip to content

Commit

Permalink
#412 @ShallowReference for properties
Browse files Browse the repository at this point in the history
  • Loading branch information
Michał Wesołowski committed Oct 15, 2016
1 parent 5e7e065 commit c4b6d32
Show file tree
Hide file tree
Showing 20 changed files with 237 additions and 54 deletions.
Expand Up @@ -7,7 +7,7 @@
* @author bartosz walacik
*/
public interface CdoFactory {
Cdo create(Object target, OwnerContext owner);
Cdo create(Object target, OwnerContext owner, boolean shallowReference);

String typeDesc();
}
Expand Up @@ -25,7 +25,7 @@ public CollectionsCdoFactory(ClassScanner classScanner, TailoredJaversMemberFact
public Cdo createCdo(final CollectionWrapper wrapper, final Class<?> clazz) {
Property primaryProperty = classScanner.scan(wrapper.getClass()).getProperties().get(0);
JaversMember javersMember = memberGenericTypeInjector.create(primaryProperty, clazz);
Property fixedProperty = new Property(javersMember, false);
Property fixedProperty = new Property(javersMember, false, false);
ValueObjectType valueObject = new ValueObjectType(wrapper.getClass(), Lists.asList(fixedProperty));
return new CdoWrapper(wrapper, new UnboundedValueObjectId(valueObject.getName()), valueObject);
}
Expand Down
Expand Up @@ -29,14 +29,14 @@ String graphType(){
SingleEdge buildSingleEdge(ObjectNode node, Property singleRef) {
Object rawReference = node.getPropertyValue(singleRef);

Cdo cdo = asCdo(rawReference, createOwnerContext(node, singleRef));
Cdo cdo = asCdo(rawReference, createOwnerContext(node, singleRef), singleRef.hasShallowReferenceAnn());
ObjectNode referencedNode = buildNodeStubOrReuse(cdo);

return new SingleEdge(singleRef, referencedNode);
}

Cdo asCdo(Object target, OwnerContext owner){
return cdoFactory.create(target, owner);
Cdo asCdo(Object target, OwnerContext owner, boolean shallowReference){
return cdoFactory.create(target, owner, shallowReference);
}

private OwnerContext createOwnerContext(ObjectNode parentNode, Property property) {
Expand Down Expand Up @@ -72,7 +72,7 @@ public Object apply(Object input, EnumerationAwareOwnerContext context) {
if (!isManagedPosition(input)){
return input;
}
ObjectNode objectNode = buildNodeStubOrReuse(asCdo(input, context));
ObjectNode objectNode = buildNodeStubOrReuse(asCdo(input, context, false));
multiEdge.addReferenceNode(objectNode);
return input;
}
Expand Down
@@ -1,6 +1,7 @@
package org.javers.core.graph;

import org.javers.core.metamodel.object.*;
import org.javers.core.metamodel.type.ManagedType;
import org.javers.core.metamodel.type.TypeMapper;

/**
Expand All @@ -19,10 +20,18 @@ public LiveCdoFactory(GlobalIdFactory globalIdFactory, ObjectAccessHook objectAc
}

@Override
public CdoWrapper create (Object wrappedCdo, OwnerContext owner){
public CdoWrapper create(Object wrappedCdo, OwnerContext owner, boolean shallowReference) {
Object wrappedCdoAccessed = objectAccessHook.access(wrappedCdo);
GlobalId globalId = globalIdFactory.createId(wrappedCdoAccessed, owner);
return new CdoWrapper(wrappedCdoAccessed, globalId, typeMapper.getJaversManagedType(wrappedCdoAccessed.getClass()));
ManagedType managedType = getManagedType(wrappedCdoAccessed, shallowReference);
return new CdoWrapper(wrappedCdoAccessed, globalId, managedType);
}

private ManagedType getManagedType(Object wrappedCdoAccessed, boolean shallowReference) {
Class javaClass = wrappedCdoAccessed.getClass();
return shallowReference ?
typeMapper.getShallowReferenceType(javaClass) :
typeMapper.getJaversManagedType(javaClass);
}

@Override
Expand Down
Expand Up @@ -40,7 +40,7 @@ public LiveGraph createLiveGraph(Object handle) {
}

public Cdo createCdo(Object cdo){
return liveCdoFactory.create(cdo, null);
return liveCdoFactory.create(cdo, null, false);
}

private Object wrapTopLevelContainer(Object handle){
Expand Down
Expand Up @@ -41,7 +41,7 @@ public ObjectGraphBuilder(TypeMapper typeMapper, CdoFactory cdoFactory) {
public LiveGraph buildGraph(Object handle) {
argumentIsNotNull(handle);

Cdo cdo = edgeBuilder.asCdo(handle, null);
Cdo cdo = edgeBuilder.asCdo(handle, null, false);
// logger.debug("building objectGraph for handle [{}] ...",cdo);

return buildGraphFromCdo(cdo);
Expand Down
Expand Up @@ -3,7 +3,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
Expand All @@ -18,7 +18,7 @@
* @author akrystian
*/

@Target(TYPE)
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface ShallowReference {
}
Expand Up @@ -18,11 +18,13 @@ public class Property {

private transient final JaversMember member;
private transient final boolean hasTransientAnn;
private transient final boolean hasShallowReferenceAnn;

public Property(JaversMember member, boolean hasTransientAnn){
public Property(JaversMember member, boolean hasTransientAnn, boolean hasShallowReferenceAnn){
argumentIsNotNull(member);
this.member = member;
this.hasTransientAnn = hasTransientAnn;
this.hasShallowReferenceAnn = hasShallowReferenceAnn;
}

public Type getGenericType() {
Expand Down Expand Up @@ -73,6 +75,10 @@ public boolean hasTransientAnn() {
return hasTransientAnn;
}

public boolean hasShallowReferenceAnn() {
return hasShallowReferenceAnn;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Expand Up @@ -54,15 +54,19 @@ boolean isValueAlias(Annotation ann){
return valueAliases.contains(ann.annotationType().getSimpleName());
}

boolean isIgnoredTypeAliase(Annotation ann) {
boolean isIgnoredTypeAlias(Annotation ann) {
return ignoredTypeAliases.contains(ann.annotationType().getSimpleName());
}

public Set<String> getTransientAliases() {
Set<String> getTransientAliases() {
return Collections.unmodifiableSet(transientPropertyAliases);
}

boolean isShallowReferenceAlias(Annotation ann){
return shallowReferenceAliases.contains(ann.annotationType().getSimpleName());
}

Set<String> getShallowReferenceAliases() {
return Collections.unmodifiableSet(shallowReferenceAliases);
}
}
Expand Up @@ -24,10 +24,9 @@ public PropertyScan scan(Class<?> managedClass) {
List<Property> beanProperties = new ArrayList<>();

for (JaversMethod getter : getters) {

boolean hasTransientAnn = getter.hasAnyAnnotation(annotationNamesProvider.getTransientAliases());

beanProperties.add(new Property(getter, hasTransientAnn));
boolean hasShallowReferenceAnn = getter.hasAnyAnnotation(annotationNamesProvider.getShallowReferenceAliases());
beanProperties.add(new Property(getter, hasTransientAnn, hasShallowReferenceAnn));
}
return new PropertyScan(beanProperties);
}
Expand Down
Expand Up @@ -48,7 +48,7 @@ public ClassAnnotationsScan scan(Class javaClass){
hasShallowReference = true;
}

if (annotationNamesProvider.isIgnoredTypeAliase(ann)) {
if (annotationNamesProvider.isIgnoredTypeAlias(ann)) {
hasIgnored = true;
}

Expand Down
Expand Up @@ -25,7 +25,8 @@ public PropertyScan scan(Class<?> managedClass) {

for (JaversField field : fields) {
boolean hasTransientAnn = field.hasAnyAnnotation(annotationNamesProvider.getTransientAliases());
propertyList.add(new Property(field, hasTransientAnn));
boolean hasShallowReferenceAnn = field.hasAnyAnnotation(annotationNamesProvider.getShallowReferenceAliases());
propertyList.add(new Property(field, hasTransientAnn, hasShallowReferenceAnn));
}
return new PropertyScan(propertyList);
}
Expand Down
Expand Up @@ -57,15 +57,19 @@ private ValueObjectType createValueObject(ValueObjectDefinition definition) {
}

JaversType infer(Type javaType, Optional<JaversType> prototype) {
return infer(javaType, prototype, false);
}

JaversType infer(Type javaType, Optional<JaversType> prototype, boolean asShallowReference) {
JaversType jType;

if (prototype.isPresent()) {
if (!asShallowReference && prototype.isPresent()) {
jType = spawnFromPrototype(javaType, prototype.get());
logger.debug("javersType of {} spawned as {} from prototype {}",
javaType, jType.getClass().getSimpleName(), prototype.get());
}
else {
jType = inferFromAnnotations(javaType);
jType = inferFromAnnotations(javaType, asShallowReference);
logger.debug("javersType of {} inferred as {}",
javaType, jType.getClass().getSimpleName());
}
Expand Down Expand Up @@ -95,22 +99,26 @@ private JaversType spawnFromPrototype(Type javaType, JaversType prototype) {
}

JaversType inferFromAnnotations(Type javaType) {
return inferFromAnnotations(javaType, false);
}

private JaversType inferFromAnnotations(Type javaType, boolean asShallowReference) {
Class javaClass = extractClass(javaType);
ClassScan scan = classScanner.scan(javaClass);

if (scan.hasValueAnn()){
return create( new ValueDefinition(javaClass) );
if (scan.hasValueAnn()) {
return create(new ValueDefinition(javaClass));
}

if (scan.hasIgnoredAnn()){
return create( new IgnoredTypeDefinition(javaClass) );
if (scan.hasIgnoredAnn()) {
return create(new IgnoredTypeDefinition(javaClass));
}

ClientsClassDefinitionBuilder builder;
if (scan.hasIdProperty() || scan.hasEntityAnn()) {
builder = EntityDefinitionBuilder.entityDefinition(javaClass);
if (scan.hasShallowReferenceAnn()) {
((EntityDefinitionBuilder)builder).withShallowReference();
if (scan.hasShallowReferenceAnn() || asShallowReference) {
((EntityDefinitionBuilder) builder).withShallowReference();
}
} else {
builder = ValueObjectDefinitionBuilder.valueObjectDefinition(javaClass);
Expand Down
Expand Up @@ -101,8 +101,12 @@ public MapContentType getMapContentType(ContainerType containerType){
* or infers new one using default mapping
*/
public JaversType getJaversType(Type javaType) {
return getJaversType(javaType, false);
}

public JaversType getJaversType(Type javaType, boolean asShallowReference) {
argumentIsNotNull(javaType);
return state.getJaversType(javaType);
return state.getJaversType(javaType, asShallowReference);
}

/**
Expand Down Expand Up @@ -142,8 +146,14 @@ public <T extends ManagedType> T getJaversManagedType(DuckType duckType, Class<T
*
* @throws JaversException MANAGED_CLASS_MAPPING_ERROR
*/
public ManagedType getJaversManagedType(Class javaType) {
return getJaversManagedType(javaType, ManagedType.class);
public ManagedType getJaversManagedType(Class javaClass) {
return getJaversManagedType(javaClass, ManagedType.class);
}

public ShallowReferenceType getShallowReferenceType(Class javaClass) {
JaversType mType = getJaversType(javaClass, true);
checkExpectedType(javaClass, ShallowReferenceType.class, mType);
return (ShallowReferenceType) mType;
}

/**
Expand All @@ -153,21 +163,23 @@ public ManagedType getJaversManagedType(Class javaType) {
*/
public <T extends ManagedType> T getJaversManagedType(Class javaClass, Class<T> expectedType) {
JaversType mType = getJaversType(javaClass);
checkExpectedType(javaClass, expectedType, mType);
return (T) mType;
}

if (expectedType.isAssignableFrom(mType.getClass())) {
return (T) mType;
} else {
private <T> void checkExpectedType(Class javaClass, Class<T> expectedType, JaversType mType) {
if (!expectedType.isAssignableFrom(mType.getClass())) {
throw new JaversException(JaversExceptionCode.MANAGED_CLASS_MAPPING_ERROR,
javaClass,
mType.getClass().getSimpleName(),
expectedType.getSimpleName());
javaClass,
mType.getClass().getSimpleName(),
expectedType.getSimpleName());
}
}

public <T extends JaversType> T getPropertyType(Property property){
public <T extends JaversType> T getPropertyType(Property property) {
argumentIsNotNull(property);
try {
return (T) getJaversType(property.getGenericType());
return (T) getJaversType(property.getGenericType(), property.hasShallowReferenceAnn());
}catch (JaversException e) {
logger.error("Can't calculate JaversType for property: {}", property);
throw e;
Expand Down
Expand Up @@ -70,23 +70,29 @@ boolean contains(Type javaType){
return mappedTypes.containsKey(javaType.toString());
}

JaversType getJaversType(Type javaType) {
JaversType getJaversType(Type javaType, final boolean asShallowReference) {
argumentIsNotNull(javaType);

if (javaType == Object.class) {
return OBJECT_TYPE;
}

JaversType jType = getFromMap(javaType);
if (jType != null) {
return jType;
}

return computeIfAbsent(javaType, new Function<Type, JaversType>() {
public JaversType apply(Type type) {
return infer(type);
if (asShallowReference) {
synchronized (javaType) {
return infer(javaType, true);
}
});
} else {
JaversType jType = getFromMap(javaType);
if (jType != null) {
return jType;
}

return computeIfAbsent(javaType, new Function<Type, JaversType>() {
public JaversType apply(Type type) {
return infer(type, false);
}
});
}
}

void putIfAbsent(Type javaType, final JaversType jType) {
Expand Down Expand Up @@ -155,10 +161,10 @@ private void addFullMapping(Type javaType, JaversType newType){
/**
* must be called within synchronized block
*/
private JaversType infer(Type javaType) {
private JaversType infer(Type javaType, boolean asShallowReference) {
argumentIsNotNull(javaType);
JaversType prototype = findNearestAncestor(javaType);
JaversType newType = typeFactory.infer(javaType, Optional.fromNullable(prototype));
JaversType newType = typeFactory.infer(javaType, Optional.fromNullable(prototype), asShallowReference);

return newType;
}
Expand All @@ -172,7 +178,7 @@ private JaversType findNearestAncestor(Type javaType) {

//this is due too spoiled Java Array reflection API
if (javaClass.isArray()) {
return getJaversType(Object[].class);
return getJaversType(Object[].class, false);
}

//just to better speed
Expand Down
Expand Up @@ -21,7 +21,7 @@ public ObjectHasher(SnapshotFactory snapshotFactory, JsonConverter jsonConverter
}

public String hash(Object object) {
CdoWrapper cdo = liveCdoFactory.create(object, null);
CdoWrapper cdo = liveCdoFactory.create(object, null, false);

CdoSnapshotState state = snapshotFactory.createSnapshotState(cdo);

Expand Down

0 comments on commit c4b6d32

Please sign in to comment.