75 changed files with 935 additions and 4331 deletions
@ -0,0 +1,76 @@ |
|||||||
|
package org.springframework.persistence.document.test; |
||||||
|
|
||||||
|
import javax.persistence.Entity; |
||||||
|
import javax.persistence.Id; |
||||||
|
|
||||||
|
import org.springframework.persistence.RelatedEntity; |
||||||
|
|
||||||
|
@Entity |
||||||
|
public class Person { |
||||||
|
|
||||||
|
@Id Long id; |
||||||
|
|
||||||
|
private String name; |
||||||
|
|
||||||
|
private int age; |
||||||
|
|
||||||
|
private java.util.Date birthDate; |
||||||
|
|
||||||
|
// @Document // need to decide what the annotation here should be
|
||||||
|
@RelatedEntity |
||||||
|
public Resume resume; |
||||||
|
|
||||||
|
public Person() { |
||||||
|
} |
||||||
|
|
||||||
|
public Person(String name, int age) { |
||||||
|
this.name = name; |
||||||
|
this.age = age; |
||||||
|
this.birthDate = new java.util.Date(); |
||||||
|
} |
||||||
|
|
||||||
|
public void birthday() { |
||||||
|
++age; |
||||||
|
} |
||||||
|
|
||||||
|
public Long getId() { |
||||||
|
return id; |
||||||
|
} |
||||||
|
|
||||||
|
public void setId(Long id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
public void setName(String name) { |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
|
||||||
|
public int getAge() { |
||||||
|
return age; |
||||||
|
} |
||||||
|
|
||||||
|
public void setAge(int age) { |
||||||
|
this.age = age; |
||||||
|
} |
||||||
|
|
||||||
|
public java.util.Date getBirthDate() { |
||||||
|
return birthDate; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBirthDate(java.util.Date birthDate) { |
||||||
|
this.birthDate = birthDate; |
||||||
|
} |
||||||
|
|
||||||
|
public Resume getResume() { |
||||||
|
return resume; |
||||||
|
} |
||||||
|
|
||||||
|
public void setResume(Resume resume) { |
||||||
|
this.resume = resume; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,33 @@ |
|||||||
|
package org.springframework.persistence.document.test; |
||||||
|
|
||||||
|
import org.springframework.persistence.document.DocumentEntity; |
||||||
|
|
||||||
|
@DocumentEntity |
||||||
|
public class Resume { |
||||||
|
|
||||||
|
private String education = ""; |
||||||
|
|
||||||
|
private String jobs = ""; |
||||||
|
|
||||||
|
public String getEducation() { |
||||||
|
return education; |
||||||
|
} |
||||||
|
|
||||||
|
public void addEducation(String education) { |
||||||
|
this.education = this.education + (this.education.length() > 0 ? "; " : "") + education; |
||||||
|
} |
||||||
|
|
||||||
|
public String getJobs() { |
||||||
|
return jobs; |
||||||
|
} |
||||||
|
|
||||||
|
public void addJob(String job) { |
||||||
|
this.jobs = this.jobs + (this.jobs.length() > 0 ? "; " : "") + job; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "Resume [education=" + education + ", jobs=" + jobs + "]"; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,45 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.document.mongodb.mapping; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
public class MappingException extends RuntimeException { |
|
||||||
|
|
||||||
private final Object source; |
|
||||||
|
|
||||||
public MappingException(String s) { |
|
||||||
super(s); |
|
||||||
this.source = null; |
|
||||||
} |
|
||||||
|
|
||||||
public MappingException(String s, Object source) { |
|
||||||
super(String.format("Error encountered mapping object: %s", source)); |
|
||||||
this.source = source; |
|
||||||
} |
|
||||||
|
|
||||||
public MappingException(String s, Throwable throwable, Object source) { |
|
||||||
super(s, throwable); |
|
||||||
this.source = source; |
|
||||||
} |
|
||||||
|
|
||||||
public Object getSource() { |
|
||||||
return source; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,499 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.document.mongodb.mapping; |
|
||||||
|
|
||||||
import com.mongodb.DBRef; |
|
||||||
import org.apache.commons.logging.Log; |
|
||||||
import org.apache.commons.logging.LogFactory; |
|
||||||
import org.bson.types.CodeWScope; |
|
||||||
import org.bson.types.ObjectId; |
|
||||||
import org.springframework.beans.factory.InitializingBean; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
import org.springframework.context.ApplicationContext; |
|
||||||
import org.springframework.context.expression.BeanFactoryResolver; |
|
||||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer; |
|
||||||
import org.springframework.data.mapping.annotation.*; |
|
||||||
import org.springframework.data.mapping.model.MappingInstantiationException; |
|
||||||
import org.springframework.expression.Expression; |
|
||||||
import org.springframework.expression.spel.standard.SpelExpressionParser; |
|
||||||
import org.springframework.expression.spel.support.StandardEvaluationContext; |
|
||||||
|
|
||||||
import java.beans.BeanInfo; |
|
||||||
import java.beans.IntrospectionException; |
|
||||||
import java.beans.Introspector; |
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
import java.lang.annotation.Annotation; |
|
||||||
import java.lang.reflect.*; |
|
||||||
import java.math.BigInteger; |
|
||||||
import java.util.*; |
|
||||||
import java.util.concurrent.ConcurrentHashMap; |
|
||||||
import java.util.concurrent.ConcurrentMap; |
|
||||||
import java.util.regex.Pattern; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
public class MappingIntrospector<T> { |
|
||||||
|
|
||||||
private static final Log log = LogFactory.getLog(MappingIntrospector.class); |
|
||||||
private static final ConcurrentMap<Class<?>, MappingIntrospector<?>> introspectors = new ConcurrentHashMap<Class<?>, MappingIntrospector<?>>(); |
|
||||||
private static final Set<String> SIMPLE_TYPES; |
|
||||||
|
|
||||||
static { |
|
||||||
Set<String> basics = new HashSet<String>(); |
|
||||||
basics.add(boolean.class.getName()); |
|
||||||
basics.add(long.class.getName()); |
|
||||||
basics.add(short.class.getName()); |
|
||||||
basics.add(int.class.getName()); |
|
||||||
basics.add(byte.class.getName()); |
|
||||||
basics.add(float.class.getName()); |
|
||||||
basics.add(double.class.getName()); |
|
||||||
basics.add(char.class.getName()); |
|
||||||
basics.add(Boolean.class.getName()); |
|
||||||
basics.add(Long.class.getName()); |
|
||||||
basics.add(Short.class.getName()); |
|
||||||
basics.add(Integer.class.getName()); |
|
||||||
basics.add(Byte.class.getName()); |
|
||||||
basics.add(Float.class.getName()); |
|
||||||
basics.add(Double.class.getName()); |
|
||||||
basics.add(Character.class.getName()); |
|
||||||
basics.add(String.class.getName()); |
|
||||||
basics.add(java.util.Date.class.getName()); |
|
||||||
basics.add(Locale.class.getName()); |
|
||||||
basics.add(Class.class.getName()); |
|
||||||
basics.add(DBRef.class.getName()); |
|
||||||
basics.add(Pattern.class.getName()); |
|
||||||
basics.add(CodeWScope.class.getName()); |
|
||||||
basics.add(ObjectId.class.getName()); |
|
||||||
// TODO check on enums..
|
|
||||||
basics.add(Enum.class.getName()); |
|
||||||
SIMPLE_TYPES = Collections.unmodifiableSet(basics); |
|
||||||
} |
|
||||||
|
|
||||||
private final Class<T> clazz; |
|
||||||
private final BeanInfo beanInfo; |
|
||||||
private final Map<String, PropertyDescriptor> properties; |
|
||||||
private final Map<String, Field> fields; |
|
||||||
private final Set<Association> associations; |
|
||||||
private final Map<String, Method> setters; |
|
||||||
private final Map<String, Method> getters; |
|
||||||
private Field idField = null; |
|
||||||
private PropertyDescriptor idPropertyDescriptor = null; |
|
||||||
private List<String> ignoredProperties = new ArrayList<String>() {{ |
|
||||||
add("class"); |
|
||||||
}}; |
|
||||||
private List<Class<?>> validIdTypes = new ArrayList<Class<?>>() {{ |
|
||||||
add(ObjectId.class); |
|
||||||
add(String.class); |
|
||||||
add(BigInteger.class); |
|
||||||
}}; |
|
||||||
|
|
||||||
private SpelExpressionParser parser = new SpelExpressionParser(); |
|
||||||
private Map<String, Expression> expressions = new HashMap<String, Expression>(); |
|
||||||
private PreferredConstructor preferredConstructor = null; |
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"}) |
|
||||||
private MappingIntrospector(Class<T> clazz) throws MappingException { |
|
||||||
this.clazz = clazz; |
|
||||||
try { |
|
||||||
this.beanInfo = Introspector.getBeanInfo(clazz); |
|
||||||
} catch (IntrospectionException e) { |
|
||||||
throw new MappingException(e.getMessage(), e, clazz); |
|
||||||
} |
|
||||||
Map<String, PropertyDescriptor> properties = new HashMap<String, PropertyDescriptor>(); |
|
||||||
Map<String, Field> fields = new HashMap<String, Field>(); |
|
||||||
Set<Association> associations = new HashSet<Association>(); |
|
||||||
Map<String, Method> setters = new HashMap<String, Method>(); |
|
||||||
Map<String, Method> getters = new HashMap<String, Method>(); |
|
||||||
for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) { |
|
||||||
String name = descriptor.getName(); |
|
||||||
if (!ignoredProperties.contains(name)) { |
|
||||||
try { |
|
||||||
Field fld = clazz.getDeclaredField(name); |
|
||||||
Class<?> fldType = fld.getType(); |
|
||||||
fld.setAccessible(true); |
|
||||||
if (!isTransientField(fld)) { |
|
||||||
if (fld.isAnnotationPresent(Id.class)) { |
|
||||||
if (null == idField) { |
|
||||||
idField = fld; |
|
||||||
idPropertyDescriptor = descriptor; |
|
||||||
} else { |
|
||||||
log.warn("Only the first field found with the @Id annotation will be considered the ID. Ignoring " + idField); |
|
||||||
} |
|
||||||
continue; |
|
||||||
} else if (null == idField |
|
||||||
&& validIdTypes.contains(fldType) |
|
||||||
&& ("id".equals(name) || "_id".equals(name))) { |
|
||||||
idField = fld; |
|
||||||
idPropertyDescriptor = descriptor; |
|
||||||
continue; |
|
||||||
} else if (fld.isAnnotationPresent(Reference.class) |
|
||||||
|| fld.isAnnotationPresent(OneToMany.class) |
|
||||||
|| fld.isAnnotationPresent(OneToOne.class) |
|
||||||
|| fld.isAnnotationPresent(ManyToMany.class)) { |
|
||||||
Class<?> targetClass = fld.getType(); |
|
||||||
if (fld.isAnnotationPresent(Reference.class)) { |
|
||||||
Reference ref = fld.getAnnotation(Reference.class); |
|
||||||
if (ref.targetClass() != Object.class) { |
|
||||||
targetClass = ref.targetClass(); |
|
||||||
} |
|
||||||
} |
|
||||||
if (fldType.isAssignableFrom(Collection.class) || fldType.isAssignableFrom(List.class)) { |
|
||||||
Type t = fld.getGenericType(); |
|
||||||
if (t instanceof ParameterizedType) { |
|
||||||
ParameterizedType ptype = (ParameterizedType) t; |
|
||||||
Type[] paramTypes = ptype.getActualTypeArguments(); |
|
||||||
if (paramTypes.length > 0) { |
|
||||||
if (paramTypes[0] instanceof TypeVariable) { |
|
||||||
targetClass = Object.class; |
|
||||||
} else { |
|
||||||
targetClass = (Class<?>) paramTypes[0]; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
associations.add(new Association(descriptor, fld, targetClass)); |
|
||||||
continue; |
|
||||||
} else if (fld.isAnnotationPresent(Value.class)) { |
|
||||||
// @Value fields are evaluated at runtime and are the same transient fields
|
|
||||||
continue; |
|
||||||
} |
|
||||||
fields.put(name, fld); |
|
||||||
properties.put(name, descriptor); |
|
||||||
setters.put(name, descriptor.getWriteMethod()); |
|
||||||
getters.put(name, descriptor.getReadMethod()); |
|
||||||
if (fld.isAnnotationPresent(Value.class)) { |
|
||||||
expressions.put(name, parser.parseExpression(fld.getAnnotation(Value.class).value())); |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (NoSuchFieldException e) { |
|
||||||
log.warn(e.getMessage()); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (null == this.idField) { |
|
||||||
// ID might be in a private field
|
|
||||||
for (Field f : fields.values()) { |
|
||||||
Class<?> type = f.getType(); |
|
||||||
if (f.isAnnotationPresent(Id.class)) { |
|
||||||
this.idField = f; |
|
||||||
break; |
|
||||||
} else if (validIdTypes.contains(type) && (f.getName().equals("id") || f.getName().equals("_id"))) { |
|
||||||
this.idField = f; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
this.properties = Collections.unmodifiableMap(properties); |
|
||||||
this.fields = Collections.unmodifiableMap(fields); |
|
||||||
this.associations = Collections.unmodifiableSet(associations); |
|
||||||
this.setters = Collections.unmodifiableMap(setters); |
|
||||||
this.getters = Collections.unmodifiableMap(getters); |
|
||||||
|
|
||||||
// Find the right constructor
|
|
||||||
for (Constructor<?> constructor : clazz.getConstructors()) { |
|
||||||
if (constructor.getParameterTypes().length != 0) { |
|
||||||
// Non-no-arg constructor
|
|
||||||
if (null == preferredConstructor || constructor.isAnnotationPresent(PersistenceConstructor.class)) { |
|
||||||
String[] paramNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(constructor); |
|
||||||
Type[] paramTypes = constructor.getGenericParameterTypes(); |
|
||||||
Class<?>[] paramClassTypes = new Class[paramTypes.length]; |
|
||||||
for (int i = 0; i < paramTypes.length; i++) { |
|
||||||
Class<?> targetType; |
|
||||||
if (paramTypes[i] instanceof ParameterizedType) { |
|
||||||
ParameterizedType ptype = (ParameterizedType) paramTypes[i]; |
|
||||||
Type[] types = ptype.getActualTypeArguments(); |
|
||||||
if (types.length == 1) { |
|
||||||
if (types[0] instanceof TypeVariable) { |
|
||||||
// Placeholder type
|
|
||||||
targetType = Object.class; |
|
||||||
} else { |
|
||||||
targetType = (Class<?>) types[0]; |
|
||||||
} |
|
||||||
} else { |
|
||||||
targetType = (Class<?>) ptype.getRawType(); |
|
||||||
} |
|
||||||
} else { |
|
||||||
targetType = (Class<?>) paramTypes[i]; |
|
||||||
} |
|
||||||
paramClassTypes[i] = targetType; |
|
||||||
} |
|
||||||
preferredConstructor = new PreferredConstructor((Constructor<T>) constructor, paramNames, paramClassTypes); |
|
||||||
if (constructor.isAnnotationPresent(PersistenceConstructor.class)) { |
|
||||||
// We're done
|
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"}) |
|
||||||
public static <C extends Object> MappingIntrospector<C> getInstance(Class<C> clazz) throws MappingException { |
|
||||||
MappingIntrospector<C> introspector = (MappingIntrospector<C>) introspectors.get(clazz); |
|
||||||
if (null == introspector) { |
|
||||||
introspector = new MappingIntrospector<C>(clazz); |
|
||||||
introspectors.put(clazz, introspector); |
|
||||||
} |
|
||||||
return introspector; |
|
||||||
} |
|
||||||
|
|
||||||
public Class<T> getTargetClass() { |
|
||||||
return clazz; |
|
||||||
} |
|
||||||
|
|
||||||
public Field getField(String name) { |
|
||||||
return fields.get(name); |
|
||||||
} |
|
||||||
|
|
||||||
public PropertyDescriptor getPropertyDescriptor(String name) { |
|
||||||
return properties.get(name); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isMappable() { |
|
||||||
return (null != clazz.getAnnotation(Persistent.class)); |
|
||||||
} |
|
||||||
|
|
||||||
public Field getIdField() { |
|
||||||
return idField; |
|
||||||
} |
|
||||||
|
|
||||||
public PropertyDescriptor getIdPropertyDescriptor() { |
|
||||||
return idPropertyDescriptor; |
|
||||||
} |
|
||||||
|
|
||||||
public T createInstance() { |
|
||||||
return createInstance(null); |
|
||||||
} |
|
||||||
|
|
||||||
public T createInstance(ParameterValueProvider provider) { |
|
||||||
try { |
|
||||||
if (null == preferredConstructor || null == provider) { |
|
||||||
return clazz.newInstance(); |
|
||||||
} else { |
|
||||||
List<Object> params = new LinkedList<Object>(); |
|
||||||
for (ConstructorParameter<?> p : preferredConstructor.parameters) { |
|
||||||
Expression x = null; |
|
||||||
Value v = p.getValueAnnotation(); |
|
||||||
if (null != v) { |
|
||||||
x = parser.parseExpression(v.value()); |
|
||||||
} |
|
||||||
params.add(provider.getParameterValue(p.name, p.type, x)); |
|
||||||
} |
|
||||||
return preferredConstructor.constructor.newInstance(params.toArray()); |
|
||||||
} |
|
||||||
} catch (InvocationTargetException e) { |
|
||||||
throw new MappingInstantiationException(e.getMessage(), e); |
|
||||||
} catch (InstantiationException e) { |
|
||||||
throw new MappingInstantiationException(e.getMessage(), e); |
|
||||||
} catch (IllegalAccessException e) { |
|
||||||
throw new MappingInstantiationException(e.getMessage(), e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Object getFieldValue(String name, Object from) throws MappingException { |
|
||||||
return getFieldValue(name, from, null); |
|
||||||
} |
|
||||||
|
|
||||||
public Object getFieldValue(String name, Object from, Object defaultObj) throws MappingException { |
|
||||||
try { |
|
||||||
if (properties.containsKey(name) && null != getters.get(name)) { |
|
||||||
return getters.get(name).invoke(from); |
|
||||||
} else { |
|
||||||
if (fields.containsKey(name)) { |
|
||||||
Field f = fields.get(name); |
|
||||||
return f.get(from); |
|
||||||
} else { |
|
||||||
for (Association assoc : associations) { |
|
||||||
if (assoc.getField().getName().equals(name)) { |
|
||||||
return assoc.getField().get(from); |
|
||||||
} |
|
||||||
} |
|
||||||
for (Field f : clazz.getDeclaredFields()) { |
|
||||||
// Lastly, check for any private fields
|
|
||||||
if (f.getName().equals(name)) { |
|
||||||
f.setAccessible(true); |
|
||||||
return f.get(from); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (IllegalAccessException e) { |
|
||||||
throw new MappingException(e.getMessage(), e, from); |
|
||||||
} catch (InvocationTargetException e) { |
|
||||||
throw new MappingException(e.getMessage(), e, from); |
|
||||||
} |
|
||||||
return defaultObj; |
|
||||||
} |
|
||||||
|
|
||||||
public void setValue(String name, Object on, Object value) throws MappingException { |
|
||||||
Field f = fields.get(name); |
|
||||||
try { |
|
||||||
if (null != f) { |
|
||||||
Method setter = setters.get(name); |
|
||||||
if (null != setter) { |
|
||||||
setter.invoke(on, value); |
|
||||||
} else { |
|
||||||
f.set(on, value); |
|
||||||
} |
|
||||||
} else { |
|
||||||
for (Association assoc : associations) { |
|
||||||
if (assoc.getField().getName().equals(name)) { |
|
||||||
assoc.getField().set(on, value); |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
for (Field privFld : clazz.getDeclaredFields()) { |
|
||||||
if (privFld.getName().equals(name)) { |
|
||||||
privFld.setAccessible(true); |
|
||||||
privFld.set(on, value); |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (IllegalAccessException e) { |
|
||||||
throw new MappingException(e.getMessage(), e, value); |
|
||||||
} catch (InvocationTargetException e) { |
|
||||||
throw new MappingException(e.getMessage(), e, value); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void maybeAutowire(Object obj, ApplicationContext applicationContext, boolean autowire) throws MappingException { |
|
||||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(obj); |
|
||||||
evaluationContext.setBeanResolver(new BeanFactoryResolver(applicationContext)); |
|
||||||
|
|
||||||
if (autowire) { |
|
||||||
applicationContext.getAutowireCapableBeanFactory().autowireBean(obj); |
|
||||||
if (obj instanceof InitializingBean) { |
|
||||||
try { |
|
||||||
((InitializingBean) obj).afterPropertiesSet(); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new MappingException(e.getMessage(), e, obj); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for (Map.Entry<String, Expression> entry : expressions.entrySet()) { |
|
||||||
setValue(entry.getKey(), obj, entry.getValue().getValue(evaluationContext)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void doWithProperties(PropertyHandler handler) { |
|
||||||
for (Map.Entry<String, PropertyDescriptor> entry : properties.entrySet()) { |
|
||||||
String name = entry.getKey(); |
|
||||||
handler.doWithProperty(entry.getValue(), fields.get(name), expressions.get(name)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void doWithAssociations(AssociationHandler handler) { |
|
||||||
for (Association association : associations) { |
|
||||||
handler.doWithAssociation(association); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isSimpleType(Class<?> propertyType) { |
|
||||||
if (propertyType == null) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
if (propertyType.isArray()) { |
|
||||||
return isSimpleType(propertyType.getComponentType()); |
|
||||||
} |
|
||||||
return SIMPLE_TYPES.contains(propertyType.getName()); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isTransientField(Field f) { |
|
||||||
return (Modifier.isTransient(f.getModifiers()) || null != f.getAnnotation(Transient.class) || null != f.getAnnotation(Autowired.class)); |
|
||||||
} |
|
||||||
|
|
||||||
public static class Association { |
|
||||||
|
|
||||||
private final PropertyDescriptor descriptor; |
|
||||||
private final Field field; |
|
||||||
private final Class<?> targetClass; |
|
||||||
|
|
||||||
public Association(PropertyDescriptor descriptor, Field field, Class<?> targetClass) { |
|
||||||
this.descriptor = descriptor; |
|
||||||
this.field = field; |
|
||||||
this.targetClass = targetClass; |
|
||||||
} |
|
||||||
|
|
||||||
public PropertyDescriptor getDescriptor() { |
|
||||||
return descriptor; |
|
||||||
} |
|
||||||
|
|
||||||
public Field getField() { |
|
||||||
return field; |
|
||||||
} |
|
||||||
|
|
||||||
public Class<?> getTargetClass() { |
|
||||||
return targetClass; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private class PreferredConstructor { |
|
||||||
|
|
||||||
Constructor<T> constructor; |
|
||||||
ConstructorParameter<?>[] parameters; |
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"}) |
|
||||||
public PreferredConstructor(Constructor<T> constructor, String[] names, Class<?>[] types) { |
|
||||||
this.constructor = constructor; |
|
||||||
Annotation[][] annos = constructor.getParameterAnnotations(); |
|
||||||
parameters = new ConstructorParameter[names.length]; |
|
||||||
for (int i = 0; i < names.length; i++) { |
|
||||||
parameters[i] = new ConstructorParameter(names[i], types[i], annos[i]); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private class ConstructorParameter<V> { |
|
||||||
String name; |
|
||||||
Class<V> type; |
|
||||||
Annotation[] annotations; |
|
||||||
|
|
||||||
private ConstructorParameter(String name, Class<V> type, Annotation[] annotations) { |
|
||||||
this.name = name; |
|
||||||
this.type = type; |
|
||||||
this.annotations = annotations; |
|
||||||
} |
|
||||||
|
|
||||||
private Value getValueAnnotation() { |
|
||||||
for (Annotation anno : annotations) { |
|
||||||
if (anno instanceof Value) { |
|
||||||
return (Value) anno; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public interface AssociationHandler { |
|
||||||
void doWithAssociation(Association association); |
|
||||||
} |
|
||||||
|
|
||||||
public interface PropertyHandler { |
|
||||||
void doWithProperty(PropertyDescriptor descriptor, Field field, Expression spelExpr); |
|
||||||
} |
|
||||||
|
|
||||||
public interface ParameterValueProvider { |
|
||||||
<T> T getParameterValue(String name, Class<T> type, Expression spelExpr); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,33 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.document.mongodb.mapping; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.AbstractClassMapping; |
|
||||||
import org.springframework.data.mapping.model.MappingContext; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
|
|
||||||
public class MongoClassMapping extends AbstractClassMapping<MongoCollection> { |
|
||||||
|
|
||||||
public MongoClassMapping(PersistentEntity entity, MappingContext context) { |
|
||||||
super(entity, context); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public MongoCollection getMappedForm() { |
|
||||||
return (MongoCollection) context.getMappingFactory().createMappedForm(entity); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,37 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.document.mongodb.mapping; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
public class MongoCollection { |
|
||||||
|
|
||||||
private String name; |
|
||||||
|
|
||||||
public MongoCollection(String name) { |
|
||||||
this.name = name; |
|
||||||
} |
|
||||||
|
|
||||||
public String getName() { |
|
||||||
return name; |
|
||||||
} |
|
||||||
|
|
||||||
public void setName(String name) { |
|
||||||
this.name = name; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,167 @@ |
|||||||
|
/* |
||||||
|
* 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.document.mongodb.mapping; |
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject; |
||||||
|
import com.mongodb.DBCollection; |
||||||
|
import com.mongodb.DBObject; |
||||||
|
import com.mongodb.MongoException; |
||||||
|
import com.mongodb.util.JSON; |
||||||
|
import org.bson.types.CodeWScope; |
||||||
|
import org.bson.types.ObjectId; |
||||||
|
import org.springframework.dao.DataAccessException; |
||||||
|
import org.springframework.data.document.mongodb.CollectionCallback; |
||||||
|
import org.springframework.data.document.mongodb.MongoTemplate; |
||||||
|
import org.springframework.data.document.mongodb.index.CompoundIndex; |
||||||
|
import org.springframework.data.document.mongodb.index.CompoundIndexes; |
||||||
|
import org.springframework.data.document.mongodb.index.IndexDirection; |
||||||
|
import org.springframework.data.document.mongodb.index.Indexed; |
||||||
|
import org.springframework.data.mapping.BasicMappingConfigurationBuilder; |
||||||
|
import org.springframework.data.mapping.MappingBeanHelper; |
||||||
|
import org.springframework.data.mapping.model.*; |
||||||
|
|
||||||
|
import java.beans.PropertyDescriptor; |
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.math.BigInteger; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Jon Brisbin <jbrisbin@vmware.com> |
||||||
|
*/ |
||||||
|
public class MongoMappingConfigurationBuilder extends BasicMappingConfigurationBuilder { |
||||||
|
|
||||||
|
protected Map<String, CompoundIndex> compoundIndexes = new HashMap<String, CompoundIndex>(); |
||||||
|
protected Map<String, Indexed> fieldIndexes = new HashMap<String, Indexed>(); |
||||||
|
protected MongoTemplate mongoTemplate; |
||||||
|
|
||||||
|
public MongoMappingConfigurationBuilder(MongoTemplate mongoTemplate) { |
||||||
|
this.mongoTemplate = mongoTemplate; |
||||||
|
// Augment simpleTypes with MongoDB-specific classes
|
||||||
|
Set<String> simpleTypes = MappingBeanHelper.getSimpleTypes(); |
||||||
|
simpleTypes.add(DBRef.class.getName()); |
||||||
|
simpleTypes.add(ObjectId.class.getName()); |
||||||
|
simpleTypes.add(CodeWScope.class.getName()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public PersistentProperty<?> createPersistentProperty(Field field, PropertyDescriptor descriptor) throws MappingConfigurationException { |
||||||
|
PersistentProperty<?> property = super.createPersistentProperty(field, descriptor); |
||||||
|
if (field.isAnnotationPresent(Indexed.class)) { |
||||||
|
Indexed index = field.getAnnotation(Indexed.class); |
||||||
|
String collection = index.collection(); |
||||||
|
if ("".equals(collection)) { |
||||||
|
collection = field.getName(); |
||||||
|
} |
||||||
|
if (!fieldIndexes.containsKey(collection)) { |
||||||
|
ensureIndex(collection, index.name(), null, index.direction(), index.unique(), index.dropDups(), index.sparse()); |
||||||
|
fieldIndexes.put(collection, index); |
||||||
|
} |
||||||
|
} |
||||||
|
return property; |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked"}) |
||||||
|
@Override |
||||||
|
public <T> PersistentEntity<T> createPersistentEntity(Class<T> type, MappingContext mappingContext) throws MappingConfigurationException { |
||||||
|
MongoPersistentEntity<T> entity = new MongoPersistentEntity<T>(mappingContext, type); |
||||||
|
|
||||||
|
// Check for special collection setting
|
||||||
|
if (type.isAnnotationPresent(Document.class)) { |
||||||
|
Document doc = type.getAnnotation(Document.class); |
||||||
|
String collection = doc.collection(); |
||||||
|
if ("".equals(collection)) { |
||||||
|
collection = type.getSimpleName().toLowerCase(); |
||||||
|
} |
||||||
|
entity.setCollection(collection); |
||||||
|
} |
||||||
|
|
||||||
|
// Make sure indexes get created
|
||||||
|
if (type.isAnnotationPresent(CompoundIndexes.class)) { |
||||||
|
CompoundIndexes indexes = type.getAnnotation(CompoundIndexes.class); |
||||||
|
for (CompoundIndex index : indexes.value()) { |
||||||
|
String indexColl = index.collection(); |
||||||
|
if ("".equals(indexColl)) { |
||||||
|
indexColl = type.getSimpleName().toLowerCase(); |
||||||
|
} |
||||||
|
if (!compoundIndexes.containsKey(indexColl)) { |
||||||
|
ensureIndex(indexColl, index.name(), index.def(), index.direction(), index.unique(), index.dropDups(), index.sparse()); |
||||||
|
compoundIndexes.put(indexColl, index); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return entity; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAssociation(Field field, PropertyDescriptor descriptor) throws MappingConfigurationException { |
||||||
|
if (field.isAnnotationPresent(DBRef.class)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
return super.isAssociation(field, descriptor); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Association createAssociation(PersistentProperty<?> property) { |
||||||
|
return super.createAssociation(property); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean isIdField(Field field) { |
||||||
|
if (super.isIdField(field)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
if (field.getType() == ObjectId.class || field.getType() == BigInteger.class) { |
||||||
|
if ("id".equals(field.getName()) || "_id".equals(field.getName())) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
protected void ensureIndex(String collection, |
||||||
|
final String name, |
||||||
|
final String def, |
||||||
|
final IndexDirection direction, |
||||||
|
final boolean unique, |
||||||
|
final boolean dropDups, |
||||||
|
final boolean sparse) { |
||||||
|
mongoTemplate.execute(collection, new CollectionCallback<Object>() { |
||||||
|
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { |
||||||
|
DBObject defObj; |
||||||
|
if (null != def) { |
||||||
|
defObj = (DBObject) JSON.parse(def); |
||||||
|
} else { |
||||||
|
defObj = new BasicDBObject(); |
||||||
|
defObj.put(name, (direction == IndexDirection.ASCENDING ? 1 : -1)); |
||||||
|
} |
||||||
|
DBObject opts = new BasicDBObject(); |
||||||
|
if (!"".equals(name)) { |
||||||
|
opts.put("name", name); |
||||||
|
} |
||||||
|
opts.put("dropDups", dropDups); |
||||||
|
opts.put("sparse", sparse); |
||||||
|
opts.put("unique", unique); |
||||||
|
collection.ensureIndex(defObj, opts); |
||||||
|
return null; |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,417 +0,0 @@ |
|||||||
package org.springframework.data.document.mongodb.mapping; |
|
||||||
|
|
||||||
import com.mongodb.BasicDBObject; |
|
||||||
import com.mongodb.DBCollection; |
|
||||||
import com.mongodb.DBObject; |
|
||||||
import com.mongodb.MongoException; |
|
||||||
import com.mongodb.util.JSON; |
|
||||||
import org.apache.commons.logging.Log; |
|
||||||
import org.apache.commons.logging.LogFactory; |
|
||||||
import org.springframework.dao.DataAccessException; |
|
||||||
import org.springframework.data.document.mongodb.CollectionCallback; |
|
||||||
import org.springframework.data.document.mongodb.MongoTemplate; |
|
||||||
import org.springframework.data.document.mongodb.index.CompoundIndex; |
|
||||||
import org.springframework.data.document.mongodb.index.CompoundIndexes; |
|
||||||
import org.springframework.data.document.mongodb.index.IndexDirection; |
|
||||||
import org.springframework.data.document.mongodb.index.Indexed; |
|
||||||
import org.springframework.data.mapping.annotation.IdentifiedBy; |
|
||||||
import org.springframework.data.mapping.annotation.OneToOne; |
|
||||||
import org.springframework.data.mapping.annotation.PersistenceStrategy; |
|
||||||
import org.springframework.data.mapping.annotation.Persistent; |
|
||||||
import org.springframework.data.mapping.model.*; |
|
||||||
import org.springframework.data.mapping.model.types.Association; |
|
||||||
import org.springframework.expression.EvaluationContext; |
|
||||||
import org.springframework.expression.Expression; |
|
||||||
import org.springframework.expression.common.TemplateParserContext; |
|
||||||
import org.springframework.expression.spel.standard.SpelExpressionParser; |
|
||||||
import org.springframework.expression.spel.support.StandardEvaluationContext; |
|
||||||
import org.springframework.util.Assert; |
|
||||||
|
|
||||||
import java.beans.IntrospectionException; |
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
import java.lang.annotation.Annotation; |
|
||||||
import java.lang.reflect.Field; |
|
||||||
import java.lang.reflect.Method; |
|
||||||
import java.lang.reflect.ParameterizedType; |
|
||||||
import java.lang.reflect.Type; |
|
||||||
import java.util.*; |
|
||||||
import java.util.concurrent.ConcurrentHashMap; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author J. Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
public class MongoMappingConfigurationStrategy implements MappingConfigurationStrategy { |
|
||||||
|
|
||||||
protected static final Log log = LogFactory.getLog(MongoMappingConfigurationStrategy.class); |
|
||||||
|
|
||||||
protected MongoTemplate mongo; |
|
||||||
protected MongoMappingFactory mappingFactory; |
|
||||||
protected SpelExpressionParser expressionParser = new SpelExpressionParser(); |
|
||||||
protected TemplateParserContext templateParserContext = new TemplateParserContext(); |
|
||||||
protected Map<Class<?>, PersistenceDescriptor> descriptors = new ConcurrentHashMap<Class<?>, PersistenceDescriptor>(); |
|
||||||
protected Map<Class<?>, Set<PersistentEntity>> owners = new LinkedHashMap<Class<?>, Set<PersistentEntity>>(); |
|
||||||
|
|
||||||
public MongoMappingConfigurationStrategy(MongoTemplate mongo) { |
|
||||||
this.mongo = mongo; |
|
||||||
} |
|
||||||
|
|
||||||
public MongoMappingConfigurationStrategy(MongoTemplate mongo, MongoMappingFactory mappingFactory) { |
|
||||||
this.mongo = mongo; |
|
||||||
this.mappingFactory = mappingFactory; |
|
||||||
} |
|
||||||
|
|
||||||
public SpelExpressionParser getExpressionParser() { |
|
||||||
return expressionParser; |
|
||||||
} |
|
||||||
|
|
||||||
public void setExpressionParser(SpelExpressionParser expressionParser) { |
|
||||||
this.expressionParser = expressionParser; |
|
||||||
} |
|
||||||
|
|
||||||
public TemplateParserContext getTemplateParserContext() { |
|
||||||
return templateParserContext; |
|
||||||
} |
|
||||||
|
|
||||||
public void setTemplateParserContext(TemplateParserContext templateParserContext) { |
|
||||||
this.templateParserContext = templateParserContext; |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"}) |
|
||||||
public boolean isPersistentEntity(Class aClass) { |
|
||||||
if (null != aClass) { |
|
||||||
return (null != aClass.getAnnotation(Persistent.class)); |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public List<PersistentProperty> getPersistentProperties(Class aClass, MappingContext mappingContext) { |
|
||||||
return getPersistentProperties(aClass, mappingContext, null); |
|
||||||
} |
|
||||||
|
|
||||||
public List<PersistentProperty> getPersistentProperties(Class aClass, |
|
||||||
MappingContext mappingContext, |
|
||||||
ClassMapping classMapping) { |
|
||||||
PersistenceDescriptor pd = null; |
|
||||||
try { |
|
||||||
pd = getPersistenceDescriptor(aClass, mappingContext, classMapping); |
|
||||||
} catch (MappingException e) { |
|
||||||
log.error(e.getMessage(), e); |
|
||||||
} |
|
||||||
return (null != pd ? pd.getProperties() : null); |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentProperty getIdentity(Class aClass, MappingContext mappingContext) throws MappingException { |
|
||||||
PersistenceDescriptor idPd = getPersistenceDescriptor(aClass, mappingContext, null); |
|
||||||
return (null != idPd ? idPd.getIdProperty() : null); |
|
||||||
} |
|
||||||
|
|
||||||
public IdentityMapping getDefaultIdentityMapping(final ClassMapping classMapping) throws MappingException { |
|
||||||
final PersistentProperty<?> prop = getPersistenceDescriptor(classMapping.getEntity().getJavaClass(), |
|
||||||
classMapping.getEntity().getMappingContext(), |
|
||||||
classMapping).getIdProperty(); |
|
||||||
|
|
||||||
return new IdentityMapping() { |
|
||||||
public String[] getIdentifierName() { |
|
||||||
return new String[]{prop.getName()}; |
|
||||||
} |
|
||||||
|
|
||||||
public ClassMapping getClassMapping() { |
|
||||||
return classMapping; |
|
||||||
} |
|
||||||
|
|
||||||
public Object getMappedForm() { |
|
||||||
return classMapping.getMappedForm(); |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
public Set getOwningEntities(Class aClass, MappingContext mappingContext) { |
|
||||||
return owners.get(aClass); |
|
||||||
} |
|
||||||
|
|
||||||
protected PersistenceDescriptor getPersistenceDescriptor(final Class<?> javaClass, |
|
||||||
final MappingContext context, |
|
||||||
final ClassMapping mapping) throws MappingException { |
|
||||||
PersistenceDescriptor descriptor = descriptors.get(javaClass); |
|
||||||
if (null == descriptor) { |
|
||||||
final MappingIntrospector introspector = MappingIntrospector.getInstance(javaClass); |
|
||||||
final PersistentEntity entity = getPersistentEntity(javaClass, context, mapping); |
|
||||||
|
|
||||||
final String collection = javaClass.getSimpleName().toLowerCase(); |
|
||||||
for (Annotation anno : javaClass.getAnnotations()) { |
|
||||||
if (anno instanceof Persistent) { |
|
||||||
|
|
||||||
} else if (anno instanceof CompoundIndexes) { |
|
||||||
CompoundIndexes idxs = (CompoundIndexes) anno; |
|
||||||
for (CompoundIndex idx : idxs.value()) { |
|
||||||
String idxColl = collection; |
|
||||||
if (!"".equals(idx.collection())) { |
|
||||||
idxColl = idx.collection(); |
|
||||||
} |
|
||||||
String name = null; |
|
||||||
if (!"".equals(idx.name())) { |
|
||||||
name = idx.name(); |
|
||||||
} |
|
||||||
ensureIndex(idxColl, name, idx.def(), null, idx.unique(), idx.dropDups(), idx.sparse()); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
EvaluationContext elContext = new StandardEvaluationContext(); |
|
||||||
elContext.setVariable("class", javaClass); |
|
||||||
|
|
||||||
PropertyDescriptor idPropDesc = MappingIntrospector.getInstance(entity.getJavaClass()).getIdPropertyDescriptor(); |
|
||||||
PersistentProperty<?> id = mappingFactory.createIdentity(entity, context, idPropDesc); |
|
||||||
|
|
||||||
final List<PersistentProperty> properties = new LinkedList<PersistentProperty>(); |
|
||||||
introspector.doWithProperties(new MappingIntrospector.PropertyHandler() { |
|
||||||
public void doWithProperty(PropertyDescriptor descriptor, Field field, Expression spelExpr) { |
|
||||||
PersistentProperty<?> p = null; |
|
||||||
try { |
|
||||||
p = createPersistentProperty(entity, context, descriptor, mapping); |
|
||||||
if (null != p) { |
|
||||||
properties.add(p); |
|
||||||
for (Annotation anno : field.getDeclaredAnnotations()) { |
|
||||||
if (anno instanceof Indexed) { |
|
||||||
Indexed idx = (Indexed) anno; |
|
||||||
String idxColl = collection; |
|
||||||
if (!"".equals(idx.collection())) { |
|
||||||
idxColl = idx.collection(); |
|
||||||
} |
|
||||||
String name = p.getName(); |
|
||||||
if (!"".equals(idx.name())) { |
|
||||||
name = idx.name(); |
|
||||||
} |
|
||||||
ensureIndex(idxColl, name, null, idx.direction(), idx.unique(), idx.dropDups(), idx.sparse()); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (MappingException e) { |
|
||||||
throw new IllegalMappingException(e.getMessage(), e); |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
descriptor = new PersistenceDescriptor(entity, id, properties); |
|
||||||
descriptors.put(javaClass, descriptor); |
|
||||||
} |
|
||||||
return descriptor; |
|
||||||
} |
|
||||||
|
|
||||||
protected PersistentEntity getPersistentEntity(Class<?> javaClass, MappingContext context, ClassMapping mapping) { |
|
||||||
Assert.notNull(javaClass); |
|
||||||
if (null != mapping) { |
|
||||||
return mapping.getEntity(); |
|
||||||
} else { |
|
||||||
return context.getPersistentEntity(javaClass.getName()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected PersistentProperty<?> createPersistentProperty(PersistentEntity entity, |
|
||||||
MappingContext mappingContext, |
|
||||||
PropertyDescriptor descriptor, |
|
||||||
ClassMapping mapping) throws MappingException { |
|
||||||
MappingIntrospector introspector = MappingIntrospector.getInstance(entity.getJavaClass()); |
|
||||||
Field f = introspector.getField(descriptor.getName()); |
|
||||||
|
|
||||||
if (null != f) { |
|
||||||
// Handle associations and persistent types
|
|
||||||
PersistentProperty<?> prop = extractChildType(entity, mappingContext, descriptor, mapping); |
|
||||||
if (null == prop) { |
|
||||||
// Must be a simple type
|
|
||||||
prop = mappingFactory.createSimple(entity, mappingContext, descriptor); |
|
||||||
} |
|
||||||
return prop; |
|
||||||
} |
|
||||||
|
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
protected PersistentProperty<?> extractChildType(PersistentEntity entity, |
|
||||||
MappingContext mappingContext, |
|
||||||
PropertyDescriptor descriptor, |
|
||||||
ClassMapping mapping) throws MappingException { |
|
||||||
MappingIntrospector introspector = MappingIntrospector.getInstance(entity.getJavaClass()); |
|
||||||
Field f = introspector.getField(descriptor.getName()); |
|
||||||
|
|
||||||
Class<?> childClass = null; |
|
||||||
Association<?> assoc = null; |
|
||||||
if (f.getType().isAssignableFrom(List.class)) { |
|
||||||
if (null != f.getAnnotation(org.springframework.data.mapping.annotation.OneToMany.class)) { |
|
||||||
org.springframework.data.mapping.annotation.OneToMany otm = f.getAnnotation( |
|
||||||
org.springframework.data.mapping.annotation.OneToMany.class); |
|
||||||
if (Object.class != otm.targetClass()) { |
|
||||||
childClass = otm.targetClass(); |
|
||||||
} else { |
|
||||||
childClass = extractType(f); |
|
||||||
} |
|
||||||
assoc = mappingFactory.createOneToMany(entity, mappingContext, descriptor); |
|
||||||
} else if (null != f.getAnnotation(org.springframework.data.mapping.annotation.ManyToMany.class)) { |
|
||||||
org.springframework.data.mapping.annotation.ManyToMany mtm = f.getAnnotation( |
|
||||||
org.springframework.data.mapping.annotation.ManyToMany.class); |
|
||||||
if (Object.class != mtm.targetClass()) { |
|
||||||
childClass = mtm.targetClass(); |
|
||||||
} else { |
|
||||||
childClass = extractType(f); |
|
||||||
} |
|
||||||
assoc = mappingFactory.createManyToMany(entity, mappingContext, descriptor); |
|
||||||
} |
|
||||||
} else { |
|
||||||
if (null != f.getAnnotation(OneToOne.class) || null != f.getType().getAnnotation(Persistent.class)) { |
|
||||||
childClass = f.getType(); |
|
||||||
assoc = mappingFactory.createOneToOne(entity, mappingContext, descriptor); |
|
||||||
} |
|
||||||
} |
|
||||||
if (null != childClass && null != assoc) { |
|
||||||
if (childClass != entity.getJavaClass()) { |
|
||||||
PersistentEntity childEntity = getPersistentEntity(childClass, mappingContext, mapping); |
|
||||||
addOwner(entity.getJavaClass(), childEntity); |
|
||||||
assoc.setAssociatedEntity(childEntity); |
|
||||||
} else { |
|
||||||
addOwner(entity.getJavaClass(), entity); |
|
||||||
assoc.setAssociatedEntity(entity); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return assoc; |
|
||||||
} |
|
||||||
|
|
||||||
protected Class<?> extractType(Field f) { |
|
||||||
Type t = f.getGenericType(); |
|
||||||
if (null != t && t instanceof ParameterizedType) { |
|
||||||
Type[] types = ((ParameterizedType) t).getActualTypeArguments(); |
|
||||||
return ((Class) types[0]); |
|
||||||
} |
|
||||||
return f.getType(); |
|
||||||
} |
|
||||||
|
|
||||||
protected IdentifiedBy extractIdentifiedBy(Class<?> clazz, Field field) { |
|
||||||
Persistent cAnno = clazz.getAnnotation(Persistent.class); |
|
||||||
Persistent fldAnno = (null != field ? field.getAnnotation(Persistent.class) : null); |
|
||||||
return (null != fldAnno ? fldAnno.identifiedBy() : cAnno.identifiedBy()); |
|
||||||
} |
|
||||||
|
|
||||||
protected PersistenceStrategy extractPersistenceStrategy(Class<?> clazz, Field field) { |
|
||||||
Persistent cAnno = clazz.getAnnotation(Persistent.class); |
|
||||||
Persistent fldAnno = (null != field ? field.getAnnotation(Persistent.class) : null); |
|
||||||
return (null != fldAnno ? fldAnno.strategy() : cAnno.strategy()); |
|
||||||
} |
|
||||||
|
|
||||||
protected String extractId(Class<?> clazz, Field field) { |
|
||||||
Persistent cAnno = clazz.getAnnotation(Persistent.class); |
|
||||||
Persistent fldAnno = (null != field ? field.getAnnotation(Persistent.class) : null); |
|
||||||
return (null != fldAnno ? fldAnno.id() : cAnno.id()); |
|
||||||
} |
|
||||||
|
|
||||||
protected void addOwner(Class<?> javaClass, PersistentEntity parent) { |
|
||||||
if (!owners.containsKey(javaClass)) { |
|
||||||
Set<PersistentEntity> owningEntities = new HashSet<PersistentEntity>(); |
|
||||||
owningEntities.add(parent); |
|
||||||
owners.put(javaClass, owningEntities); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected void ensureIndex(String collection, |
|
||||||
final String name, |
|
||||||
final String def, |
|
||||||
final IndexDirection direction, |
|
||||||
final boolean unique, |
|
||||||
final boolean dropDups, |
|
||||||
final boolean sparse) { |
|
||||||
mongo.execute(collection, new CollectionCallback<Object>() { |
|
||||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { |
|
||||||
DBObject defObj; |
|
||||||
if (null != def) { |
|
||||||
defObj = (DBObject) JSON.parse(def); |
|
||||||
} else { |
|
||||||
defObj = new BasicDBObject(); |
|
||||||
defObj.put(name, (direction == IndexDirection.ASCENDING ? 1 : -1)); |
|
||||||
} |
|
||||||
DBObject opts = new BasicDBObject(); |
|
||||||
if (!"".equals(name)) { |
|
||||||
opts.put("name", name); |
|
||||||
} |
|
||||||
opts.put("dropDups", dropDups); |
|
||||||
opts.put("sparse", sparse); |
|
||||||
opts.put("unique", unique); |
|
||||||
collection.ensureIndex(defObj, opts); |
|
||||||
return null; |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
protected class PersistenceDescriptor { |
|
||||||
|
|
||||||
PersistentEntity entity; |
|
||||||
PersistentProperty idProperty = null; |
|
||||||
List<PersistentProperty> properties = null; |
|
||||||
|
|
||||||
PersistenceDescriptor(PersistentEntity entity, PersistentProperty idProperty, List<PersistentProperty> properties) { |
|
||||||
this.entity = entity; |
|
||||||
this.idProperty = idProperty; |
|
||||||
this.properties = properties; |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentEntity getEntity() { |
|
||||||
return entity; |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentProperty getIdProperty() { |
|
||||||
return idProperty; |
|
||||||
} |
|
||||||
|
|
||||||
public List<PersistentProperty> getProperties() { |
|
||||||
return properties; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
protected class ValuePropertyDescriptor extends PropertyDescriptor { |
|
||||||
|
|
||||||
Object value; |
|
||||||
|
|
||||||
ValuePropertyDescriptor(String s, Class<?> aClass, Object value) throws IntrospectionException { |
|
||||||
super(s, aClass); |
|
||||||
this.value = value; |
|
||||||
} |
|
||||||
|
|
||||||
public Object getValue() { |
|
||||||
return value; |
|
||||||
} |
|
||||||
|
|
||||||
public void setValue(Object value) { |
|
||||||
this.value = value; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Method getReadMethod() { |
|
||||||
try { |
|
||||||
return getClass().getMethod("getValue", null); |
|
||||||
} catch (NoSuchMethodException e) { |
|
||||||
// IGNORED
|
|
||||||
} |
|
||||||
return super.getReadMethod(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setReadMethod(Method method) throws IntrospectionException { |
|
||||||
// IGNORED
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Method getWriteMethod() { |
|
||||||
try { |
|
||||||
return getClass().getMethod("setValue", Object.class); |
|
||||||
} catch (NoSuchMethodException e) { |
|
||||||
// IGNORED
|
|
||||||
} |
|
||||||
return super.getWriteMethod(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setWriteMethod(Method method) throws IntrospectionException { |
|
||||||
// IGNORED
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,59 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.document.mongodb.mapping; |
|
||||||
|
|
||||||
import org.springframework.data.document.mongodb.MongoTemplate; |
|
||||||
import org.springframework.data.mapping.model.AbstractMappingContext; |
|
||||||
import org.springframework.data.mapping.model.MappingConfigurationStrategy; |
|
||||||
import org.springframework.data.mapping.model.MappingFactory; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
public class MongoMappingContext extends AbstractMappingContext { |
|
||||||
|
|
||||||
private MongoTemplate mongo; |
|
||||||
private MongoMappingFactory mappingFactory = null; |
|
||||||
private MappingConfigurationStrategy strategy = null; |
|
||||||
|
|
||||||
public MongoMappingContext(MongoTemplate mongo) { |
|
||||||
this.mongo = mongo; |
|
||||||
this.mappingFactory = new MongoMappingFactory(); |
|
||||||
strategy = new MongoMappingConfigurationStrategy(mongo, mappingFactory); |
|
||||||
} |
|
||||||
|
|
||||||
public MongoMappingContext(MongoTemplate mongo, MongoMappingFactory mappingFactory) { |
|
||||||
this.mongo = mongo; |
|
||||||
this.mappingFactory = mappingFactory; |
|
||||||
strategy = new MongoMappingConfigurationStrategy(mongo, mappingFactory); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected PersistentEntity createPersistentEntity(Class javaClass) { |
|
||||||
MongoPersistentEntity entity = new MongoPersistentEntity(javaClass, this); |
|
||||||
return entity; |
|
||||||
} |
|
||||||
|
|
||||||
public MappingConfigurationStrategy getMappingSyntaxStrategy() { |
|
||||||
return strategy; |
|
||||||
} |
|
||||||
|
|
||||||
public MappingFactory getMappingFactory() { |
|
||||||
return mappingFactory; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,43 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.document.mongodb.mapping; |
|
||||||
|
|
||||||
import org.springframework.data.document.mongodb.MongoTemplate; |
|
||||||
import org.springframework.data.mapping.model.MappingFactory; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
import org.springframework.data.mapping.model.PersistentProperty; |
|
||||||
import org.springframework.data.mapping.reflect.ClassPropertyFetcher; |
|
||||||
|
|
||||||
import java.lang.reflect.Field; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
public class MongoMappingFactory extends MappingFactory<MongoCollection, MongoProperty> { |
|
||||||
|
|
||||||
@Override |
|
||||||
public MongoCollection createMappedForm(PersistentEntity entity) { |
|
||||||
String name = entity.getJavaClass().getSimpleName().toLowerCase(); |
|
||||||
return new MongoCollection(name); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public MongoProperty createMappedForm(PersistentProperty property) { |
|
||||||
String name = property.getName(); |
|
||||||
return new MongoProperty(name, false); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,38 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.document.mongodb.mapping; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
public class MongoProperty { |
|
||||||
|
|
||||||
private String name; |
|
||||||
|
|
||||||
public MongoProperty(String name, boolean indexed) { |
|
||||||
this.name = name; |
|
||||||
} |
|
||||||
|
|
||||||
public String getName() { |
|
||||||
return name; |
|
||||||
} |
|
||||||
|
|
||||||
public void setName(String name) { |
|
||||||
this.name = name; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,14 +0,0 @@ |
|||||||
package org.springframework.data.mapping.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author J. Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
@Target(value = {ElementType.FIELD}) |
|
||||||
public @interface Id { |
|
||||||
} |
|
||||||
@ -1,12 +0,0 @@ |
|||||||
package org.springframework.data.mapping.annotation; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author J. Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
public enum IdentifiedBy { |
|
||||||
DEFAULT, |
|
||||||
ANNOTATION, |
|
||||||
PROPERTY, |
|
||||||
VALUE, |
|
||||||
PARENT |
|
||||||
} |
|
||||||
@ -1,17 +0,0 @@ |
|||||||
package org.springframework.data.mapping.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author J. Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
@Target(value = {ElementType.FIELD}) |
|
||||||
public @interface ManyToMany { |
|
||||||
|
|
||||||
Class<?> targetClass() default Object.class; |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,17 +0,0 @@ |
|||||||
package org.springframework.data.mapping.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author J. Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
@Target(value = {ElementType.FIELD}) |
|
||||||
public @interface OneToMany { |
|
||||||
|
|
||||||
Class<?> targetClass() default Object.class; |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,14 +0,0 @@ |
|||||||
package org.springframework.data.mapping.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author J. Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
@Target(value = {ElementType.FIELD}) |
|
||||||
public @interface OneToOne { |
|
||||||
} |
|
||||||
@ -1,30 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Jon Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
@Target(ElementType.CONSTRUCTOR) |
|
||||||
public @interface PersistenceConstructor { |
|
||||||
} |
|
||||||
@ -1,11 +0,0 @@ |
|||||||
package org.springframework.data.mapping.annotation; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author J. Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
public enum PersistenceStrategy { |
|
||||||
DEFAULT, |
|
||||||
KEY_VALUE, |
|
||||||
DOCUMENT, |
|
||||||
SERIALIZED |
|
||||||
} |
|
||||||
@ -1,37 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author J. Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
@Target(value = {ElementType.TYPE, ElementType.FIELD}) |
|
||||||
public @interface Persistent { |
|
||||||
|
|
||||||
PersistenceStrategy strategy() default PersistenceStrategy.DOCUMENT; |
|
||||||
|
|
||||||
IdentifiedBy identifiedBy() default IdentifiedBy.DEFAULT; |
|
||||||
|
|
||||||
String id() default "id"; |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,14 +0,0 @@ |
|||||||
package org.springframework.data.mapping.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author J. Brisbin <jbrisbin@vmware.com> |
|
||||||
*/ |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
@Target(ElementType.FIELD) |
|
||||||
public @interface Transient { |
|
||||||
} |
|
||||||
@ -1,42 +0,0 @@ |
|||||||
/* 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; |
|
||||||
|
|
||||||
/** |
|
||||||
* Abstract implementation of the ClassMapping interface
|
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class AbstractClassMapping<T> implements ClassMapping{ |
|
||||||
protected PersistentEntity entity; |
|
||||||
protected MappingContext context; |
|
||||||
|
|
||||||
public AbstractClassMapping(PersistentEntity entity, MappingContext context) { |
|
||||||
super(); |
|
||||||
this.entity = entity; |
|
||||||
this.context = context; |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentEntity getEntity() { |
|
||||||
return this.entity; |
|
||||||
} |
|
||||||
|
|
||||||
public abstract T getMappedForm(); |
|
||||||
|
|
||||||
public IdentityMapping getIdentifier() { |
|
||||||
return context.getMappingSyntaxStrategy().getDefaultIdentityMapping(this); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,156 +0,0 @@ |
|||||||
/* 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; |
|
||||||
|
|
||||||
import org.springframework.core.convert.ConversionService; |
|
||||||
import org.springframework.core.convert.converter.Converter; |
|
||||||
import org.springframework.core.convert.converter.ConverterRegistry; |
|
||||||
import org.springframework.core.convert.support.GenericConversionService; |
|
||||||
import org.springframework.validation.Validator; |
|
||||||
|
|
||||||
import java.util.Collection; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.concurrent.ConcurrentHashMap; |
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue; |
|
||||||
|
|
||||||
/** |
|
||||||
* Abstract implementation of the MappingContext interface
|
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class AbstractMappingContext implements MappingContext { |
|
||||||
|
|
||||||
protected Collection<PersistentEntity> persistentEntities = new ConcurrentLinkedQueue<PersistentEntity>(); |
|
||||||
protected Map<String, PersistentEntity> persistentEntitiesByName = new ConcurrentHashMap<String, PersistentEntity>(); |
|
||||||
protected Map<PersistentEntity, Map<String, PersistentEntity>> persistentEntitiesByDiscriminator = new ConcurrentHashMap<PersistentEntity, Map<String, PersistentEntity>>(); |
|
||||||
protected Map<PersistentEntity, Validator> entityValidators = new ConcurrentHashMap<PersistentEntity, Validator>(); |
|
||||||
protected Collection<Listener> eventListeners = new ConcurrentLinkedQueue<Listener>(); |
|
||||||
protected GenericConversionService conversionService = new GenericConversionService(); |
|
||||||
|
|
||||||
public ConversionService getConversionService() { |
|
||||||
return conversionService; |
|
||||||
} |
|
||||||
|
|
||||||
public ConverterRegistry getConverterRegistry() { |
|
||||||
return conversionService; |
|
||||||
} |
|
||||||
|
|
||||||
public void addMappingContextListener(Listener listener) { |
|
||||||
if (listener != null) |
|
||||||
eventListeners.add(listener); |
|
||||||
} |
|
||||||
|
|
||||||
public void addTypeConverter(Converter converter) { |
|
||||||
conversionService.addConverter(converter); |
|
||||||
} |
|
||||||
|
|
||||||
public Validator getEntityValidator(PersistentEntity entity) { |
|
||||||
if (entity != null) { |
|
||||||
return entityValidators.get(entity); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public void addEntityValidator(PersistentEntity entity, Validator validator) { |
|
||||||
if (entity != null && validator != null) { |
|
||||||
entityValidators.put(entity, validator); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentEntity addExternalPersistentEntity(Class javaClass) { |
|
||||||
if (javaClass == null) throw new IllegalArgumentException("PersistentEntity class cannot be null"); |
|
||||||
|
|
||||||
PersistentEntity entity = persistentEntitiesByName.get(javaClass.getName()); |
|
||||||
|
|
||||||
if (entity == null) { |
|
||||||
entity = addPersistentEntityInternal(javaClass, true); |
|
||||||
} |
|
||||||
|
|
||||||
return entity; |
|
||||||
} |
|
||||||
|
|
||||||
public final PersistentEntity addPersistentEntity(Class javaClass) { |
|
||||||
if (javaClass == null) throw new IllegalArgumentException("PersistentEntity class cannot be null"); |
|
||||||
|
|
||||||
PersistentEntity entity = persistentEntitiesByName.get(javaClass.getName()); |
|
||||||
|
|
||||||
if (entity == null) { |
|
||||||
entity = addPersistentEntityInternal(javaClass, false); |
|
||||||
} |
|
||||||
|
|
||||||
return entity; |
|
||||||
} |
|
||||||
|
|
||||||
private PersistentEntity addPersistentEntityInternal(Class javaClass, boolean isExternal) { |
|
||||||
PersistentEntity entity; |
|
||||||
entity = createPersistentEntity(javaClass); |
|
||||||
entity.setExternal(isExternal); |
|
||||||
|
|
||||||
persistentEntities.remove(entity); |
|
||||||
persistentEntities.add(entity); |
|
||||||
persistentEntitiesByName.put(entity.getName(), entity); |
|
||||||
try { |
|
||||||
entity.afterPropertiesSet(); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new RuntimeException(String.format("Error initializing PersistentEntity: %s", entity), e); |
|
||||||
} |
|
||||||
if (!entity.isRoot()) { |
|
||||||
PersistentEntity root = entity.getRootEntity(); |
|
||||||
Map<String, PersistentEntity> children = persistentEntitiesByDiscriminator.get(root); |
|
||||||
if (children == null) { |
|
||||||
children = new ConcurrentHashMap<String, PersistentEntity>(); |
|
||||||
persistentEntitiesByDiscriminator.put(root, children); |
|
||||||
} |
|
||||||
children.put(entity.getDiscriminator(), entity); |
|
||||||
} |
|
||||||
for (Listener eventListener : eventListeners) { |
|
||||||
eventListener.persistentEntityAdded(entity); |
|
||||||
} |
|
||||||
return entity; |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentEntity getChildEntityByDiscriminator(PersistentEntity root, String discriminator) { |
|
||||||
final Map<String, PersistentEntity> children = persistentEntitiesByDiscriminator.get(root); |
|
||||||
if (children != null) { |
|
||||||
return children.get(discriminator); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
protected abstract PersistentEntity createPersistentEntity(Class javaClass); |
|
||||||
|
|
||||||
public Collection<PersistentEntity> getPersistentEntities() { |
|
||||||
return persistentEntities; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isPersistentEntity(Class type) { |
|
||||||
return type != null && getPersistentEntity(type.getName()) != null; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public boolean isPersistentEntity(Object value) { |
|
||||||
return value != null && isPersistentEntity(value.getClass()); |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentEntity getPersistentEntity(String name) { |
|
||||||
final int proxyIndicator = name.indexOf("_$$_"); |
|
||||||
if (proxyIndicator > -1) { |
|
||||||
name = name.substring(0, proxyIndicator); |
|
||||||
} |
|
||||||
|
|
||||||
return persistentEntitiesByName.get(name); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,193 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.BeanUtils; |
|
||||||
import org.springframework.data.mapping.model.types.Association; |
|
||||||
import org.springframework.data.mapping.model.types.OneToMany; |
|
||||||
|
|
||||||
import java.beans.Introspector; |
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
import java.lang.reflect.Modifier; |
|
||||||
import java.util.*; |
|
||||||
|
|
||||||
/** |
|
||||||
* Abstract implementation to be subclasses on a per datastore basis |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class AbstractPersistentEntity<T> implements PersistentEntity<T> { |
|
||||||
|
|
||||||
protected Class<T> javaClass; |
|
||||||
protected List<PersistentProperty> persistentProperties; |
|
||||||
protected List<Association> associations; |
|
||||||
protected Map<String, PersistentProperty> propertiesByName = new HashMap<String, PersistentProperty>(); |
|
||||||
protected MappingContext context; |
|
||||||
protected PersistentProperty identity; |
|
||||||
protected List<String> persistentPropertyNames; |
|
||||||
private String decapitalizedName; |
|
||||||
protected Set owners; |
|
||||||
private PersistentEntity parentEntity = null; |
|
||||||
private boolean external; |
|
||||||
|
|
||||||
public AbstractPersistentEntity(Class<T> javaClass, MappingContext context) { |
|
||||||
if (javaClass == null) throw new IllegalArgumentException("The argument [javaClass] cannot be null"); |
|
||||||
this.javaClass = javaClass; |
|
||||||
this.context = context; |
|
||||||
this.decapitalizedName = Introspector.decapitalize(javaClass.getSimpleName()); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isExternal() { |
|
||||||
return external; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setExternal(boolean external) { |
|
||||||
this.external = external; |
|
||||||
} |
|
||||||
|
|
||||||
public MappingContext getMappingContext() { |
|
||||||
return this.context; |
|
||||||
} |
|
||||||
|
|
||||||
public void afterPropertiesSet() throws Exception { |
|
||||||
this.identity = context.getMappingSyntaxStrategy().getIdentity(javaClass, context); |
|
||||||
this.owners = context.getMappingSyntaxStrategy().getOwningEntities(javaClass, context); |
|
||||||
this.persistentProperties = context.getMappingSyntaxStrategy().getPersistentProperties(javaClass, context); |
|
||||||
persistentPropertyNames = new ArrayList<String>(); |
|
||||||
associations = new ArrayList(); |
|
||||||
for (PersistentProperty persistentProperty : persistentProperties) { |
|
||||||
if (!(persistentProperty instanceof OneToMany)) |
|
||||||
persistentPropertyNames.add(persistentProperty.getName()); |
|
||||||
if (persistentProperty instanceof Association) { |
|
||||||
associations.add((Association) persistentProperty); |
|
||||||
} |
|
||||||
} |
|
||||||
for (PersistentProperty persistentProperty : persistentProperties) { |
|
||||||
propertiesByName.put(persistentProperty.getName(), persistentProperty); |
|
||||||
} |
|
||||||
|
|
||||||
Class<?> superClass = javaClass.getSuperclass(); |
|
||||||
if (superClass != null |
|
||||||
&& !superClass.equals(Object.class) |
|
||||||
&& !Modifier.isAbstract(superClass.getModifiers())) { |
|
||||||
this.parentEntity = context.addPersistentEntity(superClass); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
getMapping().getMappedForm(); // initialize mapping
|
|
||||||
} |
|
||||||
|
|
||||||
public boolean hasProperty(String name, Class type) { |
|
||||||
final PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(getJavaClass(), name); |
|
||||||
return pd != null && pd.getPropertyType().equals(type); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isIdentityName(String propertyName) { |
|
||||||
return getIdentity().getName().equals(propertyName); |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentEntity getParentEntity() { |
|
||||||
return parentEntity; |
|
||||||
} |
|
||||||
|
|
||||||
public String getDiscriminator() { |
|
||||||
return getJavaClass().getSimpleName(); |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentEntity getRootEntity() { |
|
||||||
PersistentEntity root = this; |
|
||||||
PersistentEntity parent = getParentEntity(); |
|
||||||
while (parent != null) { |
|
||||||
root = parent; |
|
||||||
parent = parent.getParentEntity(); |
|
||||||
} |
|
||||||
return root; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isRoot() { |
|
||||||
return getParentEntity() == null; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isOwningEntity(PersistentEntity owner) { |
|
||||||
return owner != null && owners.contains(owner.getJavaClass()); |
|
||||||
} |
|
||||||
|
|
||||||
public String getDecapitalizedName() { |
|
||||||
return this.decapitalizedName; |
|
||||||
} |
|
||||||
|
|
||||||
public List<String> getPersistentPropertyNames() { |
|
||||||
return this.persistentPropertyNames; |
|
||||||
} |
|
||||||
|
|
||||||
public T newInstance() { |
|
||||||
try { |
|
||||||
return getJavaClass().newInstance(); |
|
||||||
} catch (InstantiationException e) { |
|
||||||
throw new MappingInstantiationException("Unable to create entity of type [" + getJavaClass() + "]: " + e.getMessage(), e); |
|
||||||
} catch (IllegalAccessException e) { |
|
||||||
throw new MappingInstantiationException("Unable to create entity of type [" + getJavaClass() + "]: " + e.getMessage(), e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public String getName() { |
|
||||||
return javaClass.getName(); |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentProperty getIdentity() { |
|
||||||
return this.identity; |
|
||||||
} |
|
||||||
|
|
||||||
public Class<T> getJavaClass() { |
|
||||||
return this.javaClass; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isInstance(Object obj) { |
|
||||||
return getJavaClass().isInstance(obj); |
|
||||||
} |
|
||||||
|
|
||||||
public List<PersistentProperty> getPersistentProperties() { |
|
||||||
return persistentProperties; |
|
||||||
} |
|
||||||
|
|
||||||
public List<Association> getAssociations() { |
|
||||||
return associations; |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentProperty getPropertyByName(String name) { |
|
||||||
return propertiesByName.get(name); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int hashCode() { |
|
||||||
return javaClass.hashCode(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean equals(Object o) { |
|
||||||
if (o == null || !(o instanceof PersistentEntity)) return false; |
|
||||||
if (this == o) return true; |
|
||||||
|
|
||||||
PersistentEntity other = (PersistentEntity) o; |
|
||||||
return javaClass.equals(other.getJavaClass()); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
return "PersistentEntity[" + javaClass.getName() + "]"; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,77 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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; |
|
||||||
|
|
||||||
/** |
|
||||||
* Abstract implementation of the PersistentProperty interface that |
|
||||||
* uses the PropertyDescriptor instance to establish name and type |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class AbstractPersistentProperty implements PersistentProperty { |
|
||||||
protected PersistentEntity owner; |
|
||||||
protected MappingContext context; |
|
||||||
protected String name; |
|
||||||
protected Class type; |
|
||||||
private boolean nullable = false; |
|
||||||
|
|
||||||
public AbstractPersistentProperty(PersistentEntity owner, MappingContext context, PropertyDescriptor descriptor) { |
|
||||||
this.owner = owner; |
|
||||||
this.context = context; |
|
||||||
this.name = descriptor.getName(); |
|
||||||
this.type = descriptor.getPropertyType(); |
|
||||||
} |
|
||||||
|
|
||||||
public AbstractPersistentProperty(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
this.owner = owner; |
|
||||||
this.context = context; |
|
||||||
this.name = name; |
|
||||||
this.type = type; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public String getName() { |
|
||||||
return name; |
|
||||||
} |
|
||||||
|
|
||||||
public String getCapitilizedName() { |
|
||||||
String name = getName(); |
|
||||||
return name.substring(0, 1).toUpperCase() + name.substring(1); |
|
||||||
} |
|
||||||
|
|
||||||
public Class getType() { |
|
||||||
return type; |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentEntity getOwner() { |
|
||||||
return owner; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
return getName() + ":" + getType().getName(); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isNullable() { |
|
||||||
return nullable; |
|
||||||
} |
|
||||||
|
|
||||||
public void setNullable(boolean nullable) { |
|
||||||
this.nullable = nullable; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,31 +0,0 @@ |
|||||||
package org.springframework.data.mapping.model; |
|
||||||
|
|
||||||
/** |
|
||||||
* A class mapping is a mapping between a class and some external |
|
||||||
* form such as a table, column family, or document (depending on the underlying data store) |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public interface ClassMapping<T> { |
|
||||||
/** |
|
||||||
* Obtains the PersistentEntity for this class mapping |
|
||||||
* |
|
||||||
* @return The PersistentEntity |
|
||||||
*/ |
|
||||||
PersistentEntity getEntity(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the mapped form of the class such as a Table, a Key Space, Document etc. |
|
||||||
* |
|
||||||
* @return The mapped representation |
|
||||||
*/ |
|
||||||
T getMappedForm(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns details of the identifier used for this class
|
|
||||||
* |
|
||||||
* @return The Identity |
|
||||||
*/ |
|
||||||
IdentityMapping getIdentifier(); |
|
||||||
} |
|
||||||
@ -1,18 +0,0 @@ |
|||||||
package org.springframework.data.mapping.model; |
|
||||||
|
|
||||||
/** |
|
||||||
* Exception thrown when something goes wrong configuring a datastore |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public class DatastoreConfigurationException extends RuntimeException{ |
|
||||||
|
|
||||||
public DatastoreConfigurationException(String message) { |
|
||||||
super(message); |
|
||||||
} |
|
||||||
|
|
||||||
public DatastoreConfigurationException(String message, Throwable cause) { |
|
||||||
super(message, cause); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,31 +0,0 @@ |
|||||||
/* 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; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public interface IdentityMapping extends PropertyMapping{ |
|
||||||
|
|
||||||
/** |
|
||||||
* The identifier property name(s) as an array. Usually there is just one identifier |
|
||||||
* name, however in the case of a composite or natural identifier there |
|
||||||
* may be serveral names |
|
||||||
* |
|
||||||
* @return A String[] of identifier names that make up the key |
|
||||||
*/ |
|
||||||
String[] getIdentifierName(); |
|
||||||
} |
|
||||||
@ -1,32 +0,0 @@ |
|||||||
/* 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 { |
|
||||||
|
|
||||||
public IllegalMappingException(String s, Throwable throwable) { |
|
||||||
super(s, throwable); |
|
||||||
} |
|
||||||
|
|
||||||
public IllegalMappingException(String s) { |
|
||||||
super(s); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,72 +0,0 @@ |
|||||||
package org.springframework.data.mapping.model; |
|
||||||
|
|
||||||
import org.springframework.data.document.mongodb.mapping.MappingException; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p>This interface defines a strategy for reading how |
|
||||||
* persistent properties are defined in a persistent entity.</p> |
|
||||||
* <p/> |
|
||||||
* <p>Subclasses can implement this interface in order to provide |
|
||||||
* a different mechanism for mapping entities such as annotations or XML.</p> |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public interface MappingConfigurationStrategy { |
|
||||||
|
|
||||||
/** |
|
||||||
* Tests whether the given class is a persistent entity |
|
||||||
* |
|
||||||
* @param javaClass The java class
|
|
||||||
* @return true if it is a persistent entity |
|
||||||
*/ |
|
||||||
<T> boolean isPersistentEntity(Class<T> javaClass); |
|
||||||
|
|
||||||
/** |
|
||||||
* @see #getPersistentProperties(Class, MappingContext, ClassMapping) |
|
||||||
*/ |
|
||||||
<T> List<PersistentProperty> getPersistentProperties(Class<T> javaClass, MappingContext context); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains a List of PersistentProperty instances for the given Mapped class
|
|
||||||
* |
|
||||||
* @param javaClass The Java class
|
|
||||||
* @param context The MappingContext instance |
|
||||||
* @param mapping The mapping for this class
|
|
||||||
* @return The PersistentProperty instances |
|
||||||
*/ |
|
||||||
<T> List<PersistentProperty> getPersistentProperties(Class<T> javaClass, MappingContext context, ClassMapping mapping); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains the identity of a persistent entity |
|
||||||
* |
|
||||||
* @param javaClass The Java class
|
|
||||||
* @param context The MappingContext |
|
||||||
* @return A PersistentProperty instance |
|
||||||
*/ |
|
||||||
<T> PersistentProperty getIdentity(Class<T> javaClass, MappingContext context); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains the default manner in which identifiers are mapped. In GORM |
|
||||||
* this is just using a property called 'id', but in other frameworks this |
|
||||||
* may differ. For example JPA expects an annotated @Id property |
|
||||||
* |
|
||||||
* @param classMapping The ClassMapping instance |
|
||||||
* @return The default identifier mapping |
|
||||||
*/ |
|
||||||
IdentityMapping getDefaultIdentityMapping(ClassMapping classMapping) throws MappingException; |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns a set of entities that "own" the given entity. Ownership |
|
||||||
* dictates default cascade strategies. So if entity A owns entity B |
|
||||||
* then saves, updates and deletes will cascade from A to B |
|
||||||
* |
|
||||||
* @param javaClass The Java class
|
|
||||||
* @param context The MappingContext |
|
||||||
* @return A Set of owning classes |
|
||||||
*/ |
|
||||||
<T> Set getOwningEntities(Class<T> javaClass, MappingContext context); |
|
||||||
} |
|
||||||
@ -1,169 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.core.convert.converter.Converter; |
|
||||||
import org.springframework.core.convert.converter.ConverterRegistry; |
|
||||||
import org.springframework.validation.Validator; |
|
||||||
|
|
||||||
import java.util.Collection; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p>This interface defines the overall context including all known |
|
||||||
* PersistentEntity instances and methods to obtain instances on demand</p> |
|
||||||
* <p/> |
|
||||||
* <p>This interface is used internally to establish associations |
|
||||||
* between entities and also at runtime to obtain entities by name</p> |
|
||||||
* <p/> |
|
||||||
* <p>The generic type parameters T & R are used to specify the |
|
||||||
* mapped form of a class (example Table) and property (example Column) respectively.</p> |
|
||||||
* <p/> |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public interface MappingContext { |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains a list of PersistentEntity instances |
|
||||||
* |
|
||||||
* @return A list of PersistentEntity instances |
|
||||||
*/ |
|
||||||
Collection<PersistentEntity> getPersistentEntities(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains a PersistentEntity by name |
|
||||||
* |
|
||||||
* @param name The name of the entity |
|
||||||
* @return The entity or null |
|
||||||
*/ |
|
||||||
PersistentEntity getPersistentEntity(String name); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains a child of the given root entity using the given discriminator |
|
||||||
* |
|
||||||
* @param root The root entity |
|
||||||
* @param discriminator The discriminator |
|
||||||
* @return The child entity or null if non exists |
|
||||||
*/ |
|
||||||
PersistentEntity getChildEntityByDiscriminator(PersistentEntity root, String discriminator); |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds a PersistentEntity instance |
|
||||||
* |
|
||||||
* @param javaClass The Java class representing the entity |
|
||||||
* @return The PersistentEntity instance |
|
||||||
*/ |
|
||||||
PersistentEntity addPersistentEntity(Class javaClass); |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds a persistent entity that is not mapped by this MappingContext instance. |
|
||||||
* Used for cross store persistence |
|
||||||
* |
|
||||||
* @param javaClass The Java class
|
|
||||||
* @return The persistent entity |
|
||||||
*/ |
|
||||||
PersistentEntity addExternalPersistentEntity(Class javaClass); |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds a validator to be used by the entity for validation |
|
||||||
* |
|
||||||
* @param entity The PersistentEntity |
|
||||||
* @param validator The validator |
|
||||||
*/ |
|
||||||
void addEntityValidator(PersistentEntity entity, Validator validator); |
|
||||||
|
|
||||||
/** |
|
||||||
* Add a converter used to convert property values to and from the datastore |
|
||||||
* |
|
||||||
* @param converter The converter to add |
|
||||||
*/ |
|
||||||
void addTypeConverter(Converter converter); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains the ConversionService instance to use for type conversion |
|
||||||
* |
|
||||||
* @return The conversion service instance |
|
||||||
*/ |
|
||||||
ConversionService getConversionService(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains the converter registry |
|
||||||
* |
|
||||||
* @return The converter registry used for type conversion |
|
||||||
*/ |
|
||||||
ConverterRegistry getConverterRegistry(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains a validator for the given entity |
|
||||||
* |
|
||||||
* @param entity The entity |
|
||||||
* @return A validator or null if none exists for the given entity |
|
||||||
*/ |
|
||||||
Validator getEntityValidator(PersistentEntity entity); |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the syntax reader used to interpret the entity |
|
||||||
* mapping syntax |
|
||||||
* |
|
||||||
* @return The SyntaxReader |
|
||||||
*/ |
|
||||||
MappingConfigurationStrategy getMappingSyntaxStrategy(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains the MappingFactory instance |
|
||||||
* |
|
||||||
* @return The mapping factory instance |
|
||||||
*/ |
|
||||||
MappingFactory getMappingFactory(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns whether the specified class is a persistent entity |
|
||||||
* |
|
||||||
* @param type The type to check |
|
||||||
* @return True if it is |
|
||||||
*/ |
|
||||||
boolean isPersistentEntity(Class<?> type); |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns whether the specified value is a persistent entity |
|
||||||
* |
|
||||||
* @param value The value to check |
|
||||||
* @return True if it is |
|
||||||
*/ |
|
||||||
boolean isPersistentEntity(Object value); |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds a new mapping context listener instance |
|
||||||
* |
|
||||||
* @param listener The listener |
|
||||||
*/ |
|
||||||
void addMappingContextListener(Listener listener); |
|
||||||
|
|
||||||
/** |
|
||||||
* Implementors can register for events when the mapping context changes |
|
||||||
*/ |
|
||||||
public static interface Listener { |
|
||||||
|
|
||||||
/** |
|
||||||
* Fired when a new entity is added |
|
||||||
* |
|
||||||
* @param entity The entity |
|
||||||
*/ |
|
||||||
void persistentEntityAdded(PersistentEntity entity); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,278 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.model.types.*; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
import java.io.Serializable; |
|
||||||
import java.math.BigDecimal; |
|
||||||
import java.math.BigInteger; |
|
||||||
import java.net.URI; |
|
||||||
import java.net.URL; |
|
||||||
import java.sql.Blob; |
|
||||||
import java.sql.Clob; |
|
||||||
import java.sql.Time; |
|
||||||
import java.sql.Timestamp; |
|
||||||
import java.util.*; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p>An abstract factory for creating persistent property instances.</p> |
|
||||||
* <p/> |
|
||||||
* <p>Subclasses should implement the createMappedForm method in order to |
|
||||||
* provide a mechanisms for representing the property in a form appropriate |
|
||||||
* for mapping to the underlying datastore. Example:</p> |
|
||||||
* <p/> |
|
||||||
* <pre> |
|
||||||
* <code> |
|
||||||
* class RelationalPropertyFactory<Column> extends PropertyFactory { |
|
||||||
* public Column createMappedForm(PersistentProperty mpp) { |
|
||||||
* return new Column(mpp) |
|
||||||
* } |
|
||||||
* } |
|
||||||
* </code> |
|
||||||
* </pre> |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class MappingFactory<R, T> { |
|
||||||
public static final Set<String> SIMPLE_TYPES; |
|
||||||
|
|
||||||
static { |
|
||||||
Set<String> basics = new HashSet<String>(); |
|
||||||
basics.add(boolean.class.getName()); |
|
||||||
basics.add(long.class.getName()); |
|
||||||
basics.add(short.class.getName()); |
|
||||||
basics.add(int.class.getName()); |
|
||||||
basics.add(byte.class.getName()); |
|
||||||
basics.add(float.class.getName()); |
|
||||||
basics.add(double.class.getName()); |
|
||||||
basics.add(char.class.getName()); |
|
||||||
basics.add(Boolean.class.getName()); |
|
||||||
basics.add(Long.class.getName()); |
|
||||||
basics.add(Short.class.getName()); |
|
||||||
basics.add(Integer.class.getName()); |
|
||||||
basics.add(Byte.class.getName()); |
|
||||||
basics.add(Float.class.getName()); |
|
||||||
basics.add(Double.class.getName()); |
|
||||||
basics.add(Character.class.getName()); |
|
||||||
basics.add(String.class.getName()); |
|
||||||
basics.add(java.util.Date.class.getName()); |
|
||||||
basics.add(Time.class.getName()); |
|
||||||
basics.add(Timestamp.class.getName()); |
|
||||||
basics.add(java.sql.Date.class.getName()); |
|
||||||
basics.add(BigDecimal.class.getName()); |
|
||||||
basics.add(BigInteger.class.getName()); |
|
||||||
basics.add(Locale.class.getName()); |
|
||||||
basics.add(Calendar.class.getName()); |
|
||||||
basics.add(GregorianCalendar.class.getName()); |
|
||||||
basics.add(java.util.Currency.class.getName()); |
|
||||||
basics.add(TimeZone.class.getName()); |
|
||||||
basics.add(Object.class.getName()); |
|
||||||
basics.add(Class.class.getName()); |
|
||||||
basics.add(byte[].class.getName()); |
|
||||||
basics.add(Byte[].class.getName()); |
|
||||||
basics.add(char[].class.getName()); |
|
||||||
basics.add(Character[].class.getName()); |
|
||||||
basics.add(Blob.class.getName()); |
|
||||||
basics.add(Clob.class.getName()); |
|
||||||
basics.add(Serializable.class.getName()); |
|
||||||
basics.add(URI.class.getName()); |
|
||||||
basics.add(URL.class.getName()); |
|
||||||
|
|
||||||
SIMPLE_TYPES = Collections.unmodifiableSet(basics); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public MappingFactory() { |
|
||||||
super(); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isSimpleType(Class propType) { |
|
||||||
if (propType == null) return false; |
|
||||||
if (propType.isArray()) { |
|
||||||
return isSimpleType(propType.getComponentType()); |
|
||||||
} |
|
||||||
final String typeName = propType.getName(); |
|
||||||
return isSimpleType(typeName); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isSimpleType(final String typeName) { |
|
||||||
return SIMPLE_TYPES.contains(typeName); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates the mapped form of a persistent entity |
|
||||||
* |
|
||||||
* @param entity The entity |
|
||||||
* @return The mapped form |
|
||||||
*/ |
|
||||||
public abstract R createMappedForm(PersistentEntity entity); |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates the mapped form of a PersistentProperty instance |
|
||||||
* |
|
||||||
* @param mpp The PersistentProperty instance |
|
||||||
* @return The mapped form |
|
||||||
*/ |
|
||||||
public abstract T createMappedForm(PersistentProperty mpp); |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates an identifier property |
|
||||||
* |
|
||||||
* @param owner The owner |
|
||||||
* @param context The context |
|
||||||
* @param pd The PropertyDescriptor |
|
||||||
* @return An Identity instance |
|
||||||
*/ |
|
||||||
public Identity<T> createIdentity(PersistentEntity owner, MappingContext context, PropertyDescriptor pd) { |
|
||||||
return new Identity<T>(owner, context, pd) { |
|
||||||
public PropertyMapping<T> getMapping() { |
|
||||||
return createPropertyMapping(this, owner); |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a simple property type used for mapping basic types such as String, long, integer etc. |
|
||||||
* |
|
||||||
* @param owner The owner |
|
||||||
* @param context The MappingContext |
|
||||||
* @param pd The PropertyDescriptor |
|
||||||
* @return A Simple property type |
|
||||||
*/ |
|
||||||
public Simple<T> createSimple(PersistentEntity owner, MappingContext context, PropertyDescriptor pd) { |
|
||||||
return new Simple<T>(owner, context, pd) { |
|
||||||
public PropertyMapping<T> getMapping() { |
|
||||||
return createPropertyMapping(this, owner); |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
protected PropertyMapping<T> createPropertyMapping(final PersistentProperty<T> property, final PersistentEntity owner) { |
|
||||||
return new PropertyMapping<T>() { |
|
||||||
public ClassMapping getClassMapping() { |
|
||||||
return owner.getMapping(); |
|
||||||
} |
|
||||||
|
|
||||||
public T getMappedForm() { |
|
||||||
return createMappedForm(property); |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a one-to-one association type used for mapping a one-to-one association between entities |
|
||||||
* |
|
||||||
* @param entity The entity |
|
||||||
* @param context The context |
|
||||||
* @param property The property |
|
||||||
* @return The ToOne instance |
|
||||||
*/ |
|
||||||
public ToOne createOneToOne(PersistentEntity entity, MappingContext context, PropertyDescriptor property) { |
|
||||||
return new OneToOne<T>(entity, context, property) { |
|
||||||
public PropertyMapping getMapping() { |
|
||||||
return createPropertyMapping(this, owner); |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a many-to-one association type used for a mapping a many-to-one association between entities |
|
||||||
* |
|
||||||
* @param entity The entity |
|
||||||
* @param context The context |
|
||||||
* @param property The property |
|
||||||
* @return The ToOne instance |
|
||||||
*/ |
|
||||||
public ToOne createManyToOne(PersistentEntity entity, MappingContext context, PropertyDescriptor property) { |
|
||||||
return new ManyToOne<T>(entity, context, property) { |
|
||||||
public PropertyMapping getMapping() { |
|
||||||
return createPropertyMapping(this, owner); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a {@link OneToMany} type used to model a one-to-many association between entities |
|
||||||
* |
|
||||||
* @param entity The entity |
|
||||||
* @param context The context |
|
||||||
* @param property The property |
|
||||||
* @return The {@link OneToMany} instance |
|
||||||
*/ |
|
||||||
public OneToMany createOneToMany(PersistentEntity entity, MappingContext context, PropertyDescriptor property) { |
|
||||||
return new OneToMany<T>(entity, context, property) { |
|
||||||
public PropertyMapping getMapping() { |
|
||||||
return createPropertyMapping(this, owner); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a {@link ManyToMany} type used to model a many-to-many association between entities |
|
||||||
* |
|
||||||
* @param entity The entity |
|
||||||
* @param context The context |
|
||||||
* @param property The property |
|
||||||
* @return The {@link ManyToMany} instance |
|
||||||
*/ |
|
||||||
public ManyToMany createManyToMany(PersistentEntity entity, MappingContext context, PropertyDescriptor property) { |
|
||||||
return new ManyToMany<T>(entity, context, property) { |
|
||||||
public PropertyMapping getMapping() { |
|
||||||
return createPropertyMapping(this, owner); |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates an {@link Embedded} type used to model an embedded association (composition) |
|
||||||
* |
|
||||||
* @param entity The entity |
|
||||||
* @param context The context |
|
||||||
* @param property The property |
|
||||||
* @return The {@link Embedded} instance |
|
||||||
*/ |
|
||||||
public Embedded createEmbedded(PersistentEntity entity, |
|
||||||
MappingContext context, PropertyDescriptor property) { |
|
||||||
return new Embedded<T>(entity, context, property) { |
|
||||||
public PropertyMapping getMapping() { |
|
||||||
return createPropertyMapping(this, owner); |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a {@link Basic} collection type |
|
||||||
* |
|
||||||
* @param entity The entity |
|
||||||
* @param context The context |
|
||||||
* @param property The property |
|
||||||
* @return The Basic collection type |
|
||||||
*/ |
|
||||||
public Basic createBasicCollection(PersistentEntity entity, |
|
||||||
MappingContext context, PropertyDescriptor property) { |
|
||||||
return new Basic(entity, context, property) { |
|
||||||
public PropertyMapping getMapping() { |
|
||||||
return createPropertyMapping(this, owner); |
|
||||||
} |
|
||||||
|
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@ -1,30 +0,0 @@ |
|||||||
/* |
|
||||||
* 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; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by IntelliJ IDEA. |
|
||||||
* User: jbrisbin |
|
||||||
* Date: 2/25/11 |
|
||||||
* Time: 9:07 AM |
|
||||||
* To change this template use File | Settings | File Templates. |
|
||||||
*/ |
|
||||||
public class MappingInstantiationException extends RuntimeException { |
|
||||||
public MappingInstantiationException(String s, Throwable throwable) { |
|
||||||
super(s, throwable); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,167 +0,0 @@ |
|||||||
package org.springframework.data.mapping.model; |
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean; |
|
||||||
import org.springframework.data.mapping.model.types.Association; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Represents a persistent entity |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public interface PersistentEntity<T> extends InitializingBean { |
|
||||||
|
|
||||||
/** |
|
||||||
* The entity name including any package prefix |
|
||||||
* |
|
||||||
* @return The entity name |
|
||||||
*/ |
|
||||||
String getName(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Whether this PersistentEntity is mapped using a different store. Used for cross store persistence |
|
||||||
* |
|
||||||
* @return True if this entity is externally mapped |
|
||||||
*/ |
|
||||||
boolean isExternal(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Whether this PersistentEntity is mapped using a different store. Used for cross store persistence |
|
||||||
* |
|
||||||
* @return True if this entity is externally mapped |
|
||||||
*/ |
|
||||||
void setExternal(boolean external); |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the identity of the instance |
|
||||||
* |
|
||||||
* @return The identity |
|
||||||
*/ |
|
||||||
PersistentProperty getIdentity(); |
|
||||||
|
|
||||||
/** |
|
||||||
* A list of properties to be persisted |
|
||||||
* |
|
||||||
* @return A list of PersistentProperty instances |
|
||||||
*/ |
|
||||||
List<PersistentProperty> getPersistentProperties(); |
|
||||||
|
|
||||||
/** |
|
||||||
* A list of the associations for this entity. This is typically |
|
||||||
* a subset of the list returned by {@link #getPersistentProperties()} |
|
||||||
* |
|
||||||
* @return A list of associations |
|
||||||
*/ |
|
||||||
List<Association> getAssociations(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains a PersistentProperty instance by name |
|
||||||
* |
|
||||||
* @param name The name of the property |
|
||||||
* @return The PersistentProperty or null if it doesn't exist |
|
||||||
*/ |
|
||||||
PersistentProperty getPropertyByName(String name); |
|
||||||
|
|
||||||
/** |
|
||||||
* @return The underlying Java class for this entity |
|
||||||
*/ |
|
||||||
Class<T> getJavaClass(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Tests whether the given instance is an instance of this persistent entity |
|
||||||
* |
|
||||||
* @param obj The object |
|
||||||
* @return True if it is |
|
||||||
*/ |
|
||||||
boolean isInstance(Object obj); |
|
||||||
|
|
||||||
/** |
|
||||||
* Defines the mapping between this persistent entity |
|
||||||
* and an external form |
|
||||||
* |
|
||||||
* @return The ClassMapping instance |
|
||||||
*/ |
|
||||||
<M> ClassMapping<M> getMapping(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Constructs a new instance |
|
||||||
* |
|
||||||
* @return The new instnace |
|
||||||
*/ |
|
||||||
T newInstance(); |
|
||||||
|
|
||||||
/** |
|
||||||
* A list of property names that a persistent |
|
||||||
* |
|
||||||
* @return A List of strings |
|
||||||
*/ |
|
||||||
List<String> getPersistentPropertyNames(); |
|
||||||
|
|
||||||
/** |
|
||||||
* @return Returns the name of the class decapitalized form |
|
||||||
*/ |
|
||||||
String getDecapitalizedName(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns whether the specified entity asserts ownership over this |
|
||||||
* entity |
|
||||||
* |
|
||||||
* @param owner The owning entity |
|
||||||
* @return True if it does own this entity |
|
||||||
*/ |
|
||||||
boolean isOwningEntity(PersistentEntity<?> owner); |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the parent entity of this entity |
|
||||||
* |
|
||||||
* @return The ParentEntity instance |
|
||||||
*/ |
|
||||||
PersistentEntity<?> getParentEntity(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains the root entity of an inheritance hierarchy |
|
||||||
* |
|
||||||
* @return The root entity |
|
||||||
*/ |
|
||||||
PersistentEntity<?> getRootEntity(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Whether this entity is a root entity |
|
||||||
* |
|
||||||
* @return True if it is a root entity |
|
||||||
*/ |
|
||||||
boolean isRoot(); |
|
||||||
|
|
||||||
/** |
|
||||||
* The discriminator used when persisting subclasses of an inheritance hierarchy |
|
||||||
* |
|
||||||
* @return The discriminator |
|
||||||
*/ |
|
||||||
String getDiscriminator(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains the MappingContext where this PersistentEntity is defined |
|
||||||
* |
|
||||||
* @return The MappingContext instance |
|
||||||
*/ |
|
||||||
MappingContext getMappingContext(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Checks whether an entity has a bean property of the given name and type |
|
||||||
* |
|
||||||
* @param name The name |
|
||||||
* @param type The type |
|
||||||
* @return True if it does |
|
||||||
*/ |
|
||||||
boolean hasProperty(String name, Class<?> type); |
|
||||||
|
|
||||||
/** |
|
||||||
* True if the given property is the identifier |
|
||||||
* |
|
||||||
* @param propertyName the property name |
|
||||||
* @return True if it is the identifier |
|
||||||
*/ |
|
||||||
boolean isIdentityName(String propertyName); |
|
||||||
} |
|
||||||
@ -1,51 +0,0 @@ |
|||||||
package org.springframework.data.mapping.model; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public interface PersistentProperty<T> { |
|
||||||
|
|
||||||
/** |
|
||||||
* The name of the property |
|
||||||
* |
|
||||||
* @return The property name |
|
||||||
*/ |
|
||||||
String getName(); |
|
||||||
|
|
||||||
/** |
|
||||||
* The name with the first letter in upper case as per Java bean conventions |
|
||||||
* |
|
||||||
* @return The capitilized name |
|
||||||
*/ |
|
||||||
String getCapitilizedName(); |
|
||||||
|
|
||||||
/** |
|
||||||
* The type of the property |
|
||||||
* |
|
||||||
* @return The property type |
|
||||||
*/ |
|
||||||
Class<T> getType(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Specifies the mapping between this property and an external form |
|
||||||
* such as a column, key/value pair etc. |
|
||||||
* |
|
||||||
* @return The PropertyMapping instance |
|
||||||
*/ |
|
||||||
PropertyMapping<T> getMapping(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Obtains the owner of this persistent property |
|
||||||
* |
|
||||||
* @return The owner |
|
||||||
*/ |
|
||||||
PersistentEntity<?> getOwner(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Whether the property can be set to null |
|
||||||
* |
|
||||||
* @return True if it can |
|
||||||
*/ |
|
||||||
boolean isNullable(); |
|
||||||
} |
|
||||||
@ -1,25 +0,0 @@ |
|||||||
package org.springframework.data.mapping.model; |
|
||||||
|
|
||||||
/** |
|
||||||
* A marker interface for a property mapping which specifies |
|
||||||
* what or where a particular property is mapped to |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public interface PropertyMapping<T> { |
|
||||||
|
|
||||||
/** |
|
||||||
* Retrieves the ClassMapping instance of the owning class
|
|
||||||
* |
|
||||||
* @return The ClassMapping instance |
|
||||||
*/ |
|
||||||
ClassMapping getClassMapping(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the mapped form of the property such as a Column, a Key/Value pair, attribute etc. |
|
||||||
* @return The mapped representation |
|
||||||
*/ |
|
||||||
T getMappedForm(); |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,146 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.types; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.*; |
|
||||||
|
|
||||||
import javax.persistence.CascadeType; |
|
||||||
import javax.persistence.FetchType; |
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Models an association between one class and another |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class Association<T> extends AbstractPersistentProperty { |
|
||||||
|
|
||||||
public static final List<CascadeType> DEFAULT_OWNER_CASCADE = new ArrayList<CascadeType>() {{ |
|
||||||
add(CascadeType.ALL); |
|
||||||
}}; |
|
||||||
|
|
||||||
public static final List<CascadeType> DEFAULT_CHILD_CASCADE = new ArrayList<CascadeType>() {{ |
|
||||||
add(CascadeType.PERSIST); |
|
||||||
}}; |
|
||||||
|
|
||||||
private PersistentEntity associatedEntity; |
|
||||||
private String referencedPropertyName; |
|
||||||
private boolean owningSide; |
|
||||||
private List<CascadeType> cascadeOperations = new ArrayList<CascadeType>(); |
|
||||||
private FetchType fetchStrategy = FetchType.EAGER; |
|
||||||
|
|
||||||
public Association(PersistentEntity owner, MappingContext context, PropertyDescriptor descriptor) { |
|
||||||
super(owner, context, descriptor); |
|
||||||
} |
|
||||||
|
|
||||||
public Association(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
super(owner, context, name, type); |
|
||||||
} |
|
||||||
|
|
||||||
public FetchType getFetchStrategy() { |
|
||||||
return fetchStrategy; |
|
||||||
} |
|
||||||
|
|
||||||
public void setFetchStrategy(FetchType fetchStrategy) { |
|
||||||
this.fetchStrategy = fetchStrategy; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isBidirectional() { |
|
||||||
return getInverseSide() != null; |
|
||||||
} |
|
||||||
|
|
||||||
public Association getInverseSide() { |
|
||||||
final PersistentProperty associatedProperty = associatedEntity.getPropertyByName(referencedPropertyName); |
|
||||||
if(associatedProperty == null) return null; |
|
||||||
if(associatedProperty instanceof Association) { |
|
||||||
return (Association) associatedProperty; |
|
||||||
} |
|
||||||
else { |
|
||||||
throw new IllegalMappingException("The inverse side ["+associatedEntity.getName()+"." + associatedProperty.getName() +"] of the association ["+getOwner().getName()+"." + this.getName() +"] is not valid. Associations can only map to other entities and collection types."); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns true if the this association cascade for the given cascade operation |
|
||||||
* |
|
||||||
* @param cascadeOperation The cascadeOperation |
|
||||||
* @return True if it does |
|
||||||
*/ |
|
||||||
public boolean doesCascade(CascadeType cascadeOperation) { |
|
||||||
List<CascadeType> cascades = getCascadeOperations(); |
|
||||||
return cascadeOperation != null && (cascades.contains(CascadeType.ALL) || cascades.contains(cascadeOperation)); |
|
||||||
} |
|
||||||
|
|
||||||
protected List<CascadeType> getCascadeOperations() { |
|
||||||
List<CascadeType> cascades; |
|
||||||
if(cascadeOperations.isEmpty()) { |
|
||||||
if(isOwningSide()) cascades = DEFAULT_OWNER_CASCADE; |
|
||||||
else { |
|
||||||
cascades = DEFAULT_CHILD_CASCADE; |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
cascades = this.cascadeOperations; |
|
||||||
} |
|
||||||
return cascades; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns whether this side owns the relationship. This controls |
|
||||||
* the default cascading behavior if none is specified |
|
||||||
* |
|
||||||
* @return True if this property is the owning side |
|
||||||
*/ |
|
||||||
public boolean isOwningSide() { |
|
||||||
return owningSide; |
|
||||||
} |
|
||||||
|
|
||||||
public void setOwningSide(boolean owningSide) { |
|
||||||
this.owningSide = owningSide; |
|
||||||
} |
|
||||||
|
|
||||||
public void setAssociatedEntity(PersistentEntity associatedEntity) { |
|
||||||
this.associatedEntity = associatedEntity; |
|
||||||
} |
|
||||||
|
|
||||||
public PersistentEntity getAssociatedEntity() { |
|
||||||
return associatedEntity; |
|
||||||
} |
|
||||||
|
|
||||||
public void setReferencedPropertyName(String referencedPropertyName) { |
|
||||||
this.referencedPropertyName = referencedPropertyName; |
|
||||||
} |
|
||||||
|
|
||||||
public String getReferencedPropertyName() { |
|
||||||
return referencedPropertyName; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
return getOwner().getName() + "->" + getName(); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isList() { |
|
||||||
return List.class.isAssignableFrom(getType()); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isCircular() { |
|
||||||
return isBidirectional() && getAssociatedEntity().equals(getOwner()); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,65 +0,0 @@ |
|||||||
/* Copyright (C) 2011 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.types; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.MappingContext; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
import org.springframework.data.mapping.model.PropertyMapping; |
|
||||||
|
|
||||||
/** |
|
||||||
* Models a basic collection type such as a list of Strings |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
* |
|
||||||
*/ |
|
||||||
public abstract class Basic extends Association { |
|
||||||
|
|
||||||
public Basic(PersistentEntity owner, MappingContext context, |
|
||||||
PropertyDescriptor descriptor) { |
|
||||||
super(owner, context, descriptor); |
|
||||||
} |
|
||||||
|
|
||||||
public Basic(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
super(owner, context, name, type); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Association getInverseSide() { |
|
||||||
return null; // basic collection types have no inverse side
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isOwningSide() { |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setOwningSide(boolean owningSide) { |
|
||||||
// noop
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public PersistentEntity getAssociatedEntity() { |
|
||||||
return null; // basic collection types have no associated entity
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
@ -1,133 +0,0 @@ |
|||||||
/* 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.types; |
|
||||||
|
|
||||||
import org.springframework.core.convert.converter.Converter; |
|
||||||
import org.springframework.core.convert.converter.ConverterRegistry; |
|
||||||
|
|
||||||
import java.util.Calendar; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.GregorianCalendar; |
|
||||||
|
|
||||||
/** |
|
||||||
* A registrar that registers basic type converters |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public class BasicTypeConverterRegistrar { |
|
||||||
|
|
||||||
public void register(ConverterRegistry registry) { |
|
||||||
registry.addConverter(new Converter<Date, String>() { |
|
||||||
public String convert(Date date) { |
|
||||||
return String.valueOf(date.getTime()); |
|
||||||
} |
|
||||||
}); |
|
||||||
registry.addConverter(new Converter<Date, Calendar>() { |
|
||||||
public Calendar convert(Date date) { |
|
||||||
final GregorianCalendar calendar = new GregorianCalendar(); |
|
||||||
calendar.setTime(date); |
|
||||||
return calendar; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
registry.addConverter(new Converter<Integer, Long>() { |
|
||||||
public Long convert(Integer integer) { |
|
||||||
return integer.longValue(); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
registry.addConverter(new Converter<Integer, Double>() { |
|
||||||
public Double convert(Integer integer) { |
|
||||||
return integer.doubleValue(); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
|
|
||||||
registry.addConverter(new Converter<CharSequence, Date>() { |
|
||||||
|
|
||||||
public Date convert(CharSequence s) { |
|
||||||
try { |
|
||||||
final Long time = Long.valueOf(s.toString()); |
|
||||||
return new Date(time); |
|
||||||
} catch (NumberFormatException e) { |
|
||||||
// ignore
|
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
registry.addConverter(new Converter<CharSequence, Double>() { |
|
||||||
|
|
||||||
public Double convert(CharSequence s) { |
|
||||||
try { |
|
||||||
return Double.valueOf(s.toString()); |
|
||||||
} catch (NumberFormatException e) { |
|
||||||
return (double) 0; |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
registry.addConverter(new Converter<CharSequence, Integer>() { |
|
||||||
|
|
||||||
public Integer convert(CharSequence s) { |
|
||||||
try { |
|
||||||
return Integer.valueOf(s.toString()); |
|
||||||
} catch (NumberFormatException e) { |
|
||||||
// ignore
|
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
}); |
|
||||||
registry.addConverter(new Converter<CharSequence, Long>() { |
|
||||||
|
|
||||||
public Long convert(CharSequence s) { |
|
||||||
try { |
|
||||||
return Long.valueOf(s.toString()); |
|
||||||
} catch (NumberFormatException e) { |
|
||||||
// ignore
|
|
||||||
} |
|
||||||
return 0L; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
|
|
||||||
registry.addConverter(new Converter<Object, String>() { |
|
||||||
public String convert(Object o) { |
|
||||||
return o.toString(); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
registry.addConverter(new Converter<Calendar, String>() { |
|
||||||
public String convert(Calendar calendar) { |
|
||||||
return String.valueOf(calendar.getTime().getTime()); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
registry.addConverter(new Converter<CharSequence, Calendar>() { |
|
||||||
|
|
||||||
public Calendar convert(CharSequence s) { |
|
||||||
try { |
|
||||||
Date date = new Date(Long.valueOf(s.toString())); |
|
||||||
Calendar c = new GregorianCalendar(); |
|
||||||
c.setTime(date); |
|
||||||
return c; |
|
||||||
} catch (NumberFormatException e) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,43 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.types; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.MappingContext; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
|
|
||||||
/** |
|
||||||
* Models an embedded component |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class Embedded<T> extends ToOne<T> { |
|
||||||
|
|
||||||
public Embedded(PersistentEntity owner, MappingContext context, PropertyDescriptor descriptor) { |
|
||||||
super(owner, context, descriptor); |
|
||||||
} |
|
||||||
|
|
||||||
public Embedded(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
super(owner, context, name, type); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isOwningSide() { |
|
||||||
return true; // embedded instances are always owned
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,36 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.types; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.AbstractPersistentProperty; |
|
||||||
import org.springframework.data.mapping.model.MappingContext; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
|
|
||||||
/** |
|
||||||
* Represents the identity of a persistent entity |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class Identity<T> extends AbstractPersistentProperty { |
|
||||||
public Identity(PersistentEntity owner, MappingContext context, PropertyDescriptor descriptor) { |
|
||||||
super(owner, context, descriptor); |
|
||||||
} |
|
||||||
public Identity(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
super(owner, context, name, type); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,36 +0,0 @@ |
|||||||
/* 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.types; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.MappingContext; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
|
|
||||||
/** |
|
||||||
* Models a many-to-many association between one class and another |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class ManyToMany<T> extends Association<T> { |
|
||||||
public ManyToMany(PersistentEntity owner, MappingContext context, PropertyDescriptor descriptor) { |
|
||||||
super(owner, context, descriptor); |
|
||||||
} |
|
||||||
|
|
||||||
public ManyToMany(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
super(owner, context, name, type); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,37 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.types; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.MappingContext; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
|
|
||||||
/** |
|
||||||
* Models a many-to-one association |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class ManyToOne<T> extends ToOne<T> { |
|
||||||
public ManyToOne(PersistentEntity owner, MappingContext context, PropertyDescriptor descriptor) { |
|
||||||
super(owner, context, descriptor); |
|
||||||
} |
|
||||||
|
|
||||||
public ManyToOne(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
super(owner, context, name, type); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,36 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.types; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.MappingContext; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
|
|
||||||
/** |
|
||||||
* Models a one-to-many association |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class OneToMany<T> extends Association<T> { |
|
||||||
public OneToMany(PersistentEntity owner, MappingContext context, PropertyDescriptor descriptor) { |
|
||||||
super(owner, context, descriptor); |
|
||||||
} |
|
||||||
|
|
||||||
public OneToMany(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
super(owner, context, name, type); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,36 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.types; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.MappingContext; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
|
|
||||||
/** |
|
||||||
* Models a one-to-one association |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class OneToOne<T> extends ToOne<T> { |
|
||||||
public OneToOne(PersistentEntity owner, MappingContext context, PropertyDescriptor descriptor) { |
|
||||||
super(owner, context, descriptor); |
|
||||||
} |
|
||||||
|
|
||||||
public OneToOne(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
super(owner, context, name, type); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,37 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.types; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.AbstractPersistentProperty; |
|
||||||
import org.springframework.data.mapping.model.MappingContext; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
|
|
||||||
/** |
|
||||||
* Models a simple property type |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public abstract class Simple<T> extends AbstractPersistentProperty { |
|
||||||
public Simple(PersistentEntity owner, MappingContext context, PropertyDescriptor descriptor) { |
|
||||||
super(owner, context, descriptor); |
|
||||||
} |
|
||||||
|
|
||||||
public Simple(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
super(owner, context, name, type); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,47 +0,0 @@ |
|||||||
/* 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.types; |
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.MappingContext; |
|
||||||
import org.springframework.data.mapping.model.PersistentEntity; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.1 |
|
||||||
*/ |
|
||||||
public abstract class ToOne<T> extends Association<T> { |
|
||||||
|
|
||||||
private boolean foreignKeyInChild; |
|
||||||
|
|
||||||
public ToOne(PersistentEntity owner, MappingContext context, PropertyDescriptor descriptor) { |
|
||||||
super(owner, context, descriptor); |
|
||||||
} |
|
||||||
|
|
||||||
public ToOne(PersistentEntity owner, MappingContext context, String name, Class type) { |
|
||||||
super(owner, context, name, type); |
|
||||||
} |
|
||||||
|
|
||||||
public void setForeignKeyInChild(boolean foreignKeyInChild) { |
|
||||||
this.foreignKeyInChild = foreignKeyInChild; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isForeignKeyInChild() { |
|
||||||
return foreignKeyInChild; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
@ -1,372 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.reflect; |
|
||||||
|
|
||||||
import org.apache.commons.logging.Log; |
|
||||||
import org.apache.commons.logging.LogFactory; |
|
||||||
import org.springframework.data.mapping.annotation.PersistenceConstructor; |
|
||||||
|
|
||||||
import java.beans.IntrospectionException; |
|
||||||
import java.beans.Introspector; |
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
import java.lang.reflect.*; |
|
||||||
import java.util.*; |
|
||||||
|
|
||||||
/** |
|
||||||
* Reads the properties of a class in an optimized manner avoiding |
|
||||||
* exceptions |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public class ClassPropertyFetcher { |
|
||||||
|
|
||||||
private static final Log log = LogFactory.getLog(ClassPropertyFetcher.class); |
|
||||||
|
|
||||||
private final Class clazz; |
|
||||||
final Map<String, PropertyFetcher> staticFetchers = new HashMap<String, PropertyFetcher>(); |
|
||||||
final Map<String, PropertyFetcher> instanceFetchers = new HashMap<String, PropertyFetcher>(); |
|
||||||
private final ReferenceInstanceCallback callback; |
|
||||||
private PropertyDescriptor[] propertyDescriptors; |
|
||||||
private Constructor preferredConstructor; |
|
||||||
private Map<String, PropertyDescriptor> propertyDescriptorsByName = new HashMap<String, PropertyDescriptor>(); |
|
||||||
private Map<String, Field> fieldsByName = new HashMap<String, Field>(); |
|
||||||
private Map<Class, List<PropertyDescriptor>> typeToPropertyMap = new HashMap<Class, List<PropertyDescriptor>>(); |
|
||||||
|
|
||||||
private static Map<Class, ClassPropertyFetcher> cachedClassPropertyFetchers = new WeakHashMap<Class, ClassPropertyFetcher>(); |
|
||||||
|
|
||||||
public static ClassPropertyFetcher forClass(final Class c) { |
|
||||||
ClassPropertyFetcher cpf = cachedClassPropertyFetchers.get(c); |
|
||||||
if (cpf == null) { |
|
||||||
cpf = new ClassPropertyFetcher(c); |
|
||||||
cachedClassPropertyFetchers.put(c, cpf); |
|
||||||
} |
|
||||||
return cpf; |
|
||||||
} |
|
||||||
|
|
||||||
ClassPropertyFetcher(final Class clazz) { |
|
||||||
this.clazz = clazz; |
|
||||||
this.callback = new ReferenceInstanceCallback() { |
|
||||||
public Object getReferenceInstance() { |
|
||||||
try { |
|
||||||
return ReflectionUtils.instantiate(clazz); |
|
||||||
} catch (InstantiationException e) { |
|
||||||
throw new IllegalStateException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
}; |
|
||||||
init(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @return The Java that this ClassPropertyFetcher was constructor for |
|
||||||
*/ |
|
||||||
public Class getJavaClass() { |
|
||||||
return this.clazz; |
|
||||||
} |
|
||||||
|
|
||||||
public Object getReference() { |
|
||||||
if (callback != null) |
|
||||||
return this.callback.getReferenceInstance(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public PropertyDescriptor[] getPropertyDescriptors() { |
|
||||||
return propertyDescriptors; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isReadableProperty(String name) { |
|
||||||
return staticFetchers.containsKey(name) || instanceFetchers.containsKey(name); |
|
||||||
} |
|
||||||
|
|
||||||
private void init() { |
|
||||||
|
|
||||||
List<Class> allClasses = resolveAllClasses(clazz); |
|
||||||
for (Class c : allClasses) { |
|
||||||
Field[] fields = c.getDeclaredFields(); |
|
||||||
for (Field field : fields) { |
|
||||||
processField(field); |
|
||||||
} |
|
||||||
Method[] methods = c.getDeclaredMethods(); |
|
||||||
for (Method method : methods) { |
|
||||||
processMethod(method); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
try { |
|
||||||
this.propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors(); |
|
||||||
} catch (IntrospectionException e) { |
|
||||||
// ignore
|
|
||||||
} |
|
||||||
if (propertyDescriptors != null) { |
|
||||||
for (PropertyDescriptor desc : propertyDescriptors) { |
|
||||||
propertyDescriptorsByName.put(desc.getName(), desc); |
|
||||||
final Class<?> propertyType = desc.getPropertyType(); |
|
||||||
List<PropertyDescriptor> pds = typeToPropertyMap.get(propertyType); |
|
||||||
if (pds == null) { |
|
||||||
pds = new ArrayList<PropertyDescriptor>(); |
|
||||||
typeToPropertyMap.put(propertyType, pds); |
|
||||||
} |
|
||||||
pds.add(desc); |
|
||||||
|
|
||||||
Method readMethod = desc.getReadMethod(); |
|
||||||
if (readMethod != null) { |
|
||||||
boolean staticReadMethod = Modifier.isStatic(readMethod.getModifiers()); |
|
||||||
if (staticReadMethod) { |
|
||||||
staticFetchers.put(desc.getName(), new GetterPropertyFetcher(readMethod, staticReadMethod)); |
|
||||||
} else { |
|
||||||
instanceFetchers.put(desc.getName(), new GetterPropertyFetcher(readMethod, staticReadMethod)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Constructor[] constructors = clazz.getConstructors(); |
|
||||||
if (constructors.length == 1 && constructors[0].getGenericParameterTypes().length > 0) { |
|
||||||
preferredConstructor = constructors[0]; |
|
||||||
} else { |
|
||||||
for (Constructor<?> c : constructors) { |
|
||||||
if (c.isAnnotationPresent(PersistenceConstructor.class)) { |
|
||||||
preferredConstructor = c; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public <T> Constructor<T> getPreferredConstructor() { |
|
||||||
return preferredConstructor; |
|
||||||
} |
|
||||||
|
|
||||||
private void processMethod(Method method) { |
|
||||||
if (method.isSynthetic()) |
|
||||||
return; |
|
||||||
if (!Modifier.isPublic(method.getModifiers())) |
|
||||||
return; |
|
||||||
if (Modifier.isStatic(method.getModifiers()) |
|
||||||
&& method.getReturnType() != Void.class) { |
|
||||||
if (method.getParameterTypes().length == 0) { |
|
||||||
String name = method.getName(); |
|
||||||
if (name.indexOf('$') == -1) { |
|
||||||
if (name.length() > 3 && name.startsWith("get") && Character.isUpperCase(name.charAt(3))) { |
|
||||||
name = name.substring(3); |
|
||||||
} else if (name.length() > 2 |
|
||||||
&& name.startsWith("is") |
|
||||||
&& Character.isUpperCase(name.charAt(2)) |
|
||||||
&& (method.getReturnType() == Boolean.class || method.getReturnType() == boolean.class)) { |
|
||||||
name = name.substring(2); |
|
||||||
} |
|
||||||
PropertyFetcher fetcher = new GetterPropertyFetcher(method, true); |
|
||||||
staticFetchers.put(name, fetcher); |
|
||||||
staticFetchers.put(Introspector.decapitalize(name), fetcher); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void processField(Field field) { |
|
||||||
if (field.isSynthetic()) |
|
||||||
return; |
|
||||||
final int modifiers = field.getModifiers(); |
|
||||||
final String name = field.getName(); |
|
||||||
if (!Modifier.isPublic(modifiers)) { |
|
||||||
if (name.indexOf('$') == -1) { |
|
||||||
fieldsByName.put(name, field); |
|
||||||
} |
|
||||||
} else { |
|
||||||
if (name.indexOf('$') == -1) { |
|
||||||
boolean staticField = Modifier.isStatic(modifiers); |
|
||||||
if (staticField) { |
|
||||||
staticFetchers.put(name, new FieldReaderFetcher(field, staticField)); |
|
||||||
} else { |
|
||||||
instanceFetchers.put(name, new FieldReaderFetcher(field, staticField)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private List<Class> resolveAllClasses(Class c) { |
|
||||||
List<Class> list = new ArrayList<Class>(); |
|
||||||
Class currentClass = c; |
|
||||||
while (currentClass != null) { |
|
||||||
list.add(currentClass); |
|
||||||
currentClass = currentClass.getSuperclass(); |
|
||||||
} |
|
||||||
Collections.reverse(list); |
|
||||||
return list; |
|
||||||
} |
|
||||||
|
|
||||||
public Object getPropertyValue(String name) { |
|
||||||
return getPropertyValue(name, false); |
|
||||||
} |
|
||||||
|
|
||||||
public Object getPropertyValue(String name, boolean onlyInstanceProperties) { |
|
||||||
PropertyFetcher fetcher = resolveFetcher(name, onlyInstanceProperties); |
|
||||||
return getPropertyValueWithFetcher(name, fetcher); |
|
||||||
} |
|
||||||
|
|
||||||
private Object getPropertyValueWithFetcher(String name, PropertyFetcher fetcher) { |
|
||||||
if (fetcher != null) { |
|
||||||
try { |
|
||||||
return fetcher.get(callback); |
|
||||||
} catch (Exception e) { |
|
||||||
log.warn("Error fetching property's " + name + " value from class " + clazz.getName(), e); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public <T> T getStaticPropertyValue(String name, Class<T> c) { |
|
||||||
PropertyFetcher fetcher = staticFetchers.get(name); |
|
||||||
if (fetcher != null) { |
|
||||||
Object v = getPropertyValueWithFetcher(name, fetcher); |
|
||||||
return returnOnlyIfInstanceOf(v, c); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public <T> T getPropertyValue(String name, Class<T> c) { |
|
||||||
return returnOnlyIfInstanceOf(getPropertyValue(name, false), c); |
|
||||||
} |
|
||||||
|
|
||||||
private <T> T returnOnlyIfInstanceOf(Object value, Class<T> type) { |
|
||||||
if ((value != null) && (type == Object.class || ReflectionUtils.isAssignableFrom(type, value.getClass()))) { |
|
||||||
return (T) value; |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private PropertyFetcher resolveFetcher(String name, |
|
||||||
boolean onlyInstanceProperties) { |
|
||||||
PropertyFetcher fetcher = null; |
|
||||||
if (!onlyInstanceProperties) { |
|
||||||
fetcher = staticFetchers.get(name); |
|
||||||
} |
|
||||||
if (fetcher == null) { |
|
||||||
fetcher = instanceFetchers.get(name); |
|
||||||
} |
|
||||||
return fetcher; |
|
||||||
} |
|
||||||
|
|
||||||
public Class getPropertyType(String name) { |
|
||||||
return getPropertyType(name, false); |
|
||||||
} |
|
||||||
|
|
||||||
public Class getPropertyType(String name, boolean onlyInstanceProperties) { |
|
||||||
PropertyFetcher fetcher = resolveFetcher(name, onlyInstanceProperties); |
|
||||||
if (fetcher != null) { |
|
||||||
return fetcher.getPropertyType(name); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public PropertyDescriptor getPropertyDescriptor(String name) { |
|
||||||
return propertyDescriptorsByName.get(name); |
|
||||||
} |
|
||||||
|
|
||||||
public List<PropertyDescriptor> getPropertiesOfType(Class javaClass) { |
|
||||||
final List<PropertyDescriptor> propertyDescriptorList = typeToPropertyMap.get(javaClass); |
|
||||||
if (propertyDescriptorList == null) return Collections.emptyList(); |
|
||||||
return propertyDescriptorList; |
|
||||||
} |
|
||||||
|
|
||||||
public List<PropertyDescriptor> getPropertiesAssignableToType(Class assignableType) { |
|
||||||
List<PropertyDescriptor> properties = new ArrayList<PropertyDescriptor>(); |
|
||||||
for (Class type : typeToPropertyMap.keySet()) { |
|
||||||
if (assignableType.isAssignableFrom(type)) { |
|
||||||
properties.addAll(typeToPropertyMap.get(type)); |
|
||||||
} |
|
||||||
} |
|
||||||
return properties; |
|
||||||
} |
|
||||||
|
|
||||||
public static interface ReferenceInstanceCallback { |
|
||||||
public Object getReferenceInstance(); |
|
||||||
} |
|
||||||
|
|
||||||
static interface PropertyFetcher { |
|
||||||
public Object get(ReferenceInstanceCallback callback) |
|
||||||
throws IllegalArgumentException, IllegalAccessException, |
|
||||||
InvocationTargetException; |
|
||||||
|
|
||||||
public Class getPropertyType(String name); |
|
||||||
} |
|
||||||
|
|
||||||
static class GetterPropertyFetcher implements PropertyFetcher { |
|
||||||
private final Method readMethod; |
|
||||||
private final boolean staticMethod; |
|
||||||
|
|
||||||
GetterPropertyFetcher(Method readMethod, boolean staticMethod) { |
|
||||||
this.readMethod = readMethod; |
|
||||||
this.staticMethod = staticMethod; |
|
||||||
ReflectionUtils.makeAccessible(readMethod); |
|
||||||
} |
|
||||||
|
|
||||||
public Object get(ReferenceInstanceCallback callback) |
|
||||||
throws IllegalArgumentException, IllegalAccessException, |
|
||||||
InvocationTargetException { |
|
||||||
if (staticMethod) { |
|
||||||
return readMethod.invoke(null, (Object[]) null); |
|
||||||
} else { |
|
||||||
if (callback != null) { |
|
||||||
return readMethod.invoke(callback.getReferenceInstance(), |
|
||||||
(Object[]) null); |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Class getPropertyType(String name) { |
|
||||||
return readMethod.getReturnType(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static class FieldReaderFetcher implements PropertyFetcher { |
|
||||||
private final Field field; |
|
||||||
private final boolean staticField; |
|
||||||
|
|
||||||
public FieldReaderFetcher(Field field, boolean staticField) { |
|
||||||
this.field = field; |
|
||||||
this.staticField = staticField; |
|
||||||
ReflectionUtils.makeAccessible(field); |
|
||||||
} |
|
||||||
|
|
||||||
public Object get(ReferenceInstanceCallback callback) |
|
||||||
throws IllegalArgumentException, IllegalAccessException, |
|
||||||
InvocationTargetException { |
|
||||||
if (staticField) { |
|
||||||
return field.get(null); |
|
||||||
} else { |
|
||||||
if (callback != null) { |
|
||||||
return field.get(callback.getReferenceInstance()); |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Class getPropertyType(String name) { |
|
||||||
return field.getType(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Field getDeclaredField(String name) { |
|
||||||
return fieldsByName.get(name); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,209 +0,0 @@ |
|||||||
/* Copyright 2004-2005 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.reflect; |
|
||||||
|
|
||||||
import org.springframework.beans.BeanUtils; |
|
||||||
|
|
||||||
import java.beans.PropertyDescriptor; |
|
||||||
import java.lang.Boolean; |
|
||||||
import java.lang.Byte; |
|
||||||
import java.lang.Character; |
|
||||||
import java.lang.Class; |
|
||||||
import java.lang.Double; |
|
||||||
import java.lang.Exception; |
|
||||||
import java.lang.Float; |
|
||||||
import java.lang.IllegalAccessException; |
|
||||||
import java.lang.InstantiationException; |
|
||||||
import java.lang.Integer; |
|
||||||
import java.lang.Long; |
|
||||||
import java.lang.NoSuchMethodException; |
|
||||||
import java.lang.NullPointerException; |
|
||||||
import java.lang.Object; |
|
||||||
import java.lang.Short; |
|
||||||
import java.lang.reflect.Field; |
|
||||||
import java.lang.reflect.InvocationTargetException; |
|
||||||
import java.lang.reflect.Method; |
|
||||||
import java.lang.reflect.Modifier; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.HashSet; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
/** |
|
||||||
* Provides methods to help with reflective operations |
|
||||||
* |
|
||||||
* @author Graeme Rocher |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public class ReflectionUtils { |
|
||||||
|
|
||||||
public static final Map<Class<?>, Class<?>> PRIMITIVE_TYPE_COMPATIBLE_CLASSES = new HashMap<Class<?>, Class<?>>(); |
|
||||||
private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; |
|
||||||
|
|
||||||
/** |
|
||||||
* Just add two entries to the class compatibility map |
|
||||||
* |
|
||||||
* @param left |
|
||||||
* @param right |
|
||||||
*/ |
|
||||||
private static void registerPrimitiveClassPair(Class<?> left, Class<?> right) { |
|
||||||
PRIMITIVE_TYPE_COMPATIBLE_CLASSES.put(left, right); |
|
||||||
PRIMITIVE_TYPE_COMPATIBLE_CLASSES.put(right, left); |
|
||||||
} |
|
||||||
|
|
||||||
static { |
|
||||||
registerPrimitiveClassPair(Boolean.class, boolean.class); |
|
||||||
registerPrimitiveClassPair(Integer.class, int.class); |
|
||||||
registerPrimitiveClassPair(Short.class, short.class); |
|
||||||
registerPrimitiveClassPair(Byte.class, byte.class); |
|
||||||
registerPrimitiveClassPair(Character.class, char.class); |
|
||||||
registerPrimitiveClassPair(Long.class, long.class); |
|
||||||
registerPrimitiveClassPair(Float.class, float.class); |
|
||||||
registerPrimitiveClassPair(Double.class, double.class); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Make the given field accessible, explicitly setting it accessible if necessary. |
|
||||||
* The <code>setAccessible(true)</code> method is only called when actually necessary, |
|
||||||
* to avoid unnecessary conflicts with a JVM SecurityManager (if active). |
|
||||||
* <p/> |
|
||||||
* Based on the same method in Spring core. |
|
||||||
* |
|
||||||
* @param field the field to make accessible |
|
||||||
* @see java.lang.reflect.Field#setAccessible |
|
||||||
*/ |
|
||||||
public static void makeAccessible(Field field) { |
|
||||||
if (!Modifier.isPublic(field.getModifiers()) || |
|
||||||
!Modifier.isPublic(field.getDeclaringClass().getModifiers())) { |
|
||||||
field.setAccessible(true); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Make the given method accessible, explicitly setting it accessible if necessary. |
|
||||||
* The <code>setAccessible(true)</code> method is only called when actually necessary, |
|
||||||
* to avoid unnecessary conflicts with a JVM SecurityManager (if active). |
|
||||||
* <p/> |
|
||||||
* Based on the same method in Spring core. |
|
||||||
* |
|
||||||
* @param method the method to make accessible |
|
||||||
* @see java.lang.reflect.Method#setAccessible |
|
||||||
*/ |
|
||||||
public static void makeAccessible(Method method) { |
|
||||||
if (!Modifier.isPublic(method.getModifiers()) || |
|
||||||
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) { |
|
||||||
method.setAccessible(true); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* <p>Tests whether or not the left hand type is compatible with the right hand type in Groovy |
|
||||||
* terms, i.e. can the left type be assigned a value of the right hand type in Groovy.</p> |
|
||||||
* <p>This handles Java primitive type equivalence and uses isAssignableFrom for all other types, |
|
||||||
* with a bit of magic for native types and polymorphism i.e. Number assigned an int. |
|
||||||
* If either parameter is null an exception is thrown</p> |
|
||||||
* |
|
||||||
* @param leftType The type of the left hand part of a notional assignment |
|
||||||
* @param rightType The type of the right hand part of a notional assignment |
|
||||||
* @return True if values of the right hand type can be assigned in Groovy to variables of the left hand type. |
|
||||||
*/ |
|
||||||
public static boolean isAssignableFrom(final Class<?> leftType, final Class<?> rightType) { |
|
||||||
if (leftType == null) { |
|
||||||
throw new NullPointerException("Left type is null!"); |
|
||||||
} |
|
||||||
if (rightType == null) { |
|
||||||
throw new NullPointerException("Right type is null!"); |
|
||||||
} |
|
||||||
if (leftType == Object.class) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
if (leftType == rightType) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
// check for primitive type equivalence
|
|
||||||
Class<?> r = PRIMITIVE_TYPE_COMPATIBLE_CLASSES.get(leftType); |
|
||||||
boolean result = r == rightType; |
|
||||||
|
|
||||||
if (!result) { |
|
||||||
// If no primitive <-> wrapper match, it may still be assignable
|
|
||||||
// from polymorphic primitives i.e. Number -> int (AKA Integer)
|
|
||||||
if (rightType.isPrimitive()) { |
|
||||||
// see if incompatible
|
|
||||||
r = PRIMITIVE_TYPE_COMPATIBLE_CLASSES.get(rightType); |
|
||||||
if (r != null) { |
|
||||||
result = leftType.isAssignableFrom(r); |
|
||||||
} |
|
||||||
} else { |
|
||||||
// Otherwise it may just be assignable using normal Java polymorphism
|
|
||||||
result = leftType.isAssignableFrom(rightType); |
|
||||||
} |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Instantiates an object catching any relevant exceptions and rethrowing as a runtime exception |
|
||||||
* |
|
||||||
* @param clazz The class
|
|
||||||
* @return The instantiated object or null if the class parameter was null |
|
||||||
*/ |
|
||||||
public static Object instantiate(Class clazz) throws InstantiationException { |
|
||||||
if (clazz == null) return null; |
|
||||||
try { |
|
||||||
return clazz.getConstructor(EMPTY_CLASS_ARRAY).newInstance(); |
|
||||||
} catch (IllegalAccessException e) { |
|
||||||
throw new InstantiationException(e.getClass().getName() + " error creating instance of class [" + e.getMessage() + "]: " + e.getMessage()); |
|
||||||
} catch (InvocationTargetException e) { |
|
||||||
throw new InstantiationException(e.getClass().getName() + " error creating instance of class [" + e.getMessage() + "]: " + e.getMessage()); |
|
||||||
} catch (NoSuchMethodException e) { |
|
||||||
throw new InstantiationException(e.getClass().getName() + " error creating instance of class [" + e.getMessage() + "]: " + e.getMessage()); |
|
||||||
} catch (java.lang.InstantiationException e) { |
|
||||||
throw new InstantiationException(e.getClass().getName() + " error creating instance of class [" + e.getMessage() + "]: " + e.getMessage()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Retrieves all the properties of the given class for the given type |
|
||||||
* |
|
||||||
* @param clazz The class to retrieve the properties from |
|
||||||
* @param propertyType The type of the properties you wish to retrieve |
|
||||||
* @return An array of PropertyDescriptor instances |
|
||||||
*/ |
|
||||||
public static PropertyDescriptor[] getPropertiesOfType(Class<?> clazz, Class<?> propertyType) { |
|
||||||
if (clazz == null || propertyType == null) { |
|
||||||
return new PropertyDescriptor[0]; |
|
||||||
} |
|
||||||
|
|
||||||
Set<PropertyDescriptor> properties = new HashSet<PropertyDescriptor>(); |
|
||||||
try { |
|
||||||
for (PropertyDescriptor descriptor : BeanUtils.getPropertyDescriptors(clazz)) { |
|
||||||
Class<?> currentPropertyType = descriptor.getPropertyType(); |
|
||||||
if (isTypeInstanceOfPropertyType(propertyType, currentPropertyType)) { |
|
||||||
properties.add(descriptor); |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
// if there are any errors in instantiating just return null for the moment
|
|
||||||
return new PropertyDescriptor[0]; |
|
||||||
} |
|
||||||
return properties.toArray(new PropertyDescriptor[properties.size()]); |
|
||||||
} |
|
||||||
|
|
||||||
private static boolean isTypeInstanceOfPropertyType(Class<?> type, Class<?> propertyType) { |
|
||||||
return propertyType.isAssignableFrom(type) && !propertyType.equals(Object.class); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
Loading…
Reference in new issue