Browse Source

spring-data-commons object mapping support for MongoDB

pull/1/head
J. Brisbin 15 years ago
parent
commit
e66f95bcf8
  1. 4
      spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoChangeSetPersister.java
  2. 31
      spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoEntityOperations.java
  3. 96
      spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java
  4. 15
      spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Account.java
  5. 76
      spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Person.java
  6. 33
      spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Resume.java
  7. 31
      spring-data-mongodb-cross-store/src/test/resources/META-INF/spring/applicationContext.xml
  8. 505
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java
  9. 2
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/index/CompoundIndex.java
  10. 1
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/index/Indexed.java
  11. 17
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/DBRef.java
  12. 13
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/Document.java
  13. 45
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MappingException.java
  14. 499
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MappingIntrospector.java
  15. 33
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoClassMapping.java
  16. 37
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoCollection.java
  17. 167
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationBuilder.java
  18. 417
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationStrategy.java
  19. 59
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingContext.java
  20. 43
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingFactory.java
  21. 22
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentEntity.java
  22. 38
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoProperty.java
  23. 4
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/AbstractMongoQuery.java
  24. 32
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoEntityInformation.java
  25. 141
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoQueryMethod.java
  26. 21
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepository.java
  27. 38
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepositoryFactoryBean.java
  28. 2
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/PartTreeMongoQuery.java
  29. 15
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/SimpleMongoRepository.java
  30. 14
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/Id.java
  31. 12
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/IdentifiedBy.java
  32. 17
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/ManyToMany.java
  33. 17
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/OneToMany.java
  34. 14
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/OneToOne.java
  35. 30
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/PersistenceConstructor.java
  36. 11
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/PersistenceStrategy.java
  37. 37
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/Persistent.java
  38. 14
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/Transient.java
  39. 42
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/AbstractClassMapping.java
  40. 156
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/AbstractMappingContext.java
  41. 193
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/AbstractPersistentEntity.java
  42. 77
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java
  43. 31
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/ClassMapping.java
  44. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/DatastoreConfigurationException.java
  45. 31
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/IdentityMapping.java
  46. 32
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/IllegalMappingException.java
  47. 72
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/MappingConfigurationStrategy.java
  48. 169
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/MappingContext.java
  49. 278
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/MappingFactory.java
  50. 30
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java
  51. 167
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/PersistentEntity.java
  52. 51
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/PersistentProperty.java
  53. 25
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/PropertyMapping.java
  54. 146
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/Association.java
  55. 65
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/Basic.java
  56. 133
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/BasicTypeConverterRegistrar.java
  57. 43
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/Embedded.java
  58. 36
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/Identity.java
  59. 36
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/ManyToMany.java
  60. 37
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/ManyToOne.java
  61. 36
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/OneToMany.java
  62. 36
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/OneToOne.java
  63. 37
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/Simple.java
  64. 47
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/ToOne.java
  65. 372
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/reflect/ClassPropertyFetcher.java
  66. 209
      spring-data-mongodb/src/main/java/org/springframework/data/mapping/reflect/ReflectionUtils.java
  67. 3
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoOperationsUnitTests.java
  68. 3
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/config/MongoNamespaceTests.java
  69. 6
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Account.java
  70. 8
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java
  71. 18
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Person.java
  72. 2
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java
  73. 6
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoEntityMetadataUnitTests.java
  74. 8
      spring-data-mongodb/src/test/resources/mapping.xml
  75. 4
      spring-data-mongodb/template.mf

4
spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoChangeSetPersister.java

@ -53,10 +53,10 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> { @@ -53,10 +53,10 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
// System.err.println("Mongo persisted property [" + propertyName + "] :: " + propertyKey + " = " + dbo.get(propertyKey));
if (propertyKey.startsWith("_")) {
// Id or class
changeSet.set(propertyName, dbo.get(propertyKey));
changeSet.set(propertyKey, dbo.get(propertyKey));
} else {
//throw new IllegalStateException("Unknown property [" + propertyName + "] found in MongoDB store");
changeSet.set(propertyName, dbo.get(propertyKey));
changeSet.set(propertyKey, dbo.get(propertyKey));
}
}
} catch (MongoException ex) {

31
spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoEntityOperations.java

@ -4,28 +4,51 @@ import java.lang.reflect.Field; @@ -4,28 +4,51 @@ import java.lang.reflect.Field;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.document.mongodb.MongoTemplate;
import org.springframework.persistence.OrderedEntityOperations;
import org.springframework.persistence.RelatedEntity;
import org.springframework.persistence.support.ChangeSet;
import org.springframework.persistence.support.ChangeSetBacked;
import org.springframework.persistence.support.ChangeSetPersister.NotFoundException;
import org.springframework.persistence.support.EntityInstantiator;
import org.springframework.persistence.support.HashMapChangeSet;
import com.mongodb.DB;
public class MongoEntityOperations extends OrderedEntityOperations<Object, ChangeSetBacked> {
@Autowired
private DB mongoDb;
private MongoTemplate mongoTemplate;
@Autowired
private EntityInstantiator<ChangeSetBacked, ChangeSet> entityInstantiator;
private MongoChangeSetPersister changeSetPersister;
public void setEntityInstantiator(EntityInstantiator<ChangeSetBacked, ChangeSet> entityInstantiator) {
this.entityInstantiator = entityInstantiator;
}
@Autowired
public void setChangeSetPersister(MongoChangeSetPersister changeSetPersister) {
this.changeSetPersister = changeSetPersister;
}
@Override
public boolean cacheInEntity() {
return true;
}
@Override
public ChangeSetBacked findEntity(Class<ChangeSetBacked> entityClass, Object pk) throws DataAccessException {
throw new UnsupportedOperationException();
public ChangeSetBacked findEntity(Class<ChangeSetBacked> entityClass, Object key) throws DataAccessException {
try {
ChangeSet cs = new HashMapChangeSet();
changeSetPersister.getPersistentState(entityClass, key, cs);
return entityInstantiator.createEntityFromState(cs, entityClass);
}
catch (NotFoundException ex) {
return null;
}
}
@Override

96
spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java

@ -1,18 +1,24 @@ @@ -1,18 +1,24 @@
package org.springframework.data.document.persistence;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.document.mongodb.MongoTemplate;
import org.springframework.persistence.document.test.Account;
import org.springframework.persistence.document.test.MongoPerson;
import org.springframework.persistence.document.test.Person;
import org.springframework.persistence.document.test.Resume;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.transaction.annotation.Transactional;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
@ -26,12 +32,21 @@ public class CrossStoreMongoTests { @@ -26,12 +32,21 @@ public class CrossStoreMongoTests {
@Autowired
private MongoTemplate mongoTemplate;
private EntityManager entityManager;
private String colName = MongoPerson.class.getSimpleName().toLowerCase();
@BeforeTransaction
public void setUp() {
DBCollection col = this.mongoTemplate.getCollection(MongoPerson.class.getSimpleName().toLowerCase());
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
private void clearData(String collectionName) {
DBCollection col = this.mongoTemplate.getCollection(collectionName);
if (col != null) {
this.mongoTemplate.dropCollection(MongoPerson.class.getName());
this.mongoTemplate.dropCollection(collectionName);
}
}
@ -39,6 +54,7 @@ public class CrossStoreMongoTests { @@ -39,6 +54,7 @@ public class CrossStoreMongoTests {
@Transactional
@Rollback(false)
public void testUserConstructor() {
clearData(colName);
int age = 33;
MongoPerson p = new MongoPerson("Thomas", age);
Assert.assertEquals(age, p.getAge());
@ -49,14 +65,74 @@ public class CrossStoreMongoTests { @@ -49,14 +65,74 @@ public class CrossStoreMongoTests {
@Test
@Transactional
public void testInstantiatedFinder() throws MongoException {
String key = MongoPerson.class.getSimpleName().toLowerCase();
DBCollection col = this.mongoTemplate.getCollection(key);
DBCollection col = this.mongoTemplate.getCollection(colName);
DBObject dbo = col.findOne();
Object id1 = dbo.get("_id");
MongoPerson found = MongoPerson.findPerson(id1);
Object _id = dbo.get("_id");
MongoPerson found = MongoPerson.findPerson(_id);
Assert.assertNotNull(found);
Assert.assertEquals(id1, found.getId());
Assert.assertEquals(_id, found.getId());
System.out.println("Loaded MongoPerson data: " + found);
}
@Test
@Transactional
@Rollback(false)
public void testCreateMongoToJpaEntityRelationship() {
clearData(colName);
Account a = new Account();
a.setName("My Account");
a.setFriendlyName("My Test Acct.");
a.setBalance(123.45F);
a.setId(2L);
MongoPerson p = new MongoPerson("Jack", 22);
entityManager.persist(a);
p.setAccount(a);
}
@Test
@Transactional
public void testReadMongoToJpaEntityRelationship() {
DBCollection col = this.mongoTemplate.getCollection(colName);
DBCursor dbc = col.find();
Object _id = null;
for (DBObject dbo : dbc) {
System.out.println(dbo);
if ("Jack".equals(dbo.get("name"))) {
_id = dbo.get("_id");
break;
}
}
System.out.println(_id);
MongoPerson found = MongoPerson.findPerson(_id);
System.out.println(found);
if (found != null)
System.out.println(found.getAccount());
}
@Test
@Transactional
@Rollback(false)
public void testCreateJpaToMongoEntityRelationship() {
clearData("resume");
Person p = new Person("Thomas", 20);
Resume r = new Resume();
r.addEducation("Skanstulls High School, 1975");
r.addEducation("Univ. of Stockholm, 1980");
r.addJob("DiMark, DBA, 1990-2000");
r.addJob("VMware, Developer, 2007-");
p.setResume(r);
p.setId(1L);
entityManager.persist(p);
}
@Test
@Transactional
public void testReadJpaToMongoEntityRelationship() {
Person found = entityManager.find(Person.class, 1L);
System.out.println(found);
// TODO: This part isn't working yet - there is no reference to the Momgo _id stored in the db
// if (found != null)
// System.out.println(found.getResume());
}
}

15
spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Account.java

@ -16,6 +16,14 @@ public class Account { @@ -16,6 +16,14 @@ public class Account {
private String whatever;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
@ -47,6 +55,11 @@ public class Account { @@ -47,6 +55,11 @@ public class Account {
public void setWhatever(String whatever) {
this.whatever = whatever;
}
@Override
public String toString() {
return "Account [id=" + id + ", name=" + name + ", balance=" + balance
+ ", friendlyName=" + friendlyName + "]";
}
}

76
spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Person.java

@ -0,0 +1,76 @@ @@ -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;
}
}

33
spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Resume.java

@ -0,0 +1,33 @@ @@ -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 + "]";
}
}

31
spring-data-mongodb-cross-store/src/test/resources/META-INF/spring/applicationContext.xml

@ -16,6 +16,37 @@ @@ -16,6 +16,37 @@
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<!-- Store spanning config -->
<bean class="org.springframework.persistence.StoreSpanning"
factory-method="aspectOf" >
<property name="mappingValidator">
<bean class="org.springframework.persistence.support.SimpleMappingValidator" />
</property>
</bean>
<bean id="entityOperationsLocator" class="org.springframework.persistence.ChainingEntityOperationsLocator" />
<bean class="org.springframework.persistence.ChainingForeignStoreKeyManagerLocator" />
<bean class="org.springframework.persistence.PresentKeyForeignStoreKeyManager" autowire="constructor" />
<bean class="org.springframework.persistence.GeneratedFieldForeignStoreKeyManager" />
<bean class="org.springframework.persistence.document.MongoEntityOperations" >
<property name="order" value="5" />
<property name="entityInstantiator">
<bean class="org.springframework.persistence.support.ChangeSetConstructorEntityInstantiator" />
</property>
<property name="changeSetPersister" ref="mongoChangeSetPersister" />
</bean>
<bean class="org.springframework.persistence.EntityManagerJpaEntityOperations" />
<bean class="org.springframework.persistence.support.ChangeSetForeignStoreKeyManager">
<property name="fieldDelimiter" value="#"/>
</bean>
<!-- Mongo config -->
<bean id="mongo" class="org.springframework.data.document.mongodb.MongoFactoryBean">
<property name="host" value="localhost" />

505
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java

@ -24,32 +24,29 @@ import org.apache.commons.logging.Log; @@ -24,32 +24,29 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.types.ObjectId;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.document.mongodb.mapping.MappingException;
import org.springframework.data.document.mongodb.mapping.MappingIntrospector;
import org.springframework.data.document.mongodb.mapping.MongoMappingContext;
import org.springframework.data.mapping.model.MappingInstantiationException;
import org.springframework.data.mapping.AssociationHandler;
import org.springframework.data.mapping.MappingBeanHelper;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.model.*;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static org.springframework.data.document.mongodb.mapping.MappingIntrospector.isSimpleType;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
@ -60,20 +57,22 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext @@ -60,20 +57,22 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext
protected static final ConcurrentMap<Class<?>, Map<String, Field>> fieldsByName = new ConcurrentHashMap<Class<?>, Map<String, Field>>();
protected GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
protected MongoMappingContext mappingContext;
protected SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
protected MappingContext mappingContext;
protected ApplicationContext applicationContext;
protected boolean autowirePersistentBeans = false;
protected boolean useFieldAccessOnly = false;
public MappingMongoConverter() {
initializeConverters();
}
public MappingMongoConverter(MongoMappingContext mappingContext) {
public MappingMongoConverter(MappingContext mappingContext) {
this.mappingContext = mappingContext;
initializeConverters();
}
public MappingMongoConverter(MongoMappingContext mappingContext, List<Converter<?, ?>> converters) {
public MappingMongoConverter(MappingContext mappingContext, List<Converter<?, ?>> converters) {
this.mappingContext = mappingContext;
if (null != converters) {
for (Converter<?, ?> c : converters) {
@ -83,11 +82,11 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext @@ -83,11 +82,11 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext
initializeConverters();
}
public MongoMappingContext getMappingContext() {
public MappingContext getMappingContext() {
return mappingContext;
}
public void setMappingContext(MongoMappingContext mappingContext) {
public void setMappingContext(MappingContext mappingContext) {
this.mappingContext = mappingContext;
}
@ -99,6 +98,14 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext @@ -99,6 +98,14 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext
this.autowirePersistentBeans = autowirePersistentBeans;
}
public boolean isUseFieldAccessOnly() {
return useFieldAccessOnly;
}
public void setUseFieldAccessOnly(boolean useFieldAccessOnly) {
this.useFieldAccessOnly = useFieldAccessOnly;
}
public <T> T convertObjectId(ObjectId id, Class<T> targetType) {
return conversionService.convert(id, targetType);
}
@ -112,208 +119,193 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext @@ -112,208 +119,193 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext
return null;
}
final StandardEvaluationContext ctx = new StandardEvaluationContext();
final StandardEvaluationContext spelCtx = new StandardEvaluationContext();
if (null != applicationContext) {
ctx.setBeanResolver(new BeanFactoryResolver(applicationContext));
spelCtx.setBeanResolver(new BeanFactoryResolver(applicationContext));
}
String[] keySet = dbo.keySet().toArray(new String[]{});
for (String key : keySet) {
ctx.setVariable(key, dbo.get(key));
spelCtx.setVariable(key, dbo.get(key));
}
try {
if ((clazz.isArray() || (clazz.isAssignableFrom(Collection.class) || clazz.isAssignableFrom(List.class))) && dbo instanceof BasicDBList) {
List l = new ArrayList<S>();
BasicDBList dbList = (BasicDBList) dbo;
for (Object o : dbList) {
if (o instanceof DBObject) {
Object newObj = read(clazz.getComponentType(), (DBObject) o);
if (newObj.getClass().isAssignableFrom(clazz.getComponentType())) {
l.add(newObj);
} else {
l.add(conversionService.convert(newObj, clazz.getComponentType()));
}
if ((clazz.isArray()
|| (clazz.isAssignableFrom(Collection.class)
|| clazz.isAssignableFrom(List.class)))
&& dbo instanceof BasicDBList) {
List l = new ArrayList<S>();
BasicDBList dbList = (BasicDBList) dbo;
for (Object o : dbList) {
if (o instanceof DBObject) {
Object newObj = read(clazz.getComponentType(), (DBObject) o);
if (newObj.getClass().isAssignableFrom(clazz.getComponentType())) {
l.add(newObj);
} else {
l.add(o);
l.add(conversionService.convert(newObj, clazz.getComponentType()));
}
} else {
l.add(o);
}
return conversionService.convert(l, clazz);
}
return conversionService.convert(l, clazz);
}
final MappingIntrospector<S> introspector = MappingIntrospector.getInstance(clazz);
final List<String> cparamNames = new ArrayList<String>();
final S instance = introspector.createInstance(new MappingIntrospector.ParameterValueProvider() {
public <T> T getParameterValue(String name, Class<T> type, Expression spelExpr) {
Object o = getValueInternal(name, type, dbo, ctx, spelExpr);
if (o instanceof DBRef) {
cparamNames.add(name);
return read(type, ((DBRef) o).fetch());
} else if (null != o && o.getClass().isAssignableFrom(type)) {
if (type == Object.class && dbo.containsField("_class")) {
try {
cparamNames.add(name);
return (T) conversionService.convert(o, Class.forName(dbo.get("_class").toString()));
} catch (ClassNotFoundException e) {
throw new MappingInstantiationException(e.getMessage(), e);
}
} else {
cparamNames.add(name);
return (T) o;
}
} else {
cparamNames.add(name);
return conversionService.convert(o, type);
}
// Retrieve persistent entity info
PersistentEntity<S> entity = mappingContext.getPersistentEntity(clazz);
final List<String> ctorParamNames = new ArrayList<String>();
final S instance = MappingBeanHelper.constructInstance(entity, new PreferredConstructor.ParameterValueProvider() {
public Object getParameterValue(PreferredConstructor.Parameter parameter) {
String name = parameter.getName();
Class<?> type = parameter.getType();
Object obj = dbo.get(name);
if (obj instanceof DBRef) {
ctorParamNames.add(name);
return read(type, ((DBRef) obj).fetch());
} else if (obj instanceof DBObject) {
ctorParamNames.add(name);
return read(type, ((DBObject) obj));
} else if (null != obj && obj.getClass().isAssignableFrom(type)) {
ctorParamNames.add(name);
return obj;
} else if (null != obj) {
ctorParamNames.add(name);
return conversionService.convert(obj, type);
}
});
// The id is important. Set it first.
if (dbo.containsField("_id")) {
introspector.setValue(introspector.getIdField().getName(), instance, convertObjectId((ObjectId) dbo.get("_id"), introspector.getIdField().getType()));
return null;
}
}, spelCtx);
// Set the ID
PersistentProperty<?> idProperty = entity.getIdProperty();
if (dbo.containsField("_id") || null != idProperty) {
Object idObj = dbo.get("_id");
try {
MappingBeanHelper.setProperty(instance, idProperty, idObj, useFieldAccessOnly);
} catch (IllegalAccessException e) {
throw new MappingException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new MappingException(e.getMessage(), e);
}
}
introspector.doWithProperties(new MappingIntrospector.PropertyHandler() {
public void doWithProperty(PropertyDescriptor descriptor, Field field, Expression spelExpr) {
String name = descriptor.getName();
if (!cparamNames.contains(name)) {
Object o = getValueInternal(name, descriptor.getPropertyType(), dbo, ctx, spelExpr);
try {
if (null != descriptor.getWriteMethod()) {
Class<?> requiredType = descriptor.getWriteMethod().getParameterTypes()[0];
if (null != o && o.getClass().isAssignableFrom(requiredType)) {
introspector.setValue(name, instance, o);
} else {
introspector.setValue(name, instance, conversionService.convert(o, requiredType));
}
} else {
introspector.setValue(name, instance, o);
}
} catch (MappingException e) {
log.error(e.getMessage(), e);
}
// Set properties not already set in the constructor
entity.doWithProperties(new PropertyHandler() {
public void doWithPersistentProperty(PersistentProperty<?> prop) {
if (!ctorParamNames.contains(prop.getName())) {
Object obj = getValueInternal(prop, dbo, spelCtx, prop.getValueAnnotation());
try {
MappingBeanHelper.setProperty(instance, prop, obj, useFieldAccessOnly);
} catch (IllegalAccessException e) {
throw new MappingException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new MappingException(e.getMessage(), e);
}
}
});
// Handle mapping-specific stuff
if (introspector.isMappable()) {
introspector.doWithAssociations(new MappingIntrospector.AssociationHandler() {
public void doWithAssociation(MappingIntrospector.Association association) {
String name = association.getDescriptor().getName();
Object targetObj = dbo.get(name);
if (null != targetObj) {
if (targetObj instanceof DBRef) {
targetObj = read(association.getTargetClass(), ((DBRef) targetObj).fetch());
} else if (targetObj instanceof BasicDBList) {
BasicDBList dbList = (BasicDBList) targetObj;
Collection<Object> targets = CollectionFactory.createCollection(association.getField().getType(), dbList.size());
for (Object tgtDbObj : dbList) {
if (tgtDbObj instanceof DBRef) {
targets.add(read(association.getTargetClass(), ((DBRef) tgtDbObj).fetch()));
} else if (tgtDbObj instanceof DBObject) {
targets.add(read(association.getTargetClass(), (DBObject) tgtDbObj));
} else if (tgtDbObj.getClass().isAssignableFrom(association.getTargetClass())) {
targets.add(tgtDbObj);
} else {
targets.add(conversionService.convert(tgtDbObj, association.getTargetClass()));
}
}
targetObj = targets;
}
introspector.setValue(name, instance, targetObj);
}
}
});
}
});
// Handle associations
entity.doWithAssociations(new AssociationHandler() {
public void doWithAssociation(Association association) {
PersistentProperty<?> inverseProp = association.getInverse();
Object obj = getValueInternal(inverseProp, dbo, spelCtx, inverseProp.getValueAnnotation());
try {
MappingBeanHelper.setProperty(instance, inverseProp, obj);
} catch (IllegalAccessException e) {
throw new MappingException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new MappingException(e.getMessage(), e);
}
}
});
introspector.maybeAutowire(instance, applicationContext, autowirePersistentBeans);
if (null != applicationContext && autowirePersistentBeans) {
applicationContext.getAutowireCapableBeanFactory().autowireBean(instance);
}
if (log.isDebugEnabled()) {
log.debug("Handing back configured object: " + instance);
return instance;
}
public void write(final Object obj, final DBObject dbo) {
if (null == obj) {
return;
}
PersistentEntity<?> entity = mappingContext.getPersistentEntity(obj.getClass());
if (null == entity) {
// Must not have explictly added this entity yet
entity = mappingContext.addPersistentEntity(obj.getClass());
if (null == entity) {
// We can't map this entity for some reason
throw new MappingException("Unable to map entity " + obj);
}
return instance;
} catch (MappingException e) {
throw new RuntimeException(e);
}
}
public void write(final Object o, final DBObject dbo) {
try {
final MappingIntrospector<?> introspector = MappingIntrospector.getInstance(o.getClass());
//final PersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(o.getClass().getName());
Field idFld = introspector.getIdField();
if (null != idFld) {
Object idObj = introspector.getFieldValue(idFld.getName(), o);
if (null != idObj) {
dbo.put("_id", conversionService.convert(idObj, ObjectId.class));
}
// Write the ID
final PersistentProperty<?> idProperty = entity.getIdProperty();
if (!dbo.containsField("_id") && null != idProperty) {
Object idObj = null;
try {
idObj = MappingBeanHelper.getProperty(obj, idProperty, ObjectId.class, useFieldAccessOnly);
} catch (IllegalAccessException e) {
throw new MappingException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new MappingException(e.getMessage(), e);
}
introspector.doWithProperties(new MappingIntrospector.PropertyHandler() {
public void doWithProperty(PropertyDescriptor descriptor, Field field, Expression spelExpr) {
String name = descriptor.getName();
try {
Object newObj = introspector.getFieldValue(name, o);
if (null != newObj) {
if (isSimpleType(newObj.getClass())) {
dbo.put(name, newObj);
} else {
if (newObj.getClass().isArray() || newObj.getClass().isAssignableFrom(Collection.class)) {
BasicDBList dbList = new BasicDBList();
for (Object collObj : (Object[]) (newObj.getClass().isArray() ? newObj : ((Collection) newObj).toArray())) {
BasicDBObject newDbObj = new BasicDBObject();
write(collObj, newDbObj);
dbList.add(newDbObj);
}
dbo.put(name, dbList);
} else {
DBObject newDbObj = new BasicDBObject();
write(newObj, newDbObj);
dbo.put(name, newDbObj);
}
}
}
} catch (MappingException e) {
log.error(e.getMessage(), e);
}
if (null != idObj) {
dbo.put("_id", idObj);
}
}
// Write the properties
entity.doWithProperties(new PropertyHandler() {
public void doWithPersistentProperty(PersistentProperty<?> prop) {
String name = prop.getName();
if (null != idProperty && name.equals(idProperty.getName())) {
return;
}
});
// Handle mapping-specific stuff
if (introspector.isMappable()) {
introspector.doWithAssociations(new MappingIntrospector.AssociationHandler() {
public void doWithAssociation(MappingIntrospector.Association association) {
String name = association.getDescriptor().getName();
Object targetObj = introspector.getFieldValue(name, o);
if (null != targetObj) {
if (isSimpleType(targetObj.getClass())) {
dbo.put(name, targetObj);
} else if (targetObj instanceof Collection || targetObj instanceof List) {
// We're doing a ToMany
BasicDBList dbRefList = new BasicDBList();
for (Object depObj : (targetObj instanceof Collection ? (Collection) targetObj : (List) targetObj)) {
DBObject depDbRef = createDBRef(depObj, depObj.getClass());
if (null != depDbRef) {
dbo.put(name, depDbRef);
}
dbRefList.add(depDbRef);
}
dbo.put(name, dbRefList);
} else {
DBObject depDbRef = createDBRef(targetObj, association.getTargetClass());
if (null != depDbRef) {
dbo.put(name, depDbRef);
}
}
}
if (prop.isAssociation()) {
return;
}
Class<?> type = prop.getType();
Object propertyObj = null;
try {
propertyObj = MappingBeanHelper.getProperty(obj, prop, type, useFieldAccessOnly);
} catch (IllegalAccessException e) {
throw new MappingException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new MappingException(e.getMessage(), e);
}
if (null != propertyObj) {
if (prop.isComplexType()) {
writeObjectInternal(prop, propertyObj, dbo);
} else {
dbo.put(name, propertyObj);
}
});
}
}
} catch (MappingException e) {
log.error(e.getMessage(), e);
}
});
entity.doWithAssociations(new AssociationHandler() {
public void doWithAssociation(Association association) {
PersistentProperty<?> inverseProp = association.getInverse();
Class<?> type = inverseProp.getType();
Object propertyObj = null;
try {
propertyObj = MappingBeanHelper.getProperty(obj, inverseProp, type, useFieldAccessOnly);
} catch (IllegalAccessException e) {
throw new MappingException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new MappingException(e.getMessage(), e);
}
if (null != propertyObj) {
writeObjectInternal(inverseProp, propertyObj, dbo);
}
}
});
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
@ -329,16 +321,81 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext @@ -329,16 +321,81 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext
conversionService.addConverter(ObjectIdToBigIntegerConverter.INSTANCE);
conversionService.addConverter(BigIntegerToIdConverter.INSTANCE);
}
if (!conversionService.canConvert(ObjectId.class, Integer.class)) {
conversionService.addConverter(IntegerToIdConverter.INSTANCE);
conversionService.addConverter(IdToIntegerConverter.INSTANCE);
}
protected void writeObjectInternal(PersistentProperty<?> prop, Object obj, DBObject dbo) {
org.springframework.data.document.mongodb.mapping.DBRef dbref = prop.getField()
.getAnnotation(org.springframework.data.document.mongodb.mapping.DBRef.class);
String name = prop.getName();
if (prop.isCollection()) {
Class<?> type = prop.getType();
BasicDBList dbList = new BasicDBList();
Collection<?> coll = (type.isArray() ? Arrays.asList((Object[]) obj) : (Collection<?>) obj);
for (Object propObjItem : coll) {
if (null != dbref) {
DBObject dbRefObj = createDBRef(propObjItem, dbref);
if (null != dbRefObj) {
dbList.add(dbRefObj);
}
} else {
BasicDBObject propDbObj = new BasicDBObject();
write(propObjItem, propDbObj);
dbList.add(propDbObj);
}
}
dbo.put(name, dbList);
} else {
if (null != dbref) {
DBObject dbRefObj = createDBRef(obj, dbref);
if (null != dbRefObj) {
dbo.put(name, dbRefObj);
}
} else {
BasicDBObject propDbObj = new BasicDBObject();
write(obj, propDbObj);
dbo.put(name, propDbObj);
}
}
}
protected Object getValueInternal(String name, Class<?> type, DBObject dbo, StandardEvaluationContext ctx, Expression spelExpr) {
protected DBObject createDBRef(Object target, org.springframework.data.document.mongodb.mapping.DBRef dbref) {
PersistentEntity<?> targetEntity = mappingContext.getPersistentEntity(target.getClass());
if (null == targetEntity || null == targetEntity.getIdProperty()) {
return null;
}
DBObject dbo = new BasicDBObject();
PersistentProperty<?> idProperty = targetEntity.getIdProperty();
ObjectId id = null;
try {
id = MappingBeanHelper.getProperty(target, idProperty, ObjectId.class, useFieldAccessOnly);
} catch (IllegalAccessException e) {
throw new MappingException(e.getMessage(), e);
} catch (InvocationTargetException e) {
throw new MappingException(e.getMessage(), e);
}
dbo.put("$id", id);
String collection = dbref.collection();
if ("".equals(collection)) {
collection = targetEntity.getType().getSimpleName().toLowerCase();
}
dbo.put("$ref", collection);
String db = dbref.db();
if (!"".equals(db)) {
dbo.put("$db", db);
}
return dbo;
}
protected Object getValueInternal(PersistentProperty<?> prop, DBObject dbo, StandardEvaluationContext ctx, Value spelExpr) {
String name = prop.getName();
Object o;
if (null != spelExpr) {
o = spelExpr.getValue(ctx);
Expression x = spelExpressionParser.parseExpression(spelExpr.value());
o = x.getValue(ctx);
} else {
DBObject from = dbo;
if (dbo instanceof DBRef) {
@ -346,6 +403,25 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext @@ -346,6 +403,25 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext
}
Object dbObj = from.get(name);
if (dbObj instanceof DBObject) {
Class<?> type = prop.getType();
if (type.isArray() && dbObj instanceof BasicDBObject && ((DBObject) dbObj).keySet().size() == 0) {
// It's empty
return Array.newInstance(type.getComponentType(), 0);
} else if (prop.isCollection() && dbObj instanceof BasicDBList) {
BasicDBList dbObjList = (BasicDBList) dbObj;
Object[] items = (Object[]) Array.newInstance(prop.getComponentType(), dbObjList.size());
for (int i = 0; i < dbObjList.size(); i++) {
Object dbObjItem = dbObjList.get(i);
if (dbObjItem instanceof DBRef) {
items[i] = read(prop.getComponentType(), ((DBRef) dbObjItem).fetch());
} else if (dbObjItem instanceof DBObject) {
items[i] = read(prop.getComponentType(), (DBObject) dbObjItem);
} else {
items[i] = dbObjItem;
}
}
return Arrays.asList(items);
}
// It's a complex object, have to read it in
o = read(type, (DBObject) dbObj);
} else {
@ -355,21 +431,6 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext @@ -355,21 +431,6 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext
return o;
}
protected DBObject createDBRef(Object obj, Class<?> targetClass) {
if (null != obj) {
MappingIntrospector<?> introspector = MappingIntrospector.getInstance(obj.getClass());
if (introspector.isMappable()) {
String idName = introspector.getIdField().getName();
Object idVal = introspector.getFieldValue(idName, obj);
BasicDBObject dbRefDbo = new BasicDBObject();
dbRefDbo.put("$ref", targetClass.getSimpleName().toLowerCase());
dbRefDbo.put("$id", convertObjectId(idVal));
return dbRefDbo;
}
}
return null;
}
/**
* Simple singleton to convert {@link ObjectId}s to their {@link String} representation.
*
@ -422,26 +483,4 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext @@ -422,26 +483,4 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext
}
}
public static enum IntegerToIdConverter implements Converter<Integer, ObjectId> {
INSTANCE;
public ObjectId convert(Integer source) {
String s = String.valueOf(source);
StringBuffer buff = new StringBuffer();
for (int i = 0; i < (16 - s.length()); i++) {
buff.append("0");
}
buff.append(s);
return new ObjectId(buff.toString());
}
}
public static enum IdToIntegerConverter implements Converter<ObjectId, Integer> {
INSTANCE;
public Integer convert(ObjectId source) {
return Integer.parseInt(source.toString());
}
}
}

2
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/index/CompoundIndex.java

@ -30,6 +30,8 @@ public @interface CompoundIndex { @@ -30,6 +30,8 @@ public @interface CompoundIndex {
String def();
IndexDirection direction() default IndexDirection.ASCENDING;
boolean unique() default false;
boolean sparse() default false;

1
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/index/Indexed.java

@ -27,6 +27,7 @@ import java.lang.annotation.Target; @@ -27,6 +27,7 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Indexed {
boolean unique() default false;
IndexDirection direction() default IndexDirection.ASCENDING;

17
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/Reference.java → spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/DBRef.java

@ -14,7 +14,9 @@ @@ -14,7 +14,9 @@
* limitations under the License.
*/
package org.springframework.data.mapping.annotation;
package org.springframework.data.document.mongodb.mapping;
import org.springframework.data.annotation.Reference;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -25,9 +27,16 @@ import java.lang.annotation.Target; @@ -25,9 +27,16 @@ import java.lang.annotation.Target;
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Reference {
@Target({
ElementType.FIELD
})
@Reference
public @interface DBRef {
String collection() default "";
String id() default "";
Class<?> targetClass() default Object.class;
String db() default "";
}

13
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/Value.java → spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/Document.java

@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.mapping.annotation;
package org.springframework.data.document.mongodb.mapping;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -26,12 +26,11 @@ import java.lang.annotation.Target; @@ -26,12 +26,11 @@ import java.lang.annotation.Target;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.PARAMETER,
ElementType.FIELD,
ElementType.ANNOTATION_TYPE
ElementType.TYPE,
ElementType.FIELD
})
public @interface Value {
String value();
public @interface Document {
String collection() default "";
}

45
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MappingException.java

@ -1,45 +0,0 @@ @@ -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;
}
}

499
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MappingIntrospector.java

@ -1,499 +0,0 @@ @@ -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);
}
}

33
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoClassMapping.java

@ -1,33 +0,0 @@ @@ -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);
}
}

37
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoCollection.java

@ -1,37 +0,0 @@ @@ -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;
}
}

167
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationBuilder.java

@ -0,0 +1,167 @@ @@ -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;
}
});
}
}

417
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationStrategy.java

@ -1,417 +0,0 @@ @@ -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
}
}
}

59
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingContext.java

@ -1,59 +0,0 @@ @@ -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;
}
}

43
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingFactory.java

@ -1,43 +0,0 @@ @@ -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);
}
}

22
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentEntity.java

@ -16,28 +16,26 @@ @@ -16,28 +16,26 @@
package org.springframework.data.document.mongodb.mapping;
import org.springframework.data.mapping.model.AbstractPersistentEntity;
import org.springframework.data.mapping.model.ClassMapping;
import org.springframework.data.mapping.BasicPersistentEntity;
import org.springframework.data.mapping.model.MappingContext;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class MongoPersistentEntity extends AbstractPersistentEntity {
public class MongoPersistentEntity<T> extends BasicPersistentEntity {
@SuppressWarnings({"unchecked"})
public MongoPersistentEntity(Class<?> javaClass, MappingContext context) {
super(javaClass, context);
}
protected String collection;
@SuppressWarnings({"unchecked"})
public ClassMapping<MongoCollection> getMapping() {
return new MongoClassMapping(this, getMappingContext());
public MongoPersistentEntity(MappingContext mappingContext, Class<T> type) {
super(mappingContext, type);
}
@Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
public String getCollection() {
return collection;
}
public void setCollection(String collection) {
this.collection = collection;
}
}

38
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoProperty.java

@ -1,38 +0,0 @@ @@ -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;
}
}

4
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/AbstractMongoQuery.java

@ -100,7 +100,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { @@ -100,7 +100,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
protected List<?> readCollection(Query query) {
MongoEntityInformation<?> metadata = method.getEntityMetadata();
MongoEntityInformation<?, ?> metadata = method.getEntityInformation();
String collectionName = metadata.getCollectionName();
return template.find(collectionName, query, metadata.getJavaType());
@ -155,7 +155,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { @@ -155,7 +155,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
@SuppressWarnings({ "rawtypes", "unchecked" })
Object execute(Query query) {
MongoEntityInformation<?> metadata = method.getEntityMetadata();
MongoEntityInformation<?, ?> metadata = method.getEntityInformation();
int count = getCollectionCursor(metadata.getCollectionName(), query.getQueryObject()).count();
List<?> result = template.find(metadata.getCollectionName(), applyPagination(query, pageable),

32
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoEntityInformation.java

@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
*/
package org.springframework.data.document.mongodb.repository;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
@ -30,7 +31,7 @@ import org.springframework.util.StringUtils; @@ -30,7 +31,7 @@ import org.springframework.util.StringUtils;
*
* @author Oliver Gierke
*/
class MongoEntityInformation<T extends Object> extends AbstractEntityInformation<T> {
class MongoEntityInformation<T extends Object, ID extends Serializable> extends AbstractEntityInformation<T, ID> {
private static final List<String> FIELD_NAMES = Arrays.asList("ID", "id", "_id");
private Field field;
@ -64,11 +65,22 @@ class MongoEntityInformation<T extends Object> extends AbstractEntityInformation @@ -64,11 +65,22 @@ class MongoEntityInformation<T extends Object> extends AbstractEntityInformation
}
/**
* Returns the name of the collection the entity shall be persisted to.
*
* @return
*/
public String getCollectionName() {
return StringUtils.uncapitalize(getJavaType().getSimpleName());
}
/**
* Returns the attribute that the id will be persisted to.
*
* @return
*/
public String getIdAttribute() {
return "_id";
@ -82,8 +94,22 @@ class MongoEntityInformation<T extends Object> extends AbstractEntityInformation @@ -82,8 +94,22 @@ class MongoEntityInformation<T extends Object> extends AbstractEntityInformation
* org.springframework.data.repository.support.IdAware#getId(java.lang.Object
* )
*/
public Object getId(Object entity) {
@SuppressWarnings("unchecked")
public ID getId(Object entity) {
return (ID) ReflectionUtils.getField(field, entity);
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.repository.support.EntityInformation#getIdType()
*/
@SuppressWarnings("unchecked")
public Class<ID> getIdType() {
return ReflectionUtils.getField(field, entity);
return (Class<ID>) field.getType();
}
}

141
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoQueryMethod.java

@ -15,85 +15,86 @@ @@ -15,85 +15,86 @@
*/
package org.springframework.data.document.mongodb.repository;
import java.lang.reflect.Method;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
/**
*
* TODO - Extract methods for {@link #getAnnotatedQuery()} into superclass as it is currently copied from Spring Data
* JPA
*
* @author Oliver Gierke
*/
class MongoQueryMethod extends QueryMethod {
private final Method method;
private final MongoEntityInformation<?> entityInformation;
/**
* Creates a new {@link MongoQueryMethod} from the given {@link Method}.
*
* @param method
*/
public MongoQueryMethod(Method method, Class<?> domainClass) {
super(method);
this.method = method;
this.entityInformation = new MongoEntityInformation(ClassUtils.getReturnedDomainClass(method));
}
/**
* Returns whether the method has an annotated query.
*
* @return
*/
boolean hasAnnotatedQuery() {
return getAnnotatedQuery() != null;
}
/**
* Returns the query string declared in a {@link Query} annotation or {@literal null} if neither the annotation
* found nor the attribute was specified.
*
* @return
*/
String getAnnotatedQuery() {
String query = (String) AnnotationUtils.getValue(getQueryAnnotation());
return StringUtils.hasText(query) ? query : null;
}
/**
* Returns the field specification to be used for the query.
*
* @return
*/
String getFieldSpecification() {
String value = (String) AnnotationUtils.getValue(getQueryAnnotation(), "fields");
return StringUtils.hasText(value) ? value : null;
}
/* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryMethod#getEntityMetadata()
*/
@Override
public MongoEntityInformation<?> getEntityMetadata() {
return entityInformation;
}
/**
* Returns the {@link Query} annotation that is applied to the method or {@code null} if none available.
*
* @return
*/
private Query getQueryAnnotation() {
return method.getAnnotation(Query.class);
}
private final Method method;
private final MongoEntityInformation<?, ?> entityInformation;
/**
* Creates a new {@link MongoQueryMethod} from the given {@link Method}.
*
* @param method
*/
@SuppressWarnings({"unchecked"})
public MongoQueryMethod(Method method, Class<?> domainClass) {
super(method);
this.method = method;
this.entityInformation = new MongoEntityInformation(ClassUtils.getReturnedDomainClass(method));
}
/**
* Returns whether the method has an annotated query.
*
* @return
*/
boolean hasAnnotatedQuery() {
return getAnnotatedQuery() != null;
}
/**
* Returns the query string declared in a {@link Query} annotation or {@literal null} if neither the annotation
* found nor the attribute was specified.
*
* @return
*/
String getAnnotatedQuery() {
String query = (String) AnnotationUtils.getValue(getQueryAnnotation());
return StringUtils.hasText(query) ? query : null;
}
/**
* Returns the field specification to be used for the query.
*
* @return
*/
String getFieldSpecification() {
String value = (String) AnnotationUtils.getValue(getQueryAnnotation(), "fields");
return StringUtils.hasText(value) ? value : null;
}
/* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryMethod#getEntityMetadata()
*/
@Override
public MongoEntityInformation<?, ?> getEntityInformation() {
return entityInformation;
}
/**
* Returns the {@link Query} annotation that is applied to the method or {@code null} if none available.
*
* @return
*/
private Query getQueryAnnotation() {
return method.getAnnotation(Query.class);
}
}

21
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepository.java

@ -16,16 +16,31 @@ @@ -16,16 +16,31 @@
package org.springframework.data.document.mongodb.repository;
import java.io.Serializable;
import java.util.List;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.PagingAndSortingRepository;
/**
* Mongo specific {@link org.springframework.data.repository.Repository} interface.
*
* @author Oliver Gierke
*/
public interface MongoRepository<T, ID extends Serializable> extends
PagingAndSortingRepository<T, ID> {
public interface MongoRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
/*
* (non-Javadoc)
*
* @see org.springframework.data.repository.Repository#findAll()
*/
@Override
List<T> findAll();
/*
* (non-Javadoc)
*
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
*/
@Override
List<T> findAll(Sort sort);
}

38
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepositoryFactoryBean.java

@ -43,7 +43,7 @@ import org.springframework.util.StringUtils; @@ -43,7 +43,7 @@ import org.springframework.util.StringUtils;
*
* @author Oliver Gierke
*/
public class MongoRepositoryFactoryBean extends RepositoryFactoryBeanSupport<MongoRepository<?, ?>> {
public class MongoRepositoryFactoryBean<T extends MongoRepository<S, ID>, S, ID extends Serializable> extends RepositoryFactoryBeanSupport<T, S, ID> {
private MongoTemplate template;
@ -101,14 +101,7 @@ public class MongoRepositoryFactoryBean extends RepositoryFactoryBeanSupport<Mon @@ -101,14 +101,7 @@ public class MongoRepositoryFactoryBean extends RepositoryFactoryBeanSupport<Mon
this.template = template;
}
@Override
@SuppressWarnings("unchecked")
protected Object getTargetRepository(RepositoryMetadata metadata) {
MongoEntityInformation<Object> info = new MongoEntityInformation<Object>(
(Class<Object>) metadata.getDomainClass());
return new SimpleMongoRepository<Object, Serializable>(info, template);
}
/*
* (non-Javadoc)
@ -162,6 +155,31 @@ public class MongoRepositoryFactoryBean extends RepositoryFactoryBeanSupport<Mon @@ -162,6 +155,31 @@ public class MongoRepositoryFactoryBean extends RepositoryFactoryBeanSupport<Mon
super.validate(metadata, customImplementation);
}
/* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
*/
@Override
public <T, ID extends Serializable> MongoEntityInformation<T, ID> getEntityInformation(
Class<T> domainClass) {
return new MongoEntityInformation<T, ID>(domainClass);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.support.RepositoryMetadata)
*/
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
protected Object getTargetRepository(RepositoryMetadata metadata) {
MongoEntityInformation<?, ?> info = getEntityInformation(
metadata.getDomainClass());
return new SimpleMongoRepository(info, template);
}
}
/**
@ -199,7 +217,7 @@ public class MongoRepositoryFactoryBean extends RepositoryFactoryBeanSupport<Mon @@ -199,7 +217,7 @@ public class MongoRepositoryFactoryBean extends RepositoryFactoryBeanSupport<Mon
index.on(property, order);
}
MongoEntityInformation<?> metadata = query.getQueryMethod().getEntityMetadata();
MongoEntityInformation<?, ?> metadata = query.getQueryMethod().getEntityInformation();
operations.ensureIndex(metadata.getCollectionName(), index);
LOG.debug(String.format("Created index %s!", index.toString()));
}

2
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/PartTreeMongoQuery.java

@ -39,7 +39,7 @@ public class PartTreeMongoQuery extends AbstractMongoQuery { @@ -39,7 +39,7 @@ public class PartTreeMongoQuery extends AbstractMongoQuery {
public PartTreeMongoQuery(MongoQueryMethod method, MongoTemplate template) {
super(method, template);
this.tree = new PartTree(method.getName(), method.getEntityMetadata().getJavaType());
this.tree = new PartTree(method.getName(), method.getEntityInformation().getJavaType());
}
/**

15
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/SimpleMongoRepository.java

@ -41,7 +41,7 @@ import static org.springframework.data.document.mongodb.query.Criteria.where; @@ -41,7 +41,7 @@ import static org.springframework.data.document.mongodb.query.Criteria.where;
public class SimpleMongoRepository<T, ID extends Serializable> implements PagingAndSortingRepository<T, ID> {
private final MongoTemplate template;
private final MongoEntityInformation<T> entityInformation;
private final MongoEntityInformation<T, ID> entityInformation;
/**
* Creates a ew {@link SimpleMongoRepository} for the given {@link MongoInformation} and {@link MongoTemplate}.
@ -49,7 +49,7 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements Paging @@ -49,7 +49,7 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements Paging
* @param metadata
* @param template
*/
public SimpleMongoRepository(MongoEntityInformation<T> metadata, MongoTemplate template) {
public SimpleMongoRepository(MongoEntityInformation<T, ID> metadata, MongoTemplate template) {
Assert.notNull(template);
Assert.notNull(metadata);
@ -105,12 +105,15 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements Paging @@ -105,12 +105,15 @@ public class SimpleMongoRepository<T, ID extends Serializable> implements Paging
return where(entityInformation.getIdAttribute()).is(objectId);
}
public T findOne(ID id) {
return null;
}
/*
* (non-Javadoc)
*
* @see org.springframework.data.repository.Repository#exists(java.io.Serializable )
*/
* (non-Javadoc)
*
* @see org.springframework.data.repository.Repository#exists(java.io.Serializable )
*/
public boolean exists(ID id) {
return findById(id) != null;

14
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/Id.java

@ -1,14 +0,0 @@ @@ -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 {
}

12
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/IdentifiedBy.java

@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
package org.springframework.data.mapping.annotation;
/**
* @author J. Brisbin <jbrisbin@vmware.com>
*/
public enum IdentifiedBy {
DEFAULT,
ANNOTATION,
PROPERTY,
VALUE,
PARENT
}

17
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/ManyToMany.java

@ -1,17 +0,0 @@ @@ -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;
}

17
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/OneToMany.java

@ -1,17 +0,0 @@ @@ -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;
}

14
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/OneToOne.java

@ -1,14 +0,0 @@ @@ -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 {
}

30
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/PersistenceConstructor.java

@ -1,30 +0,0 @@ @@ -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 {
}

11
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/PersistenceStrategy.java

@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
package org.springframework.data.mapping.annotation;
/**
* @author J. Brisbin <jbrisbin@vmware.com>
*/
public enum PersistenceStrategy {
DEFAULT,
KEY_VALUE,
DOCUMENT,
SERIALIZED
}

37
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/Persistent.java

@ -1,37 +0,0 @@ @@ -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";
}

14
spring-data-mongodb/src/main/java/org/springframework/data/mapping/annotation/Transient.java

@ -1,14 +0,0 @@ @@ -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 {
}

42
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/AbstractClassMapping.java

@ -1,42 +0,0 @@ @@ -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);
}
}

156
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/AbstractMappingContext.java

@ -1,156 +0,0 @@ @@ -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);
}
}

193
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/AbstractPersistentEntity.java

@ -1,193 +0,0 @@ @@ -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() + "]";
}
}

77
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java

@ -1,77 +0,0 @@ @@ -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;
}
}

31
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/ClassMapping.java

@ -1,31 +0,0 @@ @@ -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();
}

18
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/DatastoreConfigurationException.java

@ -1,18 +0,0 @@ @@ -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);
}
}

31
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/IdentityMapping.java

@ -1,31 +0,0 @@ @@ -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();
}

32
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/IllegalMappingException.java

@ -1,32 +0,0 @@ @@ -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);
}
}

72
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/MappingConfigurationStrategy.java

@ -1,72 +0,0 @@ @@ -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);
}

169
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/MappingContext.java

@ -1,169 +0,0 @@ @@ -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);
}
}

278
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/MappingFactory.java

@ -1,278 +0,0 @@ @@ -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);
}
};
}
}

30
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java

@ -1,30 +0,0 @@ @@ -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);
}
}

167
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/PersistentEntity.java

@ -1,167 +0,0 @@ @@ -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);
}

51
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/PersistentProperty.java

@ -1,51 +0,0 @@ @@ -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();
}

25
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/PropertyMapping.java

@ -1,25 +0,0 @@ @@ -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();
}

146
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/Association.java

@ -1,146 +0,0 @@ @@ -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());
}
}

65
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/Basic.java

@ -1,65 +0,0 @@ @@ -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
}
}

133
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/BasicTypeConverterRegistrar.java

@ -1,133 +0,0 @@ @@ -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;
}
}
});
}
}

43
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/Embedded.java

@ -1,43 +0,0 @@ @@ -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
}
}

36
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/Identity.java

@ -1,36 +0,0 @@ @@ -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);
}
}

36
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/ManyToMany.java

@ -1,36 +0,0 @@ @@ -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);
}
}

37
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/ManyToOne.java

@ -1,37 +0,0 @@ @@ -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);
}
}

36
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/OneToMany.java

@ -1,36 +0,0 @@ @@ -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);
}
}

36
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/OneToOne.java

@ -1,36 +0,0 @@ @@ -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);
}
}

37
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/Simple.java

@ -1,37 +0,0 @@ @@ -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);
}
}

47
spring-data-mongodb/src/main/java/org/springframework/data/mapping/model/types/ToOne.java

@ -1,47 +0,0 @@ @@ -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;
}
}

372
spring-data-mongodb/src/main/java/org/springframework/data/mapping/reflect/ClassPropertyFetcher.java

@ -1,372 +0,0 @@ @@ -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);
}
}

209
spring-data-mongodb/src/main/java/org/springframework/data/mapping/reflect/ReflectionUtils.java

@ -1,209 +0,0 @@ @@ -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);
}
}

3
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoOperationsUnitTests.java

@ -63,7 +63,8 @@ public abstract class MongoOperationsUnitTests { @@ -63,7 +63,8 @@ public abstract class MongoOperationsUnitTests {
dbo.put("firstName", person.getFirstName());
}
public <S extends Object> S read(Class<S> clazz, DBObject dbo) {
@SuppressWarnings({"unchecked"})
public <S extends Object> S read(Class<S> clazz, DBObject dbo) {
return (S) person;
}

3
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/config/MongoNamespaceTests.java

@ -58,7 +58,8 @@ public class MongoNamespaceTests { @@ -58,7 +58,8 @@ public class MongoNamespaceTests {
public static <T> T readField(String name, Object target) throws Exception {
@SuppressWarnings({"unchecked"})
public static <T> T readField(String name, Object target) throws Exception {
Field field = null;
Class<?> clazz = target.getClass();
do {

6
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Account.java

@ -16,13 +16,13 @@ @@ -16,13 +16,13 @@
package org.springframework.data.document.mongodb.mapping;
import org.springframework.data.mapping.annotation.Id;
import org.springframework.data.mapping.annotation.Persistent;
import org.springframework.data.annotation.Id;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
@Persistent
@Document
public class Account {
@Id

8
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java

@ -25,6 +25,7 @@ import org.springframework.data.document.mongodb.MongoTemplate; @@ -25,6 +25,7 @@ import org.springframework.data.document.mongodb.MongoTemplate;
import org.springframework.data.document.mongodb.convert.MongoConverter;
import org.springframework.data.document.mongodb.query.Criteria;
import org.springframework.data.document.mongodb.query.Query;
import org.springframework.data.mapping.BasicMappingContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ -33,6 +34,7 @@ import java.util.List; @@ -33,6 +34,7 @@ import java.util.List;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
/**
@ -45,7 +47,7 @@ public class MappingTests { @@ -45,7 +47,7 @@ public class MappingTests {
@Autowired
MongoTemplate template;
@Autowired
MongoMappingContext mappingContext;
BasicMappingContext mappingContext;
@Rule
public ExpectedException thrown = ExpectedException.none();
@ -54,9 +56,9 @@ public class MappingTests { @@ -54,9 +56,9 @@ public class MappingTests {
public void setUp() {
template.dropCollection("person");
template.dropCollection("account");
//mappingContext.addPersistentEntity(Person.class);
}
@SuppressWarnings({"unchecked"})
@Test
public void testWrite() {
Person p = new Person(123456789, "John", "Doe", 37);
@ -77,6 +79,8 @@ public class MappingTests { @@ -77,6 +79,8 @@ public class MappingTests {
p.setAccounts(accounts);
template.insert("person", p);
assertNotNull(p.getId());
}
@Test

18
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Person.java

@ -16,21 +16,23 @@ @@ -16,21 +16,23 @@
package org.springframework.data.document.mongodb.mapping;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.annotation.Transient;
import org.springframework.data.document.mongodb.index.CompoundIndex;
import org.springframework.data.document.mongodb.index.CompoundIndexes;
import org.springframework.data.document.mongodb.index.Indexed;
import org.springframework.data.mapping.annotation.*;
import java.util.List;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
@Persistent
@Document
@CompoundIndexes({
@CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}")
})
public class Person {
public class Person<T extends Address> {
@Id
private String id;
@ -42,9 +44,9 @@ public class Person { @@ -42,9 +44,9 @@ public class Person {
private Integer age;
@Transient
private Integer accountTotal;
@Reference
@DBRef
private List<Account> accounts;
private Address address;
private T address;
public Person(Integer ssn, String firstName, String lastName, Integer age) {
this.ssn = ssn;
@ -54,7 +56,7 @@ public class Person { @@ -54,7 +56,7 @@ public class Person {
}
@PersistenceConstructor
public Person(Integer ssn, String firstName, String lastName, Integer age, Address address) {
public Person(Integer ssn, String firstName, String lastName, Integer age, T address) {
this.ssn = ssn;
this.firstName = firstName;
this.lastName = lastName;
@ -114,11 +116,11 @@ public class Person { @@ -114,11 +116,11 @@ public class Person {
this.accounts = accounts;
}
public Address getAddress() {
public T getAddress() {
return address;
}
public void setAddress(Address address) {
public void setAddress(T address) {
this.address = address;
}
}

2
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java

@ -57,7 +57,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { @@ -57,7 +57,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
@Test
public void findsPersonById() throws Exception {
assertThat(repository.findById(dave.getId()), is(dave));
assertThat(repository.findOne(dave.getId()), is(dave));
}
@Test

6
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoEntityMetadataUnitTests.java

@ -31,8 +31,8 @@ public class MongoEntityMetadataUnitTests { @@ -31,8 +31,8 @@ public class MongoEntityMetadataUnitTests {
@Test
public void findsIdField() throws Exception {
MongoEntityInformation<Person> isNewAware =
new MongoEntityInformation<Person>(Person.class);
MongoEntityInformation<Person, Long> isNewAware =
new MongoEntityInformation<Person, Long>(Person.class);
Person person = new Person();
assertThat(isNewAware.isNew(person), is(true));
@ -44,7 +44,7 @@ public class MongoEntityMetadataUnitTests { @@ -44,7 +44,7 @@ public class MongoEntityMetadataUnitTests {
@Test(expected = IllegalArgumentException.class)
public void rejectsClassIfNoIdField() throws Exception {
new MongoEntityInformation<InvalidPerson>(InvalidPerson.class);
new MongoEntityInformation<InvalidPerson, Long>(InvalidPerson.class);
}
class Person {

8
spring-data-mongodb/src/test/resources/mapping.xml

@ -20,8 +20,12 @@ @@ -20,8 +20,12 @@
<constructor-arg ref="mongoConverter"/>
</bean>
<bean id="mappingContext" class="org.springframework.data.document.mongodb.mapping.MongoMappingContext">
<constructor-arg ref="mongoTemplate"/>
<bean id="mappingContext" class="org.springframework.data.mapping.BasicMappingContext">
<property name="mappingConfigurationBuilder">
<bean class="org.springframework.data.document.mongodb.mapping.MongoMappingConfigurationBuilder">
<constructor-arg ref="mongoTemplate"/>
</bean>
</property>
</bean>
<bean class="org.springframework.data.document.mongodb.MongoExceptionTranslator"/>

4
spring-data-mongodb/template.mf

@ -7,11 +7,15 @@ Import-Package: @@ -7,11 +7,15 @@ Import-Package:
Import-Template:
org.springframework.beans.*;version="[3.0.0, 4.0.0)",
org.springframework.core.*;version="[3.0.0, 4.0.0)",
org.springframework.context.*;version="[3.0.0, 4.0.0)",
org.springframework.dao.*;version="[3.0.0, 4.0.0)",
org.springframework.util.*;version="[3.0.0, 4.0.0)",
org.springframework.jmx.export.*;version="[3.0.0, 4.0.0)",
org.springframework.transaction.*;version="[3.0.0, 4.0.0)",
org.springframework.data.core.*;version="[1.0.0, 2.0.0)",
org.springframework.data.annotation.*;version="[1.0.0, 2.0.0)",
org.springframework.data.mapping.*;version="[1.0.0, 2.0.0)",
org.springframework.data.mapping.model.*;version="[1.0.0, 2.0.0)",
org.springframework.data.domain.*;version="[1.0.0, 2.0.0)",
org.springframework.data.document.*;version="[1.0.0, 2.0.0)",
org.springframework.data.repository.*;version="[1.0.0, 2.0.0)",

Loading…
Cancel
Save