DATACMNS-266 - Use new common Maven build infrastructure.
Simplified project setup to be a single module build again. Using Spring Data Build parent POM to simplify project setup. See https://github.com/SpringSource/spring-data-build#spring-data-build-infrastructure
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Value object to capture {@link Association}s.
|
||||
*
|
||||
* @param the {@link PersistentProperty}s the association connects.
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class Association<P extends PersistentProperty<P>> {
|
||||
|
||||
private final P inverse;
|
||||
private final P obverse;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Association} between the two given {@link PersistentProperty}s.
|
||||
*
|
||||
* @param inverse
|
||||
* @param obverse
|
||||
*/
|
||||
public Association(P inverse, P obverse) {
|
||||
this.inverse = inverse;
|
||||
this.obverse = obverse;
|
||||
}
|
||||
|
||||
public P getInverse() {
|
||||
return inverse;
|
||||
}
|
||||
|
||||
public P getObverse() {
|
||||
return obverse;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Callback interface to implement functionality to be applied to a collection of {@link Association}s.
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface AssociationHandler<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Processes the given {@link Association}.
|
||||
*
|
||||
* @param association
|
||||
*/
|
||||
void doWithAssociation(Association<P> association);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2011-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;
|
||||
|
||||
import org.springframework.data.convert.EntityInstantiator;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Represents a persistent entity.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Graeme Rocher
|
||||
* @author Jon Brisbin
|
||||
* @author Patryk Wasik
|
||||
*/
|
||||
public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* The entity name including any package prefix.
|
||||
*
|
||||
* @return must never return {@literal null}
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the {@link PreferredConstructor} to be used to instantiate objects of this {@link PersistentEntity}.
|
||||
*
|
||||
* @return {@literal null} in case no suitable constructor for automatic construction can be found. This usually
|
||||
* indicates that the instantiation of the object of tthat persistent entity is done through either a customer
|
||||
* {@link EntityInstantiator} or handled by custom conversion mechanisms entirely.
|
||||
*/
|
||||
PreferredConstructor<T, P> getPersistenceConstructor();
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is referred to by a constructor argument of the
|
||||
* {@link PersistentEntity}.
|
||||
*
|
||||
* @param property
|
||||
* @return true if the given {@link PersistentProperty} is referred to by a constructor argument or {@literal false}
|
||||
* if not or {@literal null}.
|
||||
*/
|
||||
boolean isConstructorArgument(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is the id property of the entity.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
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
|
||||
* completely handled by a custom conversion.
|
||||
*
|
||||
* @return the id property of the {@link PersistentEntity}.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param name The name of the property
|
||||
* @return the {@link PersistentProperty} or {@literal null} if it doesn't exist.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @return The underlying Java class for this entity
|
||||
*/
|
||||
Class<T> getType();
|
||||
|
||||
/**
|
||||
* Returns the alias to be used when storing type information. Might be {@literal null} to indicate that there was no
|
||||
* alias defined through the mapping metadata.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Object getTypeAlias();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} backing this {@link PersistentEntity}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<T> getTypeInformation();
|
||||
|
||||
/**
|
||||
* Applies the given {@link PropertyHandler} to all {@link PersistentProperty}s contained in this
|
||||
* {@link PersistentEntity}.
|
||||
*
|
||||
* @param handler must not be {@literal null}.
|
||||
*/
|
||||
void doWithProperties(PropertyHandler<P> handler);
|
||||
|
||||
/**
|
||||
* Applies the given {@link AssociationHandler} to all {@link Association} contained in this {@link PersistentEntity}.
|
||||
*
|
||||
* @param handler must not be {@literal null}.
|
||||
*/
|
||||
void doWithAssociations(AssociationHandler<P> handler);
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2011-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;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* @author Graeme Rocher
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
|
||||
PersistentEntity<?, P> getOwner();
|
||||
|
||||
/**
|
||||
* The name of the property
|
||||
*
|
||||
* @return The property name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* The type of the property
|
||||
*
|
||||
* @return The property type
|
||||
*/
|
||||
Class<?> getType();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} of the property.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<?> getTypeInformation();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} if the property references a {@link PersistentEntity}. Will return
|
||||
* {@literal null} in case it refers to a simple type. Will return {@link Collection}'s component type or the
|
||||
* {@link Map}'s value type transparently.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Iterable<? extends TypeInformation<?>> getPersistentEntityType();
|
||||
|
||||
/**
|
||||
* Returns the getter method to access the property value if available. Might return {@literal null} in case there is
|
||||
* no getter method with a return type assignable to the actual property's type.
|
||||
*
|
||||
* @return the getter method to access the property value if available, otherwise {@literal null}.
|
||||
*/
|
||||
Method getGetter();
|
||||
|
||||
/**
|
||||
* Returns the setter method to set a property value. Might return {@literal null} in case there is no setter
|
||||
* available.
|
||||
*
|
||||
* @returnthe setter method to set a property value if available, otherwise {@literal null}.
|
||||
*/
|
||||
Method getSetter();
|
||||
|
||||
Field getField();
|
||||
|
||||
String getSpelExpression();
|
||||
|
||||
Association<P> getAssociation();
|
||||
|
||||
/**
|
||||
* Returns whether the type of the {@link PersistentProperty} is actually to be regarded as {@link PersistentEntity}
|
||||
* in turn.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isEntity();
|
||||
|
||||
/**
|
||||
* Returns whether the property is a <em>potential</em> identifier property of the owning {@link PersistentEntity}.
|
||||
* This method is mainly used by {@link PersistentEntity} implementation to discover id property candidates on
|
||||
* {@link PersistentEntity} creation you should rather call {@link PersistentEntity#isIdProperty(PersistentProperty)}
|
||||
* to determine whether the current property is the id property of that {@link PersistentEntity} under consideration.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isCollectionLike();
|
||||
|
||||
/**
|
||||
* Returns whether the property is a {@link Map}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isMap();
|
||||
|
||||
/**
|
||||
* Returns whether the property is an array.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isArray();
|
||||
|
||||
/**
|
||||
* Returns whether the property is transient.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isTransient();
|
||||
|
||||
boolean shallBePersisted();
|
||||
|
||||
/**
|
||||
* Returns whether the property is an {@link Association}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isAssociation();
|
||||
|
||||
/**
|
||||
* Returns the component type of the type if it is a {@link java.util.Collection}. Will return the type of the key if
|
||||
* the property is a {@link java.util.Map}.
|
||||
*
|
||||
* @return the component type, the map's key type or {@literal null} if neither {@link java.util.Collection} nor
|
||||
* {@link java.util.Map}.
|
||||
*/
|
||||
Class<?> getComponentType();
|
||||
|
||||
/**
|
||||
* Returns the raw type as it's pulled from from the reflected property.
|
||||
*
|
||||
* @return the raw type of the property.
|
||||
*/
|
||||
Class<?> getRawType();
|
||||
|
||||
/**
|
||||
* Returns the type of the values if the property is a {@link java.util.Map}.
|
||||
*
|
||||
* @return the map's value type or {@literal null} if no {@link java.util.Map}
|
||||
*/
|
||||
Class<?> getMapValueType();
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright 2011-2013 by the original author(s).
|
||||
*
|
||||
* 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;
|
||||
|
||||
import static org.springframework.util.ObjectUtils.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Value object to encapsulate the constructor to be used when mapping persistent data to objects.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final Constructor<T> constructor;
|
||||
private final List<Parameter<Object, P>> parameters;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructor} from the given {@link Constructor} and {@link Parameter}s.
|
||||
*
|
||||
* @param constructor
|
||||
* @param parameters
|
||||
*/
|
||||
public PreferredConstructor(Constructor<T> constructor, Parameter<Object, P>... parameters) {
|
||||
|
||||
Assert.notNull(constructor);
|
||||
Assert.notNull(parameters);
|
||||
|
||||
ReflectionUtils.makeAccessible(constructor);
|
||||
this.constructor = constructor;
|
||||
this.parameters = Arrays.asList(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link Constructor}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Constructor<T> getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Parameter}s of the constructor.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<Parameter<Object, P>> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor has {@link Parameter}s.
|
||||
*
|
||||
* @see #isNoArgConstructor()
|
||||
* @return
|
||||
*/
|
||||
public boolean hasParameters() {
|
||||
return !parameters.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor does not have any arguments.
|
||||
*
|
||||
* @see #hasParameters()
|
||||
* @return
|
||||
*/
|
||||
public boolean isNoArgConstructor() {
|
||||
return parameters.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor was explicitly selected (by {@link PersistenceConstructor}).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isExplicitlyAnnotated() {
|
||||
return constructor.isAnnotationPresent(PersistenceConstructor.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is referenced in a constructor argument of the
|
||||
* {@link PersistentEntity} backing this {@link PreferredConstructor}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean isConstructorParameter(PersistentProperty<?> property) {
|
||||
|
||||
Assert.notNull(property);
|
||||
|
||||
for (Parameter<?, P> parameter : parameters) {
|
||||
if (parameter.maps(property)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link Parameter} is one referring to an enclosing class. That is in case the class this
|
||||
* {@link PreferredConstructor} belongs to is a member class actually. If that's the case the compiler creates a first
|
||||
* constructor argument of the enclosing class type.
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean isEnclosingClassParameter(Parameter<?, P> parameter) {
|
||||
|
||||
Assert.notNull(parameter);
|
||||
|
||||
if (parameters.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parameters.get(0).equals(parameter) && parameter.isEnclosingClassParameter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Value object to represent constructor parameters.
|
||||
*
|
||||
* @param <T> the type of the parameter
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public static class Parameter<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final String name;
|
||||
private final TypeInformation<T> type;
|
||||
private final String key;
|
||||
private final PersistentEntity<T, P> entity;
|
||||
|
||||
private Boolean enclosingClassCache;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Parameter} with the given name, {@link TypeInformation} as well as an array of
|
||||
* {@link Annotation}s. Will insprect the annotations for an {@link Value} annotation to lookup a key or an SpEL
|
||||
* expression to be evaluated.
|
||||
*
|
||||
* @param name the name of the parameter, can be {@literal null}
|
||||
* @param type must not be {@literal null}
|
||||
* @param annotations must not be {@literal null} but can be empty
|
||||
* @param entity can be {@literal null}.
|
||||
*/
|
||||
public Parameter(String name, TypeInformation<T> type, Annotation[] annotations, PersistentEntity<T, P> entity) {
|
||||
|
||||
Assert.notNull(type);
|
||||
Assert.notNull(annotations);
|
||||
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.key = getValue(annotations);
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
private String getValue(Annotation[] annotations) {
|
||||
for (Annotation anno : annotations) {
|
||||
if (anno.annotationType() == Value.class) {
|
||||
return ((Value) anno).value();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the parameter or {@literal null} if none was given.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} of the parameter.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public TypeInformation<T> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw resolved type of the parameter.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<T> getRawType() {
|
||||
return type.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key to be used when looking up a source data structure to populate the actual parameter value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getSpelExpression() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor parameter is equipped with a SpEL expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasSpelExpression() {
|
||||
return StringUtils.hasText(getSpelExpression());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link Parameter} maps the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
boolean maps(PersistentProperty<?> property) {
|
||||
|
||||
P referencedProperty = entity == null ? null : entity.getPersistentProperty(name);
|
||||
return property == null ? false : property.equals(referencedProperty);
|
||||
}
|
||||
|
||||
private boolean isEnclosingClassParameter() {
|
||||
|
||||
if (enclosingClassCache == null) {
|
||||
Class<T> owningType = entity.getType();
|
||||
this.enclosingClassCache = owningType.isMemberClass() && type.getType().equals(owningType.getEnclosingClass());
|
||||
}
|
||||
|
||||
return enclosingClassCache;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Parameter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Parameter<?, ?> that = (Parameter<?, ?>) obj;
|
||||
|
||||
boolean nameEquals = this.name == null ? that.name == null : this.name.equals(that.name);
|
||||
boolean keyEquals = this.key == null ? that.key == null : this.key.equals(that.key);
|
||||
boolean typeEquals = nullSafeEquals(this.type, that.type);
|
||||
boolean entityEquals = this.entity == null ? that.entity == null : this.entity.equals(that.entity);
|
||||
|
||||
return nameEquals && keyEquals && typeEquals && entityEquals;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * nullSafeHashCode(this.name);
|
||||
result += 31 * nullSafeHashCode(this.key);
|
||||
result += 31 * nullSafeHashCode(this.type);
|
||||
result += 31 * nullSafeHashCode(this.entity);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Callback interface to do something with all plain {@link PersistentProperty} instances <em>except</em> associations
|
||||
* and transient properties.
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public interface PropertyHandler<P extends PersistentProperty<P>> {
|
||||
|
||||
void doWithPersistentProperty(P persistentProperty);
|
||||
}
|
||||
358
src/main/java/org/springframework/data/mapping/PropertyPath.java
Normal file
358
src/main/java/org/springframework/data/mapping/PropertyPath.java
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright 2011-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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstraction of a {@link PropertyPath} of a domain class.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PropertyPath implements Iterable<PropertyPath> {
|
||||
|
||||
private static final String DELIMITERS = "_\\.";
|
||||
private static final String ALL_UPPERCASE = "[A-Z0-9._$]+";
|
||||
private static final Pattern SPLITTER = Pattern.compile("(?:[%s]?([%s]*?[^%s]+))".replaceAll("%s", DELIMITERS));
|
||||
|
||||
private final TypeInformation<?> owningType;
|
||||
private final String name;
|
||||
private final TypeInformation<?> type;
|
||||
private final boolean isCollection;
|
||||
|
||||
private PropertyPath next;
|
||||
|
||||
/**
|
||||
* Creates a leaf {@link PropertyPath} (no nested ones) with the given name inside the given owning type.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param owningType must not be {@literal null}.
|
||||
*/
|
||||
PropertyPath(String name, Class<?> owningType) {
|
||||
|
||||
this(name, ClassTypeInformation.from(owningType), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a leaf {@link PropertyPath} (no nested ones with the given name and owning type.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param owningType must not be {@literal null}.
|
||||
* @param base the {@link PropertyPath} previously found.
|
||||
*/
|
||||
PropertyPath(String name, TypeInformation<?> owningType, PropertyPath base) {
|
||||
|
||||
Assert.hasText(name);
|
||||
Assert.notNull(owningType);
|
||||
|
||||
String propertyName = name.matches(ALL_UPPERCASE) ? name : StringUtils.uncapitalize(name);
|
||||
TypeInformation<?> type = owningType.getProperty(propertyName);
|
||||
|
||||
if (type == null) {
|
||||
throw new PropertyReferenceException(propertyName, owningType, base);
|
||||
}
|
||||
|
||||
this.owningType = owningType;
|
||||
this.isCollection = type.isCollectionLike();
|
||||
this.type = type.getActualType();
|
||||
this.name = propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owning type of the {@link PropertyPath}.
|
||||
*
|
||||
* @return the owningType will never be {@literal null}.
|
||||
*/
|
||||
public TypeInformation<?> getOwningType() {
|
||||
return owningType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the {@link PropertyPath}.
|
||||
*
|
||||
* @return the name will never be {@literal null}.
|
||||
*/
|
||||
public String getSegment() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the leaf property of the {@link PropertyPath}.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public PropertyPath getLeafProperty() {
|
||||
|
||||
PropertyPath result = this;
|
||||
|
||||
while (result.hasNext()) {
|
||||
result = result.next();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the property will return the plain resolved type for simple properties, the component type for
|
||||
* any {@link Iterable} or the value type of a {@link java.util.Map} if the property is one.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return this.type.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next nested {@link PropertyPath}.
|
||||
*
|
||||
* @return the next nested {@link PropertyPath} or {@literal null} if no nested {@link PropertyPath} available.
|
||||
* @see #hasNext()
|
||||
*/
|
||||
public PropertyPath next() {
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there is a nested {@link PropertyPath}. If this returns {@literal true} you can expect
|
||||
* {@link #next()} to return a non- {@literal null} value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
|
||||
return next != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PropertyPath} in dot notation.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String toDotPath() {
|
||||
|
||||
if (hasNext()) {
|
||||
return getSegment() + "." + next().toDotPath();
|
||||
}
|
||||
|
||||
return getSegment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PropertyPath} is actually a collection.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isCollection() {
|
||||
|
||||
return isCollection;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyPath that = (PropertyPath) obj;
|
||||
|
||||
return this.name.equals(that.name) && this.type.equals(that.type)
|
||||
&& ObjectUtils.nullSafeEquals(this.next, that.next);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * name.hashCode();
|
||||
result += 31 * type.hashCode();
|
||||
result += 31 * (next == null ? 0 : next.hashCode());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
public Iterator<PropertyPath> iterator() {
|
||||
return new Iterator<PropertyPath>() {
|
||||
|
||||
private PropertyPath current = PropertyPath.this;
|
||||
|
||||
public boolean hasNext() {
|
||||
return current != null;
|
||||
}
|
||||
|
||||
public PropertyPath next() {
|
||||
PropertyPath result = current;
|
||||
this.current = current.next();
|
||||
return result;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the {@link PropertyPath} chain from the given source {@link String} and type.
|
||||
*
|
||||
* @param source
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static PropertyPath from(String source, Class<?> type) {
|
||||
|
||||
return from(source, ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the {@link PropertyPath} chain from the given source {@link String} and {@link TypeInformation}.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static PropertyPath from(String source, TypeInformation<?> type) {
|
||||
|
||||
List<String> iteratorSource = new ArrayList<String>();
|
||||
Matcher matcher = SPLITTER.matcher("_" + source);
|
||||
|
||||
while (matcher.find()) {
|
||||
iteratorSource.add(matcher.group(1));
|
||||
}
|
||||
|
||||
Iterator<String> parts = iteratorSource.iterator();
|
||||
|
||||
PropertyPath result = null;
|
||||
PropertyPath current = null;
|
||||
|
||||
while (parts.hasNext()) {
|
||||
if (result == null) {
|
||||
result = create(parts.next(), type, null);
|
||||
current = result;
|
||||
} else {
|
||||
current = create(parts.next(), current);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyPath} as subordinary of the given {@link PropertyPath}.
|
||||
*
|
||||
* @param source
|
||||
* @param base
|
||||
* @return
|
||||
*/
|
||||
private static PropertyPath create(String source, PropertyPath base) {
|
||||
|
||||
PropertyPath propertyPath = create(source, base.type, base);
|
||||
base.next = propertyPath;
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link PropertyPath} for the given {@link String} and owning type. It will inspect
|
||||
* the given source for camel-case parts and traverse the {@link String} along its parts starting with the entire one
|
||||
* and chewing off parts from the right side then. Whenever a valid property for the given class is found, the tail
|
||||
* will be traversed for subordinary properties of the just found one and so on.
|
||||
*
|
||||
* @param source
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
private static PropertyPath create(String source, TypeInformation<?> type, PropertyPath base) {
|
||||
|
||||
return create(source, type, "", base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to look up a chain of {@link PropertyPath}s by trying the givne source first. If that fails it will split the
|
||||
* source apart at camel case borders (starting from the right side) and try to look up a {@link PropertyPath} from
|
||||
* the calculated head and recombined new tail and additional tail.
|
||||
*
|
||||
* @param source
|
||||
* @param type
|
||||
* @param addTail
|
||||
* @return
|
||||
*/
|
||||
private static PropertyPath create(String source, TypeInformation<?> type, String addTail, PropertyPath base) {
|
||||
|
||||
PropertyReferenceException exception = null;
|
||||
PropertyPath current = null;
|
||||
|
||||
try {
|
||||
|
||||
current = new PropertyPath(source, type, base);
|
||||
|
||||
if (StringUtils.hasText(addTail)) {
|
||||
current.next = create(addTail, current.type, current);
|
||||
}
|
||||
|
||||
return current;
|
||||
|
||||
} catch (PropertyReferenceException e) {
|
||||
|
||||
if (current != null) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
exception = e;
|
||||
}
|
||||
|
||||
Pattern pattern = Pattern.compile("\\p{Lu}+\\p{Ll}*$");
|
||||
Matcher matcher = pattern.matcher(source);
|
||||
|
||||
if (matcher.find() && matcher.start() != 0) {
|
||||
|
||||
int position = matcher.start();
|
||||
String head = source.substring(0, position);
|
||||
String tail = source.substring(position);
|
||||
|
||||
return create(head, type, tail + addTail, base);
|
||||
}
|
||||
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Exception being thrown when creating {@link PropertyPath} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PropertyReferenceException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -5254424051438976570L;
|
||||
private static final String ERROR_TEMPLATE = "No property %s found for type %s";
|
||||
|
||||
private final String propertyName;
|
||||
private final TypeInformation<?> type;
|
||||
private final PropertyPath base;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyReferenceException}.
|
||||
*
|
||||
* @param propertyName the name of the property not found on the given type.
|
||||
* @param type the type the property could not be found on.
|
||||
* @param base the base {@link PropertyPath}.
|
||||
*/
|
||||
public PropertyReferenceException(String propertyName, TypeInformation<?> type, PropertyPath base) {
|
||||
|
||||
Assert.hasText(propertyName);
|
||||
Assert.notNull(type);
|
||||
|
||||
this.propertyName = propertyName;
|
||||
this.type = type;
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the property not found.
|
||||
*
|
||||
* @return will not be {@literal null} or empty.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type the property could not be found on.
|
||||
*
|
||||
* @return the type
|
||||
*/
|
||||
public TypeInformation<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Throwable#getMessage()
|
||||
*/
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return String.format(ERROR_TEMPLATE, propertyName, type.getType().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PropertyPath} which could be resolved so far.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public PropertyPath getBaseProperty() {
|
||||
return base;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* Copyright 2011-2012 by the original author(s).
|
||||
*
|
||||
* 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.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.MutablePersistentEntity;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.FieldCallback;
|
||||
import org.springframework.util.ReflectionUtils.FieldFilter;
|
||||
|
||||
/**
|
||||
* Base class to build mapping metadata and thus create instances of {@link PersistentEntity} and
|
||||
* {@link PersistentProperty}.
|
||||
* <p>
|
||||
* The implementation uses a {@link ReentrantReadWriteLock} to make sure {@link PersistentEntity} are completely
|
||||
* populated before accessing them from outside.
|
||||
*
|
||||
* @param E the concrete {@link PersistentEntity} type the {@link MappingContext} implementation creates
|
||||
* @param P the concrete {@link PersistentProperty} type the {@link MappingContext} implementation creates
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?, P>, P extends PersistentProperty<P>>
|
||||
implements MappingContext<E, P>, ApplicationContextAware, ApplicationEventPublisherAware,
|
||||
ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
private final ConcurrentMap<TypeInformation<?>, E> persistentEntities = new ConcurrentHashMap<TypeInformation<?>, E>();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
private Set<? extends Class<?>> initialEntitySet = new HashSet<Class<?>>();
|
||||
private boolean strict = false;
|
||||
private SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder();
|
||||
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final Lock read = lock.readLock();
|
||||
private final Lock write = lock.writeLock();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
|
||||
this.applicationContext = applicationContext;
|
||||
|
||||
// Default publisher
|
||||
if (this.applicationEventPublisher == null) {
|
||||
this.applicationEventPublisher = applicationContext;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)
|
||||
*/
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Set} of types to populate the context initially.
|
||||
*
|
||||
* @param initialEntitySet
|
||||
*/
|
||||
public void setInitialEntitySet(Set<? extends Class<?>> initialEntitySet) {
|
||||
this.initialEntitySet = initialEntitySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether the {@link MappingContext} is in strict mode which means, that it will throw
|
||||
* {@link MappingException}s in case one tries to lookup a {@link PersistentEntity} not already in the context. This
|
||||
* defaults to {@literal false} so that unknown types will be transparently added to the MappingContext if not known
|
||||
* in advance.
|
||||
*
|
||||
* @param strict
|
||||
*/
|
||||
public void setStrict(boolean strict) {
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link SimpleTypeHolder} to be used by the {@link MappingContext}. Allows customization of what
|
||||
* types will be regarded as simple types and thus not recursively analysed. Setting this to {@literal null} will
|
||||
* reset the context to use the default {@link SimpleTypeHolder}.
|
||||
*
|
||||
* @param simpleTypes
|
||||
*/
|
||||
public void setSimpleTypeHolder(SimpleTypeHolder simpleTypes) {
|
||||
this.simpleTypeHolder = simpleTypes == null ? new SimpleTypeHolder() : simpleTypes;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntities()
|
||||
*/
|
||||
public Collection<E> getPersistentEntities() {
|
||||
try {
|
||||
read.lock();
|
||||
return persistentEntities.values();
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(java.lang.Class)
|
||||
*/
|
||||
public E getPersistentEntity(Class<?> type) {
|
||||
Assert.notNull(type);
|
||||
return getPersistentEntity(ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public E getPersistentEntity(TypeInformation<?> type) {
|
||||
|
||||
Assert.notNull(type);
|
||||
|
||||
try {
|
||||
read.lock();
|
||||
E entity = persistentEntities.get(type);
|
||||
|
||||
if (entity != null) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
|
||||
if (strict) {
|
||||
throw new MappingException("Unknown persistent entity " + type);
|
||||
}
|
||||
|
||||
if (!shouldCreatePersistentEntityFor(type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return addPersistentEntity(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentEntity(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public E getPersistentEntity(P persistentProperty) {
|
||||
|
||||
if (persistentProperty == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
read.lock();
|
||||
return persistentEntities.get(persistentProperty.getTypeInformation());
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentPropertyPath(java.lang.Class, java.lang.String)
|
||||
*/
|
||||
public PersistentPropertyPath<P> getPersistentPropertyPath(PropertyPath propertyPath) {
|
||||
|
||||
List<P> result = new ArrayList<P>();
|
||||
E current = getPersistentEntity(propertyPath.getOwningType());
|
||||
|
||||
for (PropertyPath segment : propertyPath) {
|
||||
|
||||
P persistentProperty = current.getPersistentProperty(segment.getSegment());
|
||||
|
||||
if (persistentProperty == null) {
|
||||
throw new IllegalArgumentException(String.format("No property %s found on %s!", segment.getSegment(),
|
||||
current.getName()));
|
||||
}
|
||||
|
||||
result.add(persistentProperty);
|
||||
|
||||
if (segment.hasNext()) {
|
||||
current = getPersistentEntity(segment.getType());
|
||||
}
|
||||
}
|
||||
|
||||
return new DefaultPersistentPropertyPath<P>(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given type to the {@link MappingContext}.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
protected E addPersistentEntity(Class<?> type) {
|
||||
return addPersistentEntity(ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@link TypeInformation} to the {@link MappingContext}.
|
||||
*
|
||||
* @param typeInformation
|
||||
* @return
|
||||
*/
|
||||
protected E addPersistentEntity(TypeInformation<?> typeInformation) {
|
||||
|
||||
E persistentEntity = persistentEntities.get(typeInformation);
|
||||
|
||||
if (persistentEntity != null) {
|
||||
return persistentEntity;
|
||||
}
|
||||
|
||||
Class<?> type = typeInformation.getType();
|
||||
|
||||
try {
|
||||
|
||||
write.lock();
|
||||
|
||||
final E entity = createPersistentEntity(typeInformation);
|
||||
|
||||
// Eagerly cache the entity as we might have to find it during recursive lookups.
|
||||
persistentEntities.put(typeInformation, entity);
|
||||
|
||||
BeanInfo info = Introspector.getBeanInfo(type);
|
||||
|
||||
final Map<String, PropertyDescriptor> descriptors = new HashMap<String, PropertyDescriptor>();
|
||||
for (PropertyDescriptor descriptor : info.getPropertyDescriptors()) {
|
||||
descriptors.put(descriptor.getName(), descriptor);
|
||||
}
|
||||
|
||||
ReflectionUtils.doWithFields(type, new PersistentPropertyCreator(entity, descriptors),
|
||||
PersistentFieldFilter.INSTANCE);
|
||||
|
||||
try {
|
||||
entity.verify();
|
||||
} catch (MappingException e) {
|
||||
persistentEntities.remove(typeInformation);
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Inform listeners
|
||||
if (null != applicationEventPublisher) {
|
||||
applicationEventPublisher.publishEvent(new MappingContextEvent<E, P>(this, entity));
|
||||
}
|
||||
|
||||
return entity;
|
||||
|
||||
} catch (IntrospectionException e) {
|
||||
throw new MappingException(e.getMessage(), e);
|
||||
} finally {
|
||||
write.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the concrete {@link PersistentEntity} instance.
|
||||
*
|
||||
* @param <T>
|
||||
* @param typeInformation
|
||||
* @return
|
||||
*/
|
||||
protected abstract <T> E createPersistentEntity(TypeInformation<T> typeInformation);
|
||||
|
||||
/**
|
||||
* Creates the concrete instance of {@link PersistentProperty}.
|
||||
*
|
||||
* @param field
|
||||
* @param descriptor
|
||||
* @param owner
|
||||
* @param simpleTypeHolder
|
||||
* @return
|
||||
*/
|
||||
protected abstract P createPersistentProperty(Field field, PropertyDescriptor descriptor, E owner,
|
||||
SimpleTypeHolder simpleTypeHolder);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
*/
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
|
||||
if (!event.getApplicationContext().equals(applicationContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the mapping context. Will add the types configured through {@link #setInitialEntitySet(Set)} to the
|
||||
* context.
|
||||
*/
|
||||
public void initialize() {
|
||||
|
||||
for (Class<?> initialEntity : initialEntitySet) {
|
||||
addPersistentEntity(initialEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a {@link PersistentEntity} instance should be created for the given {@link TypeInformation}. By
|
||||
* default this will reject this for all types considered simple, but it might be necessary to tweak that in case you
|
||||
* have registered custom converters for top level types (which renders them to be considered simple) but still need
|
||||
* meta-information about them.
|
||||
*
|
||||
* @param type will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
|
||||
return !simpleTypeHolder.isSimpleType(type.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FieldCallback} to create {@link PersistentProperty} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private final class PersistentPropertyCreator implements FieldCallback {
|
||||
|
||||
private final E entity;
|
||||
private final Map<String, PropertyDescriptor> descriptors;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentPropertyCreator} for the given {@link PersistentEntity} and
|
||||
* {@link PropertyDescriptor}s.
|
||||
*
|
||||
* @param entity
|
||||
* @param descriptors
|
||||
*/
|
||||
private PersistentPropertyCreator(E entity, Map<String, PropertyDescriptor> descriptors) {
|
||||
this.entity = entity;
|
||||
this.descriptors = descriptors;
|
||||
}
|
||||
|
||||
public void doWith(Field field) {
|
||||
|
||||
PropertyDescriptor descriptor = descriptors.get(field.getName());
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
P property = createPersistentProperty(field, descriptor, entity, simpleTypeHolder);
|
||||
|
||||
if (property.isTransient()) {
|
||||
return;
|
||||
}
|
||||
|
||||
entity.addPersistentProperty(property);
|
||||
|
||||
if (property.isAssociation()) {
|
||||
entity.addAssociation(property.getAssociation());
|
||||
}
|
||||
|
||||
if (entity.getType().equals(property.getRawType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!property.isEntity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (TypeInformation<?> candidate : property.getPersistentEntityType()) {
|
||||
addPersistentEntity(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FieldFilter} rejecting static fields as well as artifically introduced ones. See
|
||||
* {@link PersistentFieldFilter#UNMAPPED_FIELDS} for details.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static enum PersistentFieldFilter implements FieldFilter {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
private static final Iterable<FieldMatch> UNMAPPED_FIELDS;
|
||||
|
||||
static {
|
||||
|
||||
Set<FieldMatch> matches = new HashSet<FieldMatch>();
|
||||
matches.add(new FieldMatch("class", null));
|
||||
matches.add(new FieldMatch("this\\$.*", null));
|
||||
matches.add(new FieldMatch("metaClass", "groovy.lang.MetaClass"));
|
||||
|
||||
UNMAPPED_FIELDS = Collections.unmodifiableCollection(matches);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.util.ReflectionUtils.FieldFilter#matches(java.lang.reflect.Field)
|
||||
*/
|
||||
public boolean matches(Field field) {
|
||||
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (FieldMatch candidate : UNMAPPED_FIELDS) {
|
||||
if (candidate.matches(field)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Value object to help defining field eclusion based on name patterns and types.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class FieldMatch {
|
||||
|
||||
private final String namePattern;
|
||||
private final String typeName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FieldMatch} for the given name pattern and type name. At least one of the paramters must not
|
||||
* be {@literal null}.
|
||||
*
|
||||
* @param namePattern a regex pattern to match field names, can be {@literal null}.
|
||||
* @param typeName the name of the type to exclude, can be {@literal null}.
|
||||
*/
|
||||
public FieldMatch(String namePattern, String typeName) {
|
||||
|
||||
Assert.isTrue(!(namePattern == null && typeName == null), "Either name patter or type name must be given!");
|
||||
|
||||
this.namePattern = namePattern;
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link Field} matches the defined {@link FieldMatch}.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean matches(Field field) {
|
||||
|
||||
if (namePattern != null && !field.getName().matches(namePattern)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeName != null && !field.getType().getName().equals(typeName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright 2011-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.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstraction of a path of {@link PersistentProperty}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements PersistentPropertyPath<T> {
|
||||
|
||||
private enum PropertyNameConverter implements Converter<PersistentProperty<?>, String> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
public String convert(PersistentProperty<?> source) {
|
||||
return source.getName();
|
||||
}
|
||||
}
|
||||
|
||||
private final List<T> properties;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultPersistentPropertyPath} for the given {@link PersistentProperty}s.
|
||||
*
|
||||
* @param properties must not be {@literal null}.
|
||||
*/
|
||||
public DefaultPersistentPropertyPath(List<T> properties) {
|
||||
|
||||
Assert.notNull(properties);
|
||||
Assert.isTrue(!properties.isEmpty());
|
||||
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toDotPath()
|
||||
*/
|
||||
public String toDotPath() {
|
||||
return toPath(null, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toDotPath(org.springframework.core.convert.converter.Converter)
|
||||
*/
|
||||
public String toDotPath(Converter<? super T, String> converter) {
|
||||
return toPath(null, converter);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toPath(java.lang.String)
|
||||
*/
|
||||
public String toPath(String delimiter) {
|
||||
return toPath(delimiter, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toPath(java.lang.String, org.springframework.core.convert.converter.Converter)
|
||||
*/
|
||||
public String toPath(String delimiter, Converter<? super T, String> converter) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Converter<? super T, String> converterToUse = (Converter<? super T, String>) (converter == null ? PropertyNameConverter.INSTANCE
|
||||
: converter);
|
||||
String delimiterToUse = delimiter == null ? "." : delimiter;
|
||||
|
||||
List<String> result = new ArrayList<String>();
|
||||
|
||||
for (T property : properties) {
|
||||
result.add(converterToUse.convert(property));
|
||||
}
|
||||
|
||||
return StringUtils.collectionToDelimitedString(result, delimiterToUse);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getLeafProperty()
|
||||
*/
|
||||
public T getLeafProperty() {
|
||||
return properties.get(properties.size() - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getBaseProperty()
|
||||
*/
|
||||
public T getBaseProperty() {
|
||||
return properties.get(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#isBasePathOf(org.springframework.data.mapping.context.PersistentPropertyPath)
|
||||
*/
|
||||
public boolean isBasePathOf(PersistentPropertyPath<T> path) {
|
||||
|
||||
if (path == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Iterator<T> iterator = path.iterator();
|
||||
|
||||
for (T property : this) {
|
||||
|
||||
if (!iterator.hasNext()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
T reference = iterator.next();
|
||||
|
||||
if (!property.equals(reference)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getExtensionForBaseOf(org.springframework.data.mapping.context.PersistentPropertyPath)
|
||||
*/
|
||||
public PersistentPropertyPath<T> getExtensionForBaseOf(PersistentPropertyPath<T> base) {
|
||||
|
||||
if (!base.isBasePathOf(this)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
List<T> properties = new ArrayList<T>();
|
||||
Iterator<T> iterator = iterator();
|
||||
|
||||
for (int i = 0; i < base.getLength(); i++) {
|
||||
iterator.next();
|
||||
}
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
properties.add(iterator.next());
|
||||
}
|
||||
|
||||
return new DefaultPersistentPropertyPath<T>(properties);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getParentPath()
|
||||
*/
|
||||
public PersistentPropertyPath<T> getParentPath() {
|
||||
int size = properties.size();
|
||||
if (size <= 1) {
|
||||
return this;
|
||||
}
|
||||
return new DefaultPersistentPropertyPath<T>(properties.subList(0, size - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getLength()
|
||||
*/
|
||||
public int getLength() {
|
||||
return properties.size();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
public Iterator<T> iterator() {
|
||||
return properties.iterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DefaultPersistentPropertyPath<?> that = (DefaultPersistentPropertyPath<?>) obj;
|
||||
|
||||
return this.properties.equals(that.properties);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return properties.hashCode();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toDotPath();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2011-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.util.Collection;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* This interface defines the overall context including all known PersistentEntity instances and methods to obtain
|
||||
* instances on demand. it is used internally to establish associations between entities and also at runtime to obtain
|
||||
* entities by name.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @author Graeme Rocher
|
||||
*/
|
||||
public interface MappingContext<E extends PersistentEntity<?, P>, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns all {@link PersistentEntity}s held in the context.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Collection<E> getPersistentEntities();
|
||||
|
||||
/**
|
||||
* Returns a {@link PersistentEntity} for the given {@link Class}. Will return {@literal null} for types that are
|
||||
* considered simple ones.
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
E getPersistentEntity(Class<?> type);
|
||||
|
||||
/**
|
||||
* Returns a {@link PersistentEntity} for the given {@link TypeInformation}. Will return {@literal null} for types
|
||||
* that are considered simple ones.
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
E getPersistentEntity(TypeInformation<?> type);
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentEntity} mapped by the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param persistentProperty
|
||||
* @return the {@link PersistentEntity} mapped by the given {@link PersistentProperty} or null if no
|
||||
* {@link PersistentEntity} exists for it or the {@link PersistentProperty} does not refer to an entity (the
|
||||
* type of the property is considered simple see
|
||||
* {@link org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)}).
|
||||
*/
|
||||
E getPersistentEntity(P persistentProperty);
|
||||
|
||||
/**
|
||||
* Returns all {@link PersistentProperty}s for the given path expression based on the given {@link PropertyPath}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param type
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
PersistentPropertyPath<P> getPersistentPropertyPath(PropertyPath propertyPath);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2011-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 org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base implementation of an {@link ApplicationEvent} refering to a {@link PersistentEntity}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @param <E> the {@link PersistentEntity} the context was created for
|
||||
* @param <P> the {@link PersistentProperty} the {@link PersistentEntity} consists of
|
||||
*/
|
||||
public class MappingContextEvent<E extends PersistentEntity<?, P>, P extends PersistentProperty<P>> extends
|
||||
ApplicationEvent {
|
||||
|
||||
private static final long serialVersionUID = 1336466833846092490L;
|
||||
|
||||
private final MappingContext<?, ?> source;
|
||||
private final E entity;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MappingContextEvent} for the given {@link MappingContext} and {@link PersistentEntity}.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public MappingContextEvent(MappingContext<?, ?> source, E entity) {
|
||||
|
||||
super(source);
|
||||
|
||||
Assert.notNull(source);
|
||||
Assert.notNull(entity);
|
||||
|
||||
this.source = source;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentEntity} the event was created for.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public E getPersistentEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link MappingContextEvent} was triggered by the given {@link MappingContext}.
|
||||
*
|
||||
* @param context the {@link MappingContext} that potentially created the event.
|
||||
* @return
|
||||
*/
|
||||
public boolean wasEmittedBy(MappingContext<?, ?> context) {
|
||||
return this.source.equals(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2011 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 org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* Abstraction of a path of {@link PersistentProperty}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface PersistentPropertyPath<T extends PersistentProperty<T>> extends Iterable<T> {
|
||||
|
||||
/**
|
||||
* Returns the dot based path notation using {@link PersistentProperty#getName()}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String toDotPath();
|
||||
|
||||
/**
|
||||
* Returns the dot based path notation using the given {@link Converter} to translate individual
|
||||
* {@link PersistentProperty}s to path segments.
|
||||
*
|
||||
* @param converter
|
||||
* @return
|
||||
*/
|
||||
String toDotPath(Converter<? super T, String> converter);
|
||||
|
||||
/**
|
||||
* Returns a {@link String} path with the given delimiter based on the {@link PersistentProperty#getName()}.
|
||||
*
|
||||
* @param delimiter will default to {@code .} if {@literal null} is given.
|
||||
* @return
|
||||
*/
|
||||
String toPath(String delimiter);
|
||||
|
||||
/**
|
||||
* Returns a {@link String} path with the given delimiter using the given {@link Converter} for
|
||||
* {@link PersistentProperty} to String conversion.
|
||||
*
|
||||
* @param delimiter will default to {@code .} if {@literal null} is given.
|
||||
* @param converter will default to use {@link PersistentProperty#getName()}.
|
||||
* @return
|
||||
*/
|
||||
String toPath(String delimiter, Converter<? super T, String> converter);
|
||||
|
||||
/**
|
||||
* Returns the last property in the {@link PersistentPropertyPath}. So for {@code foo.bar} it will return the
|
||||
* {@link PersistentProperty} for {@code bar}. For a simple {@code foo} it returns {@link PersistentProperty} for
|
||||
* {@code foo}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
T getLeafProperty();
|
||||
|
||||
/**
|
||||
* Returns the first property in the {@link PersistentPropertyPath}. So for {@code foo.bar} it will return the
|
||||
* {@link PersistentProperty} for {@code foo}. For a simple {@code foo} it returns {@link PersistentProperty} for
|
||||
* {@code foo}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
T getBaseProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentPropertyPath} is a base path of the current one. This means that the
|
||||
* current {@link PersistentPropertyPath} is basically an extension of the given one.
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
boolean isBasePathOf(PersistentPropertyPath<T> path);
|
||||
|
||||
/**
|
||||
* Returns the sub-path of the current one as if it was based on the given base path. So for a current path
|
||||
* {@code foo.bar} and a given base {@code foo} it would return {@code bar}. If the given path is not a base of the
|
||||
* the current one the current {@link PersistentPropertyPath} will be returned as is.
|
||||
*
|
||||
* @param base
|
||||
* @return
|
||||
*/
|
||||
PersistentPropertyPath<T> getExtensionForBaseOf(PersistentPropertyPath<T> base);
|
||||
|
||||
/**
|
||||
* Returns the parent path of the current {@link PersistentPropertyPath}, i.e. the path without the leaf property.
|
||||
* This happens up to the base property. So for a direct property reference calling this method will result in
|
||||
* returning the property.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
PersistentPropertyPath<T> getParentPath();
|
||||
|
||||
/**
|
||||
* Returns the length of the {@link PersistentPropertyPath}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getLength();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Mapping context API and implementation base classes.
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright 2011-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 java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple impementation of {@link PersistentProperty}.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>> implements PersistentProperty<P> {
|
||||
|
||||
protected final String name;
|
||||
protected final PropertyDescriptor propertyDescriptor;
|
||||
protected final TypeInformation<?> information;
|
||||
protected final Class<?> rawType;
|
||||
protected final Field field;
|
||||
protected final Association<P> association;
|
||||
protected final PersistentEntity<?, P> owner;
|
||||
private final SimpleTypeHolder simpleTypeHolder;
|
||||
|
||||
public AbstractPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity<?, P> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
Assert.notNull(field);
|
||||
Assert.notNull(simpleTypeHolder);
|
||||
Assert.notNull(owner);
|
||||
|
||||
this.name = field.getName();
|
||||
this.rawType = field.getType();
|
||||
this.information = owner.getTypeInformation().getProperty(this.name);
|
||||
this.propertyDescriptor = propertyDescriptor;
|
||||
this.field = field;
|
||||
this.association = isAssociation() ? createAssociation() : null;
|
||||
this.owner = owner;
|
||||
this.simpleTypeHolder = simpleTypeHolder;
|
||||
}
|
||||
|
||||
protected abstract Association<P> createAssociation();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getOwner()
|
||||
*/
|
||||
public PersistentEntity<?, P> getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getType()
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return information.getType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getRawType()
|
||||
*/
|
||||
public Class<?> getRawType() {
|
||||
return this.rawType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getTypeInformation()
|
||||
*/
|
||||
public TypeInformation<?> getTypeInformation() {
|
||||
return information;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getPersistentEntityType()
|
||||
*/
|
||||
public Iterable<? extends TypeInformation<?>> getPersistentEntityType() {
|
||||
|
||||
List<TypeInformation<?>> result = new ArrayList<TypeInformation<?>>();
|
||||
|
||||
TypeInformation<?> type = getTypeInformation();
|
||||
|
||||
if (isEntity()) {
|
||||
result.add(type);
|
||||
}
|
||||
|
||||
if (type.isCollectionLike() || isMap()) {
|
||||
TypeInformation<?> nestedType = getTypeInformationIfNotSimpleType(getTypeInformation().getActualType());
|
||||
if (nestedType != null) {
|
||||
result.add(nestedType);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private TypeInformation<?> getTypeInformationIfNotSimpleType(TypeInformation<?> information) {
|
||||
return information == null || simpleTypeHolder.isSimpleType(information.getType()) ? null : information;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getGetter()
|
||||
*/
|
||||
public Method getGetter() {
|
||||
|
||||
if (propertyDescriptor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Method getter = propertyDescriptor.getReadMethod();
|
||||
|
||||
if (getter == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return rawType.isAssignableFrom(getter.getReturnType()) ? getter : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getSetter()
|
||||
*/
|
||||
public Method getSetter() {
|
||||
|
||||
if (propertyDescriptor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Method setter = propertyDescriptor.getWriteMethod();
|
||||
|
||||
if (setter == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return setter.getParameterTypes()[0].isAssignableFrom(rawType) ? setter : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getField()
|
||||
*/
|
||||
public Field getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getSpelExpression()
|
||||
*/
|
||||
public String getSpelExpression() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isTransient()
|
||||
*/
|
||||
public boolean isTransient() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#shallBePersisted()
|
||||
*/
|
||||
public boolean shallBePersisted() {
|
||||
return !isTransient();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isAssociation()
|
||||
*/
|
||||
public boolean isAssociation() {
|
||||
if (field.isAnnotationPresent(Reference.class)) {
|
||||
return true;
|
||||
}
|
||||
for (Annotation annotation : field.getDeclaredAnnotations()) {
|
||||
if (annotation.annotationType().isAnnotationPresent(Reference.class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Association<P> getAssociation() {
|
||||
return association;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isCollectionLike()
|
||||
*/
|
||||
public boolean isCollectionLike() {
|
||||
return information.isCollectionLike();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isMap()
|
||||
*/
|
||||
public boolean isMap() {
|
||||
return Map.class.isAssignableFrom(getType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isArray()
|
||||
*/
|
||||
public boolean isArray() {
|
||||
return getType().isArray();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isEntity()
|
||||
*/
|
||||
public boolean isEntity() {
|
||||
|
||||
TypeInformation<?> actualType = information.getActualType();
|
||||
boolean isComplexType = actualType == null ? false : !simpleTypeHolder.isSimpleType(actualType.getType());
|
||||
return isComplexType && !isTransient() && !isCollectionLike() && !isMap();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getComponentType()
|
||||
*/
|
||||
public Class<?> getComponentType() {
|
||||
|
||||
if (!isMap() && !isCollectionLike()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeInformation<?> componentType = information.getComponentType();
|
||||
return componentType == null ? null : componentType.getType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getMapValueType()
|
||||
*/
|
||||
public Class<?> getMapValueType() {
|
||||
return isMap() ? information.getMapValueType().getType() : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof AbstractPersistentProperty)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AbstractPersistentProperty<?> that = (AbstractPersistentProperty<?>) obj;
|
||||
return this.field.equals(that.field);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.field.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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 java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Special {@link PersistentProperty} that takes annotations at a property into account.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public abstract class AnnotationBasedPersistentProperty<P extends PersistentProperty<P>> extends
|
||||
AbstractPersistentProperty<P> {
|
||||
|
||||
private final Value value;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationBasedPersistentProperty}.
|
||||
*
|
||||
* @param field
|
||||
* @param propertyDescriptor
|
||||
* @param owner
|
||||
*/
|
||||
public AnnotationBasedPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
|
||||
PersistentEntity<?, P> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
this.value = field.getAnnotation(Value.class);
|
||||
field.isAnnotationPresent(Autowired.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects a potentially available {@link Value} annotation at the property and returns the {@link String} value of
|
||||
* it.
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#getSpelExpression()
|
||||
*/
|
||||
@Override
|
||||
public String getSpelExpression() {
|
||||
return value == null ? null : value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers plain transient fields, fields annotated with {@link Transient}, {@link Value} or {@link Autowired} as
|
||||
* transien.
|
||||
*
|
||||
* @see org.springframework.data.mapping.BasicPersistentProperty#isTransient()
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
|
||||
boolean isTransient = super.isTransient() || field.isAnnotationPresent(Transient.class);
|
||||
|
||||
return isTransient || field.isAnnotationPresent(Value.class) || field.isAnnotationPresent(Autowired.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isIdProperty()
|
||||
*/
|
||||
public boolean isIdProperty() {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers the property an {@link Association} if it is annotated with {@link Reference}.
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssociation() {
|
||||
|
||||
if (isTransient()) {
|
||||
return false;
|
||||
}
|
||||
if (field.isAnnotationPresent(Reference.class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: do we need this? Shouldn't the section above already find that annotation?
|
||||
for (Annotation annotation : field.getDeclaredAnnotations()) {
|
||||
if (annotation.annotationType().isAnnotationPresent(Reference.class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright 2011-2012 by the original author(s).
|
||||
*
|
||||
* 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 java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.data.annotation.TypeAlias;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Simple value object to capture information of {@link PersistentEntity}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @author Patryk Wasik
|
||||
*/
|
||||
public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implements MutablePersistentEntity<T, P> {
|
||||
|
||||
private final PreferredConstructor<T, P> constructor;
|
||||
private final TypeInformation<T> information;
|
||||
private final Set<P> properties;
|
||||
private final Set<Association<P>> associations;
|
||||
|
||||
private P idProperty;
|
||||
private P versionProperty;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicPersistentEntity} from the given {@link TypeInformation}.
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
*/
|
||||
public BasicPersistentEntity(TypeInformation<T> information) {
|
||||
this(information, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicPersistentEntity} for the given {@link TypeInformation} and {@link Comparator}. The given
|
||||
* {@link Comparator} will be used to define the order of the {@link PersistentProperty} instances added to the
|
||||
* entity.
|
||||
*
|
||||
* @param information must not be {@literal null}
|
||||
* @param comparator
|
||||
*/
|
||||
public BasicPersistentEntity(TypeInformation<T> information, Comparator<P> comparator) {
|
||||
|
||||
Assert.notNull(information);
|
||||
|
||||
this.information = information;
|
||||
this.properties = comparator == null ? new HashSet<P>() : new TreeSet<P>(comparator);
|
||||
this.constructor = new PreferredConstructorDiscoverer<T, P>(information, this).getConstructor();
|
||||
this.associations = comparator == null ? new HashSet<Association<P>>() : new TreeSet<Association<P>>(
|
||||
new AssociationComparator<P>(comparator));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistenceConstructor()
|
||||
*/
|
||||
public PreferredConstructor<T, P> getPersistenceConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isConstructorArgument(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isConstructorArgument(PersistentProperty<?> property) {
|
||||
return constructor == null ? false : constructor.isConstructorParameter(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isIdProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
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()
|
||||
*/
|
||||
public String getName() {
|
||||
return getType().getName();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getIdProperty()
|
||||
*/
|
||||
public P getIdProperty() {
|
||||
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)
|
||||
*/
|
||||
public void addPersistentProperty(P property) {
|
||||
|
||||
Assert.notNull(property);
|
||||
properties.add(property);
|
||||
|
||||
if (property.isIdProperty()) {
|
||||
|
||||
if (this.idProperty != null) {
|
||||
throw new MappingException(String.format(
|
||||
"Attempt to add id property %s but already have property %s registered "
|
||||
+ "as id. Check your mapping configuration!", property.getField(), idProperty.getField()));
|
||||
}
|
||||
|
||||
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)
|
||||
* @see org.springframework.data.mapping.MutablePersistentEntity#addAssociation(org.springframework.data.mapping.model.Association)
|
||||
*/
|
||||
public void addAssociation(Association<P> association) {
|
||||
associations.add(association);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.String)
|
||||
*/
|
||||
public P getPersistentProperty(String name) {
|
||||
|
||||
for (P property : properties) {
|
||||
if (property.getName().equals(name)) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getType()
|
||||
*/
|
||||
public Class<T> getType() {
|
||||
return information.getType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getTypeAlias()
|
||||
*/
|
||||
public Object getTypeAlias() {
|
||||
|
||||
TypeAlias alias = getType().getAnnotation(TypeAlias.class);
|
||||
return alias == null ? null : StringUtils.hasText(alias.value()) ? alias.value() : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getTypeInformation()
|
||||
*/
|
||||
public TypeInformation<T> getTypeInformation() {
|
||||
return information;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#doWithProperties(org.springframework.data.mapping.PropertyHandler)
|
||||
*/
|
||||
public void doWithProperties(PropertyHandler<P> handler) {
|
||||
Assert.notNull(handler);
|
||||
for (P property : properties) {
|
||||
if (!property.isTransient() && !property.isAssociation()) {
|
||||
handler.doWithPersistentProperty(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#doWithAssociations(org.springframework.data.mapping.AssociationHandler)
|
||||
*/
|
||||
public void doWithAssociations(AssociationHandler<P> handler) {
|
||||
Assert.notNull(handler);
|
||||
for (Association<P> association : associations) {
|
||||
handler.doWithAssociation(association);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.MutablePersistentEntity#verify()
|
||||
*/
|
||||
public void verify() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple {@link Comparator} adaptor to delegate ordering to the inverse properties of the association.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static final class AssociationComparator<P extends PersistentProperty<P>> implements
|
||||
Comparator<Association<P>>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4508054194886854513L;
|
||||
private final Comparator<P> delegate;
|
||||
|
||||
public AssociationComparator(Comparator<P> delegate) {
|
||||
Assert.notNull(delegate);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public int compare(Association<P> left, Association<P> right) {
|
||||
return delegate.compare(left.getInverse(), right.getInverse());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2011-2012 by the original author(s).
|
||||
*
|
||||
* 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 java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Value object to allow creation of objects using the metamodel, setting and getting properties.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class BeanWrapper<E extends PersistentEntity<T, ?>, T> {
|
||||
|
||||
private final T bean;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BeanWrapper} for the given bean instance and {@link ConversionService}. If
|
||||
* {@link ConversionService} is {@literal null} no property type conversion will take place.
|
||||
*
|
||||
* @param <E>
|
||||
* @param <T>
|
||||
* @param bean must not be {@literal null}
|
||||
* @param conversionService
|
||||
* @return
|
||||
*/
|
||||
public static <E extends PersistentEntity<T, ?>, T> BeanWrapper<E, T> create(T bean,
|
||||
ConversionService conversionService) {
|
||||
return new BeanWrapper<E, T>(bean, conversionService);
|
||||
}
|
||||
|
||||
private BeanWrapper(T bean, ConversionService conversionService) {
|
||||
Assert.notNull(bean);
|
||||
this.bean = bean;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given {@link PersistentProperty} to the given value. Will do type conversion if a
|
||||
* {@link ConversionService} is configured. Will use the accessor method of the given {@link PersistentProperty} if it
|
||||
* has one or field access otherwise.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @param value
|
||||
*/
|
||||
public void setProperty(PersistentProperty<?> property, Object value) {
|
||||
setProperty(property, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given {@link PersistentProperty} to the given value. Will do type conversion if a
|
||||
* {@link ConversionService} is configured.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @param value
|
||||
* @param fieldAccessOnly whether to only try accessing the field ({@literal true}) or try using the getter first.
|
||||
* @throws IllegalAccessException
|
||||
* @throws InvocationTargetException
|
||||
*/
|
||||
public void setProperty(PersistentProperty<?> property, Object value, boolean fieldAccessOnly) {
|
||||
|
||||
Method setter = property.getSetter();
|
||||
|
||||
try {
|
||||
|
||||
if (fieldAccessOnly || null == setter) {
|
||||
Object valueToSet = getPotentiallyConvertedValue(value, property.getType());
|
||||
ReflectionUtils.makeAccessible(property.getField());
|
||||
ReflectionUtils.setField(property.getField(), bean, valueToSet);
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?>[] paramTypes = setter.getParameterTypes();
|
||||
Object valueToSet = getPotentiallyConvertedValue(value, paramTypes[0]);
|
||||
ReflectionUtils.makeAccessible(setter);
|
||||
ReflectionUtils.invokeMethod(setter, bean, valueToSet);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new MappingException("Could not set object property!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the given {@link PersistentProperty} of the underlying bean instance.
|
||||
*
|
||||
* @param <S>
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
public Object getProperty(PersistentProperty<?> property) {
|
||||
return getProperty(property, property.getType(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the given {@link PersistentProperty} potentially converted to the given type.
|
||||
*
|
||||
* @param <S>
|
||||
* @param property must not be {@literal null}.
|
||||
* @param type
|
||||
* @param fieldAccessOnly
|
||||
* @return
|
||||
*/
|
||||
public <S> S getProperty(PersistentProperty<?> property, Class<? extends S> type, boolean fieldAccessOnly) {
|
||||
|
||||
try {
|
||||
Object obj;
|
||||
Field field = property.getField();
|
||||
Method getter = property.getGetter();
|
||||
|
||||
if (fieldAccessOnly || null == getter) {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
obj = ReflectionUtils.getField(field, bean);
|
||||
} else {
|
||||
ReflectionUtils.makeAccessible(getter);
|
||||
obj = ReflectionUtils.invokeMethod(getter, bean);
|
||||
}
|
||||
|
||||
return getPotentiallyConvertedValue(obj, type);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new MappingException(String.format("Could not read property %s of %s!", property.toString(),
|
||||
bean.toString()), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given source value if it is not assignable to the given target type.
|
||||
*
|
||||
* @param source
|
||||
* @param targetType
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S> S getPotentiallyConvertedValue(Object source, Class<S> targetType) {
|
||||
|
||||
boolean conversionServiceAvailable = conversionService != null;
|
||||
boolean conversionNeeded = source == null || !targetType.isAssignableFrom(source.getClass());
|
||||
|
||||
if (conversionServiceAvailable && conversionNeeded) {
|
||||
return conversionService.convert(source, targetType);
|
||||
}
|
||||
|
||||
return (S) source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying bean instance.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public T getBean() {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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.PreferredConstructor.Parameter;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* {@link ParameterValueProvider} implementation that evaluates the {@link Parameter}s key against
|
||||
* {@link SpelExpressionParser} and {@link EvaluationContext}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultSpELExpressionEvaluator implements SpELExpressionEvaluator {
|
||||
|
||||
private final Object source;
|
||||
private final SpELContext factory;
|
||||
|
||||
/**
|
||||
* @param parser
|
||||
* @param factory
|
||||
*/
|
||||
public DefaultSpELExpressionEvaluator(Object source, SpELContext factory) {
|
||||
this.source = source;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.SpELExpressionEvaluator#evaluate(java.lang.String)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T evaluate(String expression) {
|
||||
|
||||
Expression parseExpression = factory.getParser().parseExpression(expression);
|
||||
return (T) parseExpression.getValue(factory.getEvaluationContext(source));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Copyright (C) 2010 SpringSource
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Thrown when an error occurs reading the mapping between object and datastore
|
||||
*
|
||||
* @author Graeme Rocher
|
||||
* @since 1.0
|
||||
*/
|
||||
public class IllegalMappingException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public IllegalMappingException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
|
||||
public IllegalMappingException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -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,36 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class MappingException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public MappingException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public MappingException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class MappingInstantiationException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public MappingInstantiationException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* Interface capturing mutator methods for {@link PersistentEntity}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface MutablePersistentEntity<T, P extends PersistentProperty<P>> extends PersistentEntity<T, P> {
|
||||
|
||||
/**
|
||||
* Adds a {@link PersistentProperty} to the entity.
|
||||
*
|
||||
* @param property
|
||||
*/
|
||||
void addPersistentProperty(P property);
|
||||
|
||||
/**
|
||||
* Adds an {@link Association} to the entity.
|
||||
*
|
||||
* @param association
|
||||
*/
|
||||
void addAssociation(Association<P> association);
|
||||
|
||||
/**
|
||||
* Callback method to trigger validation of the {@link PersistentEntity}. As {@link MutablePersistentEntity} is not
|
||||
* immutable there might be some verification steps necessary after the object has reached is final state.
|
||||
*
|
||||
* @throws MappingException in case the entity is invalid
|
||||
*/
|
||||
void verify() throws MappingException;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2012 by the original author(s).
|
||||
*
|
||||
* 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.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
|
||||
/**
|
||||
* Callback interface to lookup values for a given {@link Parameter}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface ParameterValueProvider<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns the value to be used for the given {@link Parameter} (usually when entity instances are created).
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<T> T getParameterValue(Parameter<T, P> parameter);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ParameterValueProvider} based on a {@link PersistentEntity} to use a {@link PropertyValueProvider} to lookup
|
||||
* the value of the property referenced by the given {@link Parameter}. Additionally a
|
||||
* {@link DefaultSpELExpressionEvaluator} can be configured to get property value resolution trumped by a SpEL
|
||||
* expression evaluation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PersistentEntityParameterValueProvider<P extends PersistentProperty<P>> implements
|
||||
ParameterValueProvider<P> {
|
||||
|
||||
private final PersistentEntity<?, P> entity;
|
||||
private final PropertyValueProvider<P> provider;
|
||||
private final Object parent;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentEntityParameterValueProvider} for the given {@link PersistentEntity} and
|
||||
* {@link PropertyValueProvider}.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
* @param provider must not be {@literal null}.
|
||||
* @param parent the parent object being created currently, can be {@literal null}.
|
||||
*/
|
||||
public PersistentEntityParameterValueProvider(PersistentEntity<?, P> entity, PropertyValueProvider<P> provider,
|
||||
Object parent) {
|
||||
|
||||
Assert.notNull(entity);
|
||||
Assert.notNull(provider);
|
||||
|
||||
this.entity = entity;
|
||||
this.provider = provider;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.ParameterValueProvider#getParameterValue(org.springframework.data.mapping.PreferredConstructor.Parameter)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
PreferredConstructor<?, P> constructor = entity.getPersistenceConstructor();
|
||||
|
||||
if (constructor.isEnclosingClassParameter(parameter)) {
|
||||
return (T) parent;
|
||||
}
|
||||
|
||||
P property = entity.getPersistentProperty(parameter.getName());
|
||||
|
||||
if (property == null) {
|
||||
throw new MappingException(String.format("No property %s found on entity %s to bind constructor parameter to!",
|
||||
parameter.getName(), entity.getType()));
|
||||
}
|
||||
|
||||
return provider.getPropertyValue(property);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2011-2012 by the original author(s).
|
||||
*
|
||||
* 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 java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Helper class to find a {@link PreferredConstructor}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final ParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
private PreferredConstructor<T, P> constructor;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
*/
|
||||
public PreferredConstructorDiscoverer(Class<T> type) {
|
||||
this(ClassTypeInformation.from(type), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given {@link PersistentEntity}.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public PreferredConstructorDiscoverer(PersistentEntity<T, P> entity) {
|
||||
this(entity.getTypeInformation(), entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param entity
|
||||
*/
|
||||
protected PreferredConstructorDiscoverer(TypeInformation<T> type, PersistentEntity<T, P> entity) {
|
||||
|
||||
boolean noArgConstructorFound = false;
|
||||
int numberOfArgConstructors = 0;
|
||||
Class<?> rawOwningType = type.getType();
|
||||
|
||||
for (Constructor<?> constructor : rawOwningType.getDeclaredConstructors()) {
|
||||
|
||||
PreferredConstructor<T, P> preferredConstructor = buildPreferredConstructor(constructor, type, entity);
|
||||
|
||||
// Explicitly defined constructor trumps all
|
||||
if (preferredConstructor.isExplicitlyAnnotated()) {
|
||||
this.constructor = preferredConstructor;
|
||||
return;
|
||||
}
|
||||
|
||||
// No-arg constructor trumps custom ones
|
||||
if (this.constructor == null || preferredConstructor.isNoArgConstructor()) {
|
||||
this.constructor = preferredConstructor;
|
||||
}
|
||||
|
||||
if (preferredConstructor.isNoArgConstructor()) {
|
||||
noArgConstructorFound = true;
|
||||
} else {
|
||||
numberOfArgConstructors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!noArgConstructorFound && numberOfArgConstructors > 1) {
|
||||
this.constructor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private PreferredConstructor<T, P> buildPreferredConstructor(Constructor<?> constructor,
|
||||
TypeInformation<T> typeInformation, PersistentEntity<T, P> entity) {
|
||||
|
||||
List<TypeInformation<?>> parameterTypes = typeInformation.getParameterTypes(constructor);
|
||||
|
||||
if (parameterTypes.isEmpty()) {
|
||||
return new PreferredConstructor<T, P>((Constructor<T>) constructor);
|
||||
}
|
||||
|
||||
String[] parameterNames = nameDiscoverer.getParameterNames(constructor);
|
||||
Parameter<Object, P>[] parameters = new Parameter[parameterTypes.size()];
|
||||
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
|
||||
|
||||
for (int i = 0; i < parameterTypes.size(); i++) {
|
||||
|
||||
String name = parameterNames == null ? null : parameterNames[i];
|
||||
TypeInformation<?> type = parameterTypes.get(i);
|
||||
Annotation[] annotations = parameterAnnotations[i];
|
||||
|
||||
parameters[i] = new Parameter(name, type, annotations, entity);
|
||||
}
|
||||
|
||||
return new PreferredConstructor<T, P>((Constructor<T>) constructor, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the discovered {@link PreferredConstructor}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public PreferredConstructor<T, P> getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
@@ -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.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* SPI for components to provide values for as {@link PersistentProperty}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface PropertyValueProvider<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns a value for the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<T> T getPropertyValue(P property);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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 java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple container to hold a set of types to be considered simple types.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleTypeHolder {
|
||||
|
||||
private static final Set<Class<?>> DEFAULTS = new HashSet<Class<?>>();
|
||||
|
||||
static {
|
||||
DEFAULTS.add(boolean.class);
|
||||
DEFAULTS.add(boolean[].class);
|
||||
DEFAULTS.add(long.class);
|
||||
DEFAULTS.add(long[].class);
|
||||
DEFAULTS.add(short.class);
|
||||
DEFAULTS.add(short[].class);
|
||||
DEFAULTS.add(int.class);
|
||||
DEFAULTS.add(int[].class);
|
||||
DEFAULTS.add(byte.class);
|
||||
DEFAULTS.add(byte[].class);
|
||||
DEFAULTS.add(float.class);
|
||||
DEFAULTS.add(float[].class);
|
||||
DEFAULTS.add(double.class);
|
||||
DEFAULTS.add(double[].class);
|
||||
DEFAULTS.add(char.class);
|
||||
DEFAULTS.add(char[].class);
|
||||
DEFAULTS.add(Boolean.class);
|
||||
DEFAULTS.add(Long.class);
|
||||
DEFAULTS.add(Short.class);
|
||||
DEFAULTS.add(Integer.class);
|
||||
DEFAULTS.add(Byte.class);
|
||||
DEFAULTS.add(Float.class);
|
||||
DEFAULTS.add(Double.class);
|
||||
DEFAULTS.add(Character.class);
|
||||
DEFAULTS.add(String.class);
|
||||
DEFAULTS.add(Date.class);
|
||||
DEFAULTS.add(Locale.class);
|
||||
DEFAULTS.add(Class.class);
|
||||
DEFAULTS.add(Enum.class);
|
||||
}
|
||||
|
||||
private final Set<Class<?>> simpleTypes;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleTypeHolder} containing the default types.
|
||||
*
|
||||
* @see #SimpleTypeHolder(Set, boolean)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public SimpleTypeHolder() {
|
||||
this(Collections.EMPTY_SET, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleTypeHolder} to carry the given custom simple types. Registration of default simple types
|
||||
* can be deactivated by passing {@literal false} for {@code registerDefaults}.
|
||||
*
|
||||
* @param customSimpleTypes
|
||||
* @param registerDefaults
|
||||
*/
|
||||
public SimpleTypeHolder(Set<? extends Class<?>> customSimpleTypes, boolean registerDefaults) {
|
||||
|
||||
Assert.notNull(customSimpleTypes);
|
||||
this.simpleTypes = new HashSet<Class<?>>(customSimpleTypes);
|
||||
|
||||
if (registerDefaults) {
|
||||
this.simpleTypes.addAll(DEFAULTS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor to create a new {@link SimpleTypeHolder} that carries the given additional custom simple types.
|
||||
*
|
||||
* @param customSimpleTypes must not be {@literal null}
|
||||
* @param source must not be {@literal null}
|
||||
*/
|
||||
public SimpleTypeHolder(Set<? extends Class<?>> customSimpleTypes, SimpleTypeHolder source) {
|
||||
|
||||
Assert.notNull(customSimpleTypes);
|
||||
Assert.notNull(source);
|
||||
|
||||
this.simpleTypes = new HashSet<Class<?>>(customSimpleTypes);
|
||||
this.simpleTypes.addAll(source.simpleTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given type is considered a simple one.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public boolean isSimpleType(Class<?> type) {
|
||||
Assert.notNull(type);
|
||||
if (Object.class.equals(type)) {
|
||||
return true;
|
||||
}
|
||||
for (Class<?> clazz : simpleTypes) {
|
||||
if (type == clazz || clazz.isAssignableFrom(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.beans.factory.BeanFactory;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
* Simple factory to create {@link SpelExpressionParser} and {@link EvaluationContext} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SpELContext {
|
||||
|
||||
private final SpelExpressionParser parser;
|
||||
private final PropertyAccessor accessor;
|
||||
private final BeanFactory factory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpELContext} with the given {@link PropertyAccessor}. Defaults the
|
||||
* {@link SpelExpressionParser}.
|
||||
*
|
||||
* @param accessor
|
||||
*/
|
||||
public SpELContext(PropertyAccessor accessor) {
|
||||
this(accessor, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpELContext} using the given {@link SpelExpressionParser} and {@link PropertyAccessor}. Will
|
||||
* default the {@link SpelExpressionParser} in case the given value for it is {@literal null}.
|
||||
*
|
||||
* @param parser
|
||||
* @param accessor
|
||||
*/
|
||||
public SpELContext(SpelExpressionParser parser, PropertyAccessor accessor) {
|
||||
this(accessor, parser, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor to create a {@link SpELContext} using the given one's {@link PropertyAccessor} and
|
||||
* {@link SpelExpressionParser} as well as the given {@link BeanFactory}.
|
||||
*
|
||||
* @param source
|
||||
* @param factory
|
||||
*/
|
||||
public SpELContext(SpELContext source, BeanFactory factory) {
|
||||
this(source.accessor, source.parser, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpELContext} using the given {@link SpelExpressionParser}, {@link PropertyAccessor} and
|
||||
* {@link BeanFactory}. Will default the {@link SpelExpressionParser} in case the given value for it is
|
||||
* {@literal null}.
|
||||
*
|
||||
* @param accessor
|
||||
* @param parser
|
||||
* @param factory
|
||||
*/
|
||||
private SpELContext(PropertyAccessor accessor, SpelExpressionParser parser, BeanFactory factory) {
|
||||
|
||||
this.parser = parser == null ? new SpelExpressionParser() : parser;
|
||||
this.accessor = accessor;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.SpELContext#getParser()
|
||||
*/
|
||||
public ExpressionParser getParser() {
|
||||
return this.parser;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.SpELContext#getEvaluationContext(java.lang.Object)
|
||||
*/
|
||||
public EvaluationContext getEvaluationContext(Object source) {
|
||||
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(source);
|
||||
|
||||
if (accessor != null) {
|
||||
evaluationContext.addPropertyAccessor(accessor);
|
||||
}
|
||||
|
||||
if (factory != null) {
|
||||
evaluationContext.setBeanResolver(new BeanFactoryResolver(factory));
|
||||
}
|
||||
|
||||
return evaluationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* SPI for components that can evaluate Spring EL expressions.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface SpELExpressionEvaluator {
|
||||
|
||||
/**
|
||||
* Evaluates the given expression.
|
||||
*
|
||||
* @param expression
|
||||
* @return
|
||||
*/
|
||||
<T> T evaluate(String expression);
|
||||
}
|
||||
@@ -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.mapping.model;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ParameterValueProvider} that can be used to front a {@link ParameterValueProvider} delegate to prefer a Spel
|
||||
* expression evaluation over directly resolving the parameter value with the delegate.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SpELExpressionParameterValueProvider<P extends PersistentProperty<P>> implements ParameterValueProvider<P> {
|
||||
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
private final ParameterValueProvider<P> delegate;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpELExpressionParameterValueProvider} using the given {@link SpELExpressionEvaluator},
|
||||
* {@link ConversionService} and {@link ParameterValueProvider} delegate to forward calls to, that resolve parameters
|
||||
* that do not have a Spel expression configured with them.
|
||||
*
|
||||
* @param evaluator must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
* @param delegate must not be {@literal null}.
|
||||
*/
|
||||
public SpELExpressionParameterValueProvider(SpELExpressionEvaluator evaluator, ConversionService conversionService,
|
||||
ParameterValueProvider<P> delegate) {
|
||||
|
||||
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null!");
|
||||
Assert.notNull(conversionService, "ConversionService must not be null!");
|
||||
Assert.notNull(delegate, "ParameterValueProvider delegate must not be null!");
|
||||
|
||||
this.evaluator = evaluator;
|
||||
this.conversionService = conversionService;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.ParameterValueProvider#getParameterValue(org.springframework.data.mapping.PreferredConstructor.Parameter)
|
||||
*/
|
||||
public <T> T getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
if (!parameter.hasSpelExpression()) {
|
||||
return delegate == null ? null : delegate.getParameterValue(parameter);
|
||||
}
|
||||
|
||||
Object object = evaluator.evaluate(parameter.getSpelExpression());
|
||||
return object == null ? null : potentiallyConvertSpelValue(object, parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to allow to massage the value resulting from the Spel expression evaluation. Default implementation will
|
||||
* leverage the configured {@link ConversionService} to massage the value into the parameter type.
|
||||
*
|
||||
* @param object the value to massage, will never be {@literal null}.
|
||||
* @param parameter the {@link Parameter} we create the value for
|
||||
* @return
|
||||
*/
|
||||
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, P> parameter) {
|
||||
return conversionService.convert(object, parameter.getRawType());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Core implementation of the mapping subsystem's model.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Base package for the mapping subsystem.
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
Reference in New Issue
Block a user