DATACMNS-251 - Introduced generic abstraction to determine "is new" state of entities.
Introduced IsNewStrategy and IsNewStrategyFactory interfaces to allow abstracting the way the is-new state of an entity can be determined. The factory allows creating a strategy instance by inspected type, whereas the actual strategy then implements the is-new decision based on a given entity. We provide a MappingContext based factory implementation that looks up a PersistentEntity for the type requested and inspects it for an @Version or @Id property. It will then return strategy implementations that inspect the detected properties and check their values against null or 0 respectively. We also add a CachingIsNewStrategyFactory wrapper to prevent the lookup of the actual strategy from being done over and over again. The @Version annotation was pulled up from the Spring Data MongoDB module. It can be used as meta annotation to allow a deprecation step on the MongoDB's @Version one. Added an IsNewAwareAuditingHandler that exposes a unifying markAudited(…) delegating to the markCreated(…) and markModified(…) depending on the outcome of the IsNewStrategy.
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Demarcates a property to be used as version field to implement optimistic locking on entities.
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Patryk Wasik
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Documented
|
||||
@Target({ FIELD, ANNOTATION_TYPE })
|
||||
@Retention(RUNTIME)
|
||||
public @interface Version {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link AuditingHandler} extension that uses an {@link IsNewStrategyFactory} to expose a generic
|
||||
* {@link #markAudited(Object)} method that will route calls to {@link #markCreated(Object)} or
|
||||
* {@link #markModified(Object)} based on the {@link IsNewStrategy} determined from the factory.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public class IsNewAwareAuditingHandler<T> extends AuditingHandler<T> {
|
||||
|
||||
private final IsNewStrategyFactory isNewStrategyFactory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link IsNewAwareAuditingHandler} using the given {@link IsNewStrategyFactory}.
|
||||
*
|
||||
* @param isNewStrategyFactory must not be {@literal null}.
|
||||
*/
|
||||
public IsNewAwareAuditingHandler(IsNewStrategyFactory isNewStrategyFactory) {
|
||||
|
||||
Assert.notNull(isNewStrategyFactory, "IsNewStrategy must not be null!");
|
||||
this.isNewStrategyFactory = isNewStrategyFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given object created or modified based on the {@link IsNewStrategy} returned by the
|
||||
* {@link IsNewStrategyFactory} configured. Will rout the calls to {@link #markCreated(Object)} and
|
||||
* {@link #markModified(Object)} accordingly.
|
||||
*
|
||||
* @param object
|
||||
*/
|
||||
public void markAudited(Object object) {
|
||||
|
||||
if (object == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
IsNewStrategy strategy = isNewStrategyFactory.getIsNewStrategy(object.getClass());
|
||||
|
||||
if (strategy.isNew(object)) {
|
||||
markCreated(object);
|
||||
} else {
|
||||
markModified(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import org.springframework.data.util.TypeInformation;
|
||||
* @author Oliver Gierke
|
||||
* @author Graeme Rocher
|
||||
* @author Jon Brisbin
|
||||
* @author Patryk Wasik
|
||||
*/
|
||||
public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
|
||||
@@ -51,7 +52,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
* @return true if the given {@link PersistentProperty} is referred to by a constructor argument or {@literal false}
|
||||
* if not or {@literal null}.
|
||||
*/
|
||||
boolean isConstructorArgument(P property);
|
||||
boolean isConstructorArgument(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is the id property of the entity.
|
||||
@@ -59,7 +60,15 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
boolean isIdProperty(P property);
|
||||
boolean isIdProperty(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is the version property of the entity.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
boolean isVersionProperty(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
* Returns the id property of the {@link PersistentEntity}. Can be {@literal null} in case this is an entity
|
||||
@@ -69,6 +78,14 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
*/
|
||||
P getIdProperty();
|
||||
|
||||
/**
|
||||
* Returns the version property of the {@link PersistentEntity}. Can be {@literal null} in case no version property is
|
||||
* available on the entity.
|
||||
*
|
||||
* @return the version property of the {@link PersistentEntity}.
|
||||
*/
|
||||
P getVersionProperty();
|
||||
|
||||
/**
|
||||
* Obtains a {@link PersistentProperty} instance by name.
|
||||
*
|
||||
@@ -77,6 +94,22 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
*/
|
||||
P getPersistentProperty(String name);
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PersistentEntity} has an id property. If this call returns {@literal true},
|
||||
* {@link #getIdProperty()} will return a non-{@literal null} value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasIdProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PersistentEntity} has a version property. If this call returns {@literal true},
|
||||
* {@link #getVersionProperty()} will return a non-{@literal null} value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasVersionProperty();
|
||||
|
||||
/**
|
||||
* Returns the resolved Java type of this entity.
|
||||
*
|
||||
|
||||
@@ -45,6 +45,11 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
*/
|
||||
Class<?> getType();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} of the property.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<?> getTypeInformation();
|
||||
|
||||
/**
|
||||
@@ -96,6 +101,17 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
*/
|
||||
boolean isIdProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the current property is a <em>potential</em> version property of the owning
|
||||
* {@link PersistentEntity}. This method is mainly used by {@link PersistentEntity} implementation to discover version
|
||||
* property candidates on {@link PersistentEntity} creation you should rather call
|
||||
* {@link PersistentEntity#isVersionProperty(PersistentProperty)} to determine whether the current property is the
|
||||
* version property of that {@link PersistentEntity} under consideration.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isVersionProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the property is a {@link Collection}, {@link Iterable} or an array.
|
||||
*
|
||||
|
||||
@@ -110,7 +110,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean isConstructorParameter(P property) {
|
||||
public boolean isConstructorParameter(PersistentProperty<?> property) {
|
||||
|
||||
Assert.notNull(property);
|
||||
|
||||
@@ -238,7 +238,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
boolean maps(P property) {
|
||||
boolean maps(PersistentProperty<?> property) {
|
||||
|
||||
P referencedProperty = entity == null ? null : entity.getPersistentProperty(name);
|
||||
return property == null ? false : property.equals(referencedProperty);
|
||||
|
||||
@@ -21,9 +21,11 @@ import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -59,6 +61,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#getSpelExpression()
|
||||
*/
|
||||
@Override
|
||||
public String getSpelExpression() {
|
||||
return value == null ? null : value.value();
|
||||
}
|
||||
@@ -69,6 +72,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
*
|
||||
* @see org.springframework.data.mapping.BasicPersistentProperty#isTransient()
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
|
||||
boolean isTransient = super.isTransient() || field.isAnnotationPresent(Transient.class);
|
||||
@@ -76,11 +80,20 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
return isTransient || field.isAnnotationPresent(Value.class) || field.isAnnotationPresent(Autowired.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regards the property as ID if there is an {@link Id} annotation found on it.
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isIdProperty()
|
||||
*/
|
||||
public boolean isIdProperty() {
|
||||
return field.isAnnotationPresent(Id.class);
|
||||
return AnnotationUtils.getAnnotation(field, Id.class) != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isVersionProperty()
|
||||
*/
|
||||
public boolean isVersionProperty() {
|
||||
return AnnotationUtils.getAnnotation(field, Version.class) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @author Patryk Wasik
|
||||
*/
|
||||
public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implements MutablePersistentEntity<T, P> {
|
||||
|
||||
@@ -46,6 +47,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
private final Set<Association<P>> associations;
|
||||
|
||||
private P idProperty;
|
||||
private P versionProperty;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicPersistentEntity} from the given {@link TypeInformation}.
|
||||
@@ -87,7 +89,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isConstructorArgument(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isConstructorArgument(P property) {
|
||||
public boolean isConstructorArgument(PersistentProperty<?> property) {
|
||||
return constructor == null ? false : constructor.isConstructorParameter(property);
|
||||
}
|
||||
|
||||
@@ -95,10 +97,18 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isIdProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isIdProperty(P property) {
|
||||
public boolean isIdProperty(PersistentProperty<?> property) {
|
||||
return this.idProperty == null ? false : this.idProperty.equals(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isVersionProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isVersionProperty(PersistentProperty<?> property) {
|
||||
return this.versionProperty == null ? false : this.versionProperty.equals(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getName()
|
||||
@@ -115,6 +125,30 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getVersionProperty()
|
||||
*/
|
||||
public P getVersionProperty() {
|
||||
return versionProperty;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#hasIdProperty()
|
||||
*/
|
||||
public boolean hasIdProperty() {
|
||||
return idProperty != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#hasVersionProperty()
|
||||
*/
|
||||
public boolean hasVersionProperty() {
|
||||
return versionProperty != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.MutablePersistentEntity#addPersistentProperty(P)
|
||||
@@ -134,6 +168,17 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
|
||||
this.idProperty = property;
|
||||
}
|
||||
|
||||
if (property.isVersionProperty()) {
|
||||
|
||||
if (this.versionProperty != null) {
|
||||
throw new MappingException(String.format(
|
||||
"Attempt to add version property %s but already have property %s registered "
|
||||
+ "as version. Check your mapping configuration!", property.getField(), versionProperty.getField()));
|
||||
}
|
||||
|
||||
this.versionProperty = property;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
import org.springframework.data.support.IsNewStrategyFactorySupport;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link IsNewStrategyFactory} using a {@link MappingContext} to determine the {@link IsNewStrategy} to be returned
|
||||
* for a particular type. It will look for a version and id property on the {@link PersistentEntity} and return a
|
||||
* strategy instance that will refelctively inspect the property for {@literal null} values or {@literal null} or a
|
||||
* value of 0 in case of a version property.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupport {
|
||||
|
||||
private final MappingContext<? extends PersistentEntity<?, ?>, ?> context;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MappingContextIsNewStrategyFactory} using the given {@link MappingContext}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
*/
|
||||
public MappingContextIsNewStrategyFactory(MappingContext<? extends PersistentEntity<?, ?>, ?> context) {
|
||||
|
||||
Assert.notNull(context, "MappingContext must not be null!");
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.support.IsNewStrategyFactorySupport#getFallBackStrategy(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
protected IsNewStrategy doGetIsNewStrategy(Class<?> type) {
|
||||
|
||||
PersistentEntity<?, ?> entity = context.getPersistentEntity(type);
|
||||
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entity.hasVersionProperty()) {
|
||||
return new PropertyIsNullOrZeroNumberIsNewStrategy(entity.getVersionProperty());
|
||||
} else if (entity.hasIdProperty()) {
|
||||
return new PropertyIsNullIsNewStrategy(entity.getIdProperty());
|
||||
} else {
|
||||
throw new MappingException(String.format("Cannot determine IsNewStrategy for type %s!", type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategy} implementation that will inspect a given {@link PersistentProperty} and call
|
||||
* {@link #decideIsNew(Object)} with the value retrieved by reflection.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static abstract class PersistentPropertyInspectingIsNewStrategy implements IsNewStrategy {
|
||||
|
||||
private final PersistentProperty<?> property;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentPropertyInspectingIsNewStrategy} using the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public PersistentPropertyInspectingIsNewStrategy(PersistentProperty<?> property) {
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.IsNewStrategy#isNew(java.lang.Object)
|
||||
*/
|
||||
public boolean isNew(Object entity) {
|
||||
|
||||
BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(entity, null);
|
||||
Object propertyValue = wrapper.getProperty(property);
|
||||
|
||||
return decideIsNew(propertyValue);
|
||||
}
|
||||
|
||||
protected abstract boolean decideIsNew(Object property);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategy} that does a check against {@literal null} for the given value and considers the object new if
|
||||
* the value given is {@literal null}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class PropertyIsNullIsNewStrategy extends PersistentPropertyInspectingIsNewStrategy {
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyIsNullIsNewStrategy} using the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public PropertyIsNullIsNewStrategy(PersistentProperty<?> property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory.PersistentPropertyInspectingIsNewStrategy#decideIsNew(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected boolean decideIsNew(Object property) {
|
||||
return property == null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategy} that considers property values of {@literal null} or 0 (in case of a {@link Number})
|
||||
* implementation as indicators for the new state.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class PropertyIsNullOrZeroNumberIsNewStrategy extends PersistentPropertyInspectingIsNewStrategy {
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyIsNullOrZeroNumberIsNewStrategy} instance using the given {@link PersistentProperty}
|
||||
* .
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public PropertyIsNullOrZeroNumberIsNewStrategy(PersistentProperty<?> property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory.PersistentPropertyInspectingIsNewStrategy#decideIsNew(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected boolean decideIsNew(Object property) {
|
||||
|
||||
if (property == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(property instanceof Number)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((Number) property).longValue() == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.support;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategyFactory} that caches resolved {@link IsNewStrategy} instances per type to avoid re-resolving them
|
||||
* on each and every request.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class CachingIsNewStrategyFactory implements IsNewStrategyFactory {
|
||||
|
||||
private final Map<Class<?>, IsNewStrategy> CACHE = new ConcurrentHashMap<Class<?>, IsNewStrategy>();
|
||||
private final IsNewStrategyFactory delegate;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CachingIsNewStrategyFactory} delegating to the given {@link IsNewStrategyFactory}.
|
||||
*
|
||||
* @param delegate must not be {@literal null}.
|
||||
*/
|
||||
public CachingIsNewStrategyFactory(IsNewStrategyFactory delegate) {
|
||||
|
||||
Assert.notNull(delegate, "IsNewStrategyFactory delegate must not be null!");
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.IsNewStrategyFactory#getIsNewStrategy(java.lang.Class)
|
||||
*/
|
||||
public IsNewStrategy getIsNewStrategy(Class<?> type) {
|
||||
|
||||
IsNewStrategy strategy = CACHE.get(type);
|
||||
|
||||
if (strategy != null) {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
IsNewStrategy isNewStrategy = delegate.getIsNewStrategy(type);
|
||||
|
||||
CACHE.put(type, isNewStrategy);
|
||||
return isNewStrategy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.support;
|
||||
|
||||
/**
|
||||
* Strategy interface to determine whether a given entity is to be considered new.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface IsNewStrategy {
|
||||
|
||||
/**
|
||||
* Returns whether the given entity is new, i.e. has never been persisted before or not.
|
||||
*
|
||||
* @param entity can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
boolean isNew(Object entity);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.support;
|
||||
|
||||
/**
|
||||
* Factory interface to create {@link IsNewStrategy} instances for a given class.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface IsNewStrategyFactory {
|
||||
|
||||
/**
|
||||
* Returns the {@link IsNewStrategy} to be used for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return the {@link IsNewStrategy} to be used for the given type, will never be {@literal null}.
|
||||
* @throws IllegalArgumentException in case no {@link IsNewStrategy} could be determined.
|
||||
*/
|
||||
IsNewStrategy getIsNewStrategy(Class<?> type);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.support;
|
||||
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategyFactory} that handles {@link Persistable} implementations directly by retuning a
|
||||
* {@link PersistableIsNewStrategy} and delegating to {@link #doGetIsNewStrategy(Class)} for all other types.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public abstract class IsNewStrategyFactorySupport implements IsNewStrategyFactory {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.support.IsNewStrategyFactory#getIsNewStrategy(java.lang.Class)
|
||||
*/
|
||||
public final IsNewStrategy getIsNewStrategy(Class<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
if (Persistable.class.isAssignableFrom(type)) {
|
||||
return PersistableIsNewStrategy.INSTANCE;
|
||||
}
|
||||
|
||||
IsNewStrategy strategy = doGetIsNewStrategy(type);
|
||||
|
||||
if (strategy != null) {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Unsupported entity %s! Could not determine IsNewStrategy.",
|
||||
type.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the actual {@link IsNewStrategy} to be used for the given type.
|
||||
*
|
||||
* @param type will never be {@literal null}.
|
||||
* @return the {@link IsNewStrategy} to be used for the given type or {@literal null} in case none can be resolved.
|
||||
*/
|
||||
protected abstract IsNewStrategy doGetIsNewStrategy(Class<?> type);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.support;
|
||||
|
||||
import org.springframework.data.domain.Persistable;
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategy} that invokes {@link Persistable#isNew()} on the given object.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public enum PersistableIsNewStrategy implements IsNewStrategy {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.IsNewStrategy#isNew(java.lang.Object)
|
||||
*/
|
||||
public boolean isNew(Object entity) {
|
||||
|
||||
if (!(entity instanceof Persistable)) {
|
||||
throw new IllegalArgumentException(String.format("Given object of type %s does not implement %s!",
|
||||
entity.getClass(), Persistable.class));
|
||||
}
|
||||
|
||||
return ((Persistable<?>) entity).isNew();
|
||||
}
|
||||
}
|
||||
@@ -39,13 +39,17 @@ public class AuditingHandlerUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
handler = new AuditingHandler<AuditedUser>();
|
||||
handler = getHandler();
|
||||
user = new AuditedUser();
|
||||
|
||||
auditorAware = mock(AuditorAware.class);
|
||||
when(auditorAware.getCurrentAuditor()).thenReturn(user);
|
||||
}
|
||||
|
||||
protected AuditingHandler<AuditedUser> getHandler() {
|
||||
return new AuditingHandler<AuditedUser>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the advice does not set auditor on the target entity if no {@code AuditorAware} was configured.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2008-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
|
||||
/**
|
||||
* Unit test for {@code AuditingHandler}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class IsNewAwareAuditingHandlerUnitTests extends AuditingHandlerUnitTests {
|
||||
|
||||
@Mock
|
||||
IsNewStrategyFactory factory;
|
||||
@Mock
|
||||
IsNewStrategy strategy;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
when(factory.getIsNewStrategy(Mockito.any(Class.class))).thenReturn(strategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IsNewAwareAuditingHandler<AuditedUser> getHandler() {
|
||||
return new IsNewAwareAuditingHandler<AuditedUser>(factory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delegatesToMarkCreatedForNewEntity() {
|
||||
|
||||
when(strategy.isNew(Mockito.any(Object.class))).thenReturn(true);
|
||||
AuditedUser user = new AuditedUser();
|
||||
getHandler().markAudited(user);
|
||||
|
||||
assertThat(user.createdDate, is(notNullValue()));
|
||||
assertThat(user.modifiedDate, is(notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delegatesToMarkModifiedForNonNewEntity() {
|
||||
|
||||
when(strategy.isNew(Mockito.any(Object.class))).thenReturn(false);
|
||||
AuditedUser user = new AuditedUser();
|
||||
getHandler().markAudited(user);
|
||||
|
||||
assertThat(user.createdDate, is(nullValue()));
|
||||
assertThat(user.modifiedDate, is(notNullValue()));
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,6 @@ import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import groovy.lang.MetaClass;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -30,10 +28,8 @@ import org.mockito.Mockito;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.mapping.model.AbstractPersistentProperty;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
@@ -47,17 +43,17 @@ import org.springframework.data.util.TypeInformation;
|
||||
public class AbstractMappingContextUnitTests {
|
||||
|
||||
final SimpleTypeHolder holder = new SimpleTypeHolder();
|
||||
DummyMappingContext context;
|
||||
SampleMappingContext context;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
context = new DummyMappingContext();
|
||||
context = new SampleMappingContext();
|
||||
context.setSimpleTypeHolder(holder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotTryToLookupPersistentEntityForLeafProperty() {
|
||||
PersistentPropertyPath<DummyPersistenProperty> path = context.getPersistentPropertyPath(PropertyPath.from("name",
|
||||
PersistentPropertyPath<SamplePersistentProperty> path = context.getPersistentPropertyPath(PropertyPath.from("name",
|
||||
Person.class));
|
||||
assertThat(path, is(notNullValue()));
|
||||
}
|
||||
@@ -68,6 +64,22 @@ public class AbstractMappingContextUnitTests {
|
||||
@Test(expected = MappingException.class)
|
||||
public void doesNotAddInvalidEntity() {
|
||||
|
||||
context = new SampleMappingContext() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <S> BasicPersistentEntity<Object, SamplePersistentProperty> createPersistentEntity(
|
||||
TypeInformation<S> typeInformation) {
|
||||
return new BasicPersistentEntity<Object, SamplePersistentProperty>((TypeInformation<Object>) typeInformation) {
|
||||
@Override
|
||||
public void verify() {
|
||||
if (Unsupported.class.isAssignableFrom(getType())) {
|
||||
throw new MappingException("Unsupported type!");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
context.getPersistentEntity(Unsupported.class);
|
||||
} catch (MappingException e) {
|
||||
@@ -82,7 +94,7 @@ public class AbstractMappingContextUnitTests {
|
||||
|
||||
ApplicationContext context = mock(ApplicationContext.class);
|
||||
|
||||
DummyMappingContext mappingContext = new DummyMappingContext();
|
||||
SampleMappingContext mappingContext = new SampleMappingContext();
|
||||
mappingContext.setInitialEntitySet(Collections.singleton(Person.class));
|
||||
mappingContext.setApplicationContext(context);
|
||||
|
||||
@@ -98,7 +110,7 @@ public class AbstractMappingContextUnitTests {
|
||||
@Test
|
||||
public void returnsNullPersistentEntityForSimpleTypes() {
|
||||
|
||||
DummyMappingContext context = new DummyMappingContext();
|
||||
SampleMappingContext context = new SampleMappingContext();
|
||||
assertThat(context.getPersistentEntity(String.class), is(nullValue()));
|
||||
}
|
||||
|
||||
@@ -124,10 +136,10 @@ public class AbstractMappingContextUnitTests {
|
||||
@Test
|
||||
public void doesNotCreatePersistentPropertyForGroovyMetaClass() {
|
||||
|
||||
DummyMappingContext mappingContext = new DummyMappingContext();
|
||||
SampleMappingContext mappingContext = new SampleMappingContext();
|
||||
mappingContext.initialize();
|
||||
|
||||
PersistentEntity<Object, DummyPersistenProperty> entity = mappingContext.getPersistentEntity(Sample.class);
|
||||
PersistentEntity<Object, SamplePersistentProperty> entity = mappingContext.getPersistentEntity(Sample.class);
|
||||
assertThat(entity.getPersistentProperty("metaClass"), is(nullValue()));
|
||||
}
|
||||
|
||||
@@ -143,47 +155,4 @@ public class AbstractMappingContextUnitTests {
|
||||
|
||||
MetaClass metaClass;
|
||||
}
|
||||
|
||||
class DummyMappingContext extends
|
||||
AbstractMappingContext<BasicPersistentEntity<Object, DummyPersistenProperty>, DummyPersistenProperty> {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <S> BasicPersistentEntity<Object, DummyPersistenProperty> createPersistentEntity(
|
||||
TypeInformation<S> typeInformation) {
|
||||
return new BasicPersistentEntity<Object, DummyPersistenProperty>((TypeInformation<Object>) typeInformation) {
|
||||
|
||||
@Override
|
||||
public void verify() {
|
||||
if (holder.isSimpleType(getType()) || Unsupported.class.equals(getType())) {
|
||||
throw new MappingException("Invalid!");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DummyPersistenProperty createPersistentProperty(final Field field, final PropertyDescriptor descriptor,
|
||||
final BasicPersistentEntity<Object, DummyPersistenProperty> owner, final SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
return new DummyPersistenProperty(field, descriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
}
|
||||
|
||||
class DummyPersistenProperty extends AbstractPersistentProperty<DummyPersistenProperty> {
|
||||
|
||||
public DummyPersistenProperty(Field field, PropertyDescriptor propertyDescriptor,
|
||||
BasicPersistentEntity<?, DummyPersistenProperty> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
public boolean isIdProperty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Association<DummyPersistenProperty> createAssociation() {
|
||||
return new Association<DummyPersistenProperty>(this, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
class SampleMappingContext extends
|
||||
AbstractMappingContext<BasicPersistentEntity<Object, SamplePersistentProperty>, SamplePersistentProperty> {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <S> BasicPersistentEntity<Object, SamplePersistentProperty> createPersistentEntity(
|
||||
TypeInformation<S> typeInformation) {
|
||||
return new BasicPersistentEntity<Object, SamplePersistentProperty>((TypeInformation<Object>) typeInformation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SamplePersistentProperty createPersistentProperty(final Field field, final PropertyDescriptor descriptor,
|
||||
final BasicPersistentEntity<Object, SamplePersistentProperty> owner, final SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
return new SamplePersistentProperty(field, descriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
|
||||
class SamplePersistentProperty extends AnnotationBasedPersistentProperty<SamplePersistentProperty> {
|
||||
|
||||
public SamplePersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
|
||||
BasicPersistentEntity<?, SamplePersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Association<SamplePersistentProperty> createAssociation() {
|
||||
return new Association<SamplePersistentProperty>(this, null);
|
||||
}
|
||||
}
|
||||
@@ -290,6 +290,10 @@ public class AbstractPersistentPropertyUnitTests {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isVersionProperty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Association<SamplePersistentProperty> createAssociation() {
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.data.mapping.MappingMetadataTests.SampleMappingContext;
|
||||
import org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory.PropertyIsNullIsNewStrategy;
|
||||
import org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory.PropertyIsNullOrZeroNumberIsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class MappingContextIsNewStrategyFactoryUnitTests {
|
||||
|
||||
IsNewStrategyFactory factory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
SampleMappingContext context = new SampleMappingContext();
|
||||
factory = new MappingContextIsNewStrategyFactory(context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnsPropertyIsNullOrZeroIsNewStrategyForVersionedEntity() {
|
||||
|
||||
IsNewStrategy strategy = factory.getIsNewStrategy(VersionedEntity.class);
|
||||
assertThat(strategy, is(instanceOf(PropertyIsNullOrZeroNumberIsNewStrategy.class)));
|
||||
|
||||
VersionedEntity entity = new VersionedEntity();
|
||||
assertThat(strategy.isNew(entity), is(true));
|
||||
|
||||
entity.id = 1L;
|
||||
assertThat(strategy.isNew(entity), is(true));
|
||||
|
||||
entity.version = 0L;
|
||||
assertThat(strategy.isNew(entity), is(true));
|
||||
|
||||
entity.version = 1L;
|
||||
assertThat(strategy.isNew(entity), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnsPropertyIsNullOrZeroIsNewStrategyForPrimitiveVersionedEntity() {
|
||||
|
||||
IsNewStrategy strategy = factory.getIsNewStrategy(VersionedEntity.class);
|
||||
assertThat(strategy, is(instanceOf(PropertyIsNullOrZeroNumberIsNewStrategy.class)));
|
||||
|
||||
VersionedEntity entity = new VersionedEntity();
|
||||
assertThat(strategy.isNew(entity), is(true));
|
||||
|
||||
entity.id = 1L;
|
||||
assertThat(strategy.isNew(entity), is(true));
|
||||
|
||||
entity.version = 1L;
|
||||
assertThat(strategy.isNew(entity), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnsPropertyIsNullIsNewStrategyForEntity() {
|
||||
|
||||
IsNewStrategy strategy = factory.getIsNewStrategy(Entity.class);
|
||||
assertThat(strategy, is(instanceOf(PropertyIsNullIsNewStrategy.class)));
|
||||
|
||||
Entity entity = new Entity();
|
||||
assertThat(strategy.isNew(entity), is(true));
|
||||
|
||||
entity.id = 1L;
|
||||
assertThat(strategy.isNew(entity), is(false));
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class PersistableEntity implements Persistable<Long> {
|
||||
|
||||
@Version
|
||||
Long version;
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
boolean isNew = true;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isNew() {
|
||||
return isNew;
|
||||
}
|
||||
}
|
||||
|
||||
static class VersionedEntity {
|
||||
|
||||
@Version
|
||||
Long version;
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
}
|
||||
|
||||
static class PrimitveVersionedEntity {
|
||||
|
||||
@Version
|
||||
long version = 0;
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
}
|
||||
|
||||
static class Entity {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link CachingIsNewStrategyFactory}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CachingIsNewStrategyFactoryUnitTests {
|
||||
|
||||
static final IsNewStrategy REFERENCE = PersistableIsNewStrategy.INSTANCE;
|
||||
|
||||
@Mock
|
||||
IsNewStrategyFactory delegate;
|
||||
|
||||
CachingIsNewStrategyFactory factory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
factory = new CachingIsNewStrategyFactory(delegate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokesDelegateForFirstInvocation() {
|
||||
|
||||
when(delegate.getIsNewStrategy(Object.class)).thenReturn(REFERENCE);
|
||||
|
||||
IsNewStrategy strategy = factory.getIsNewStrategy(Object.class);
|
||||
|
||||
assertThat(strategy, is(REFERENCE));
|
||||
verify(delegate, times(1)).getIsNewStrategy(Object.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesCachedValueForSecondInvocation() {
|
||||
|
||||
when(delegate.getIsNewStrategy(Mockito.any(Class.class))).thenReturn(REFERENCE);
|
||||
|
||||
IsNewStrategy strategy = factory.getIsNewStrategy(Object.class);
|
||||
|
||||
assertThat(strategy, is(REFERENCE));
|
||||
verify(delegate, times(1)).getIsNewStrategy(Object.class);
|
||||
verify(delegate, times(0)).getIsNewStrategy(String.class);
|
||||
|
||||
strategy = factory.getIsNewStrategy(Object.class);
|
||||
assertThat(strategy, is(REFERENCE));
|
||||
verify(delegate, times(1)).getIsNewStrategy(Object.class);
|
||||
verify(delegate, times(0)).getIsNewStrategy(String.class);
|
||||
|
||||
strategy = factory.getIsNewStrategy(String.class);
|
||||
assertThat(strategy, is(REFERENCE));
|
||||
verify(delegate, times(1)).getIsNewStrategy(Object.class);
|
||||
verify(delegate, times(1)).getIsNewStrategy(String.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PersistableIsNewStrategy}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PersistableIsNewStrategyUnitTests {
|
||||
|
||||
IsNewStrategy strategy = PersistableIsNewStrategy.INSTANCE;
|
||||
|
||||
@Test
|
||||
public void invokesPersistableIsNewForTest() {
|
||||
|
||||
PersistableEntity entity = new PersistableEntity();
|
||||
assertThat(strategy.isNew(entity), is(true));
|
||||
|
||||
entity.isNew = false;
|
||||
assertThat(strategy.isNew(entity), is(false));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNonPersistableEntity() {
|
||||
strategy.isNew(new Object());
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class PersistableEntity implements Persistable<Long> {
|
||||
|
||||
boolean isNew = true;
|
||||
|
||||
public Long getId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isNew() {
|
||||
return isNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user