Compare commits

...

23 Commits

Author SHA1 Message Date
Spring Buildmaster
928b5a7742 DATAMONGO-654 - Release 1.2.1.RELEASE. 2013-04-17 02:50:08 -07:00
Oliver Gierke
118a52a8d6 DATAMONGO-654 - Prepare 1.2.1.RELEASE.
Upgraded to Spring Data Build 1.0.3.RELEASE. Upgraded to Spring Data Commons 1.5.1.RELEASE. Updated changelog, notice and readme. Polished readme.md.
2013-04-17 11:28:46 +02:00
Oliver Gierke
b47e8ca3da DATAMONGO-656 - Fixed potential NPE in MongoTemplate. 2013-04-17 10:24:37 +02:00
Oliver Gierke
8527d6eb43 DATAMONGO-651 - MongoTemplate now throws Mongo-specific exception with WriteResult.
If the WriteResultChecking is set to EXCEPTION on a MongoTemplate, we now throw a Mongo-specific exception that captures both the WriteResult and MongoActionOperation for further evaluation.
2013-04-15 17:05:56 +02:00
Oliver Gierke
d645c778c3 DATAMONGO-571 - Fixed setting null values during update of versioned entities.
In case of updating a versioned object,the Update object is now constructed from plain key value pairs, not using $set anymore. This will correctly set the null values in the updated document.
2013-04-11 12:01:53 +02:00
Oliver Gierke
5c47f1ae9e DATAMONGO-650 - Added snapshot repository to resolve Spring Data Commons. 2013-04-11 11:08:02 +02:00
Oliver Gierke
9f324bac19 DATAMONGO-648 - Replaced XSD ids with XSD strings.
This change allows usage of Spring Data MongoDB XML namespace elements with <bean /> element using a profile. This scenario creates the case of e.g. two <mongo:db-factory /> declarations in the same XML file.
2013-04-10 20:34:29 +02:00
Oliver Gierke
186caba1ac DATAMONGO-642 - MongoChangeSetPersister now considers mapped collection.
So far the change set persister has used the plain domain type name to persist data. We now consider the collection name defined by the object mapping (through @Document(collection = "…")).
2013-04-02 11:42:50 +02:00
Oliver Gierke
2ebb7e801d DATAMONGO-641 - Fixed potential NullPointerException in MongoLog4jAppender.
Log4j appender now only closes Mongo instance if available.
2013-04-02 10:59:13 +02:00
Oliver Gierke
a932f3474e DATAMONGO-641 - Reformatting to prepare fix. 2013-04-02 10:59:05 +02:00
Oliver Gierke
e992456532 DATAMONGO-638 - MappingContext does not create PersistentEntities for AbstractMaps. 2013-03-28 16:29:55 +01:00
Oliver Gierke
7b34c5cac4 DATAMONGO-629 - Fixed QueryMapper not to massage queries without type information.
So far the QueryMapper applied the id massaging (especially interpreting the default id keys) even if there was no persistence metadata available to do so. This caused e.g. queries handed into MongoTemplate.count(Query, String) to get keys of "id" massaged into "_id" which shouldn't be the case as we cannot assume anything about the documents and the keys contained in them.

So we now only apply the defaults if there is at least persistence metadata present. This means that for methods on MongoOperations that don't take type information of any kind the queries have to be defined in terms of the document, not the object model as we cannot refer to it.
2013-03-27 12:04:06 +01:00
Andrey Bloschetsov
16baf00f5e DATAMONGO-637 - Fixed typo in Query.query(…).
Correcting mispelled "critera". Polished JavaDoc a little.
2013-03-27 11:28:22 +01:00
Oliver Gierke
61a2c56a27 DATAMONGO-632 - Removed schemaLocation attribute from namespace references. 2013-03-25 18:46:34 +01:00
Oliver Gierke
e62437b64a DATAMONGO-633 - Back down to bug fix versions of SD Parent and Core.
Avoid version bump to Querydsl 3.0.
2013-03-25 18:44:18 +01:00
Oliver Gierke
e9a7e887be DATAMONGO-635 - Fixed some Sonar warnings. 2013-03-25 18:13:21 +01:00
Oliver Gierke
b91a66f6f9 DATAMONGO-622 - Saving unversioned object now uses doInsert(…).
We now rather use doInsert(…) if a versioned object is saved the first time to prevent accidental updates not bumping the version number.
2013-02-26 11:39:36 +01:00
Oliver Gierke
a047e54e5a DATAMONGO-621 - Initializing version property now uses ConversionService.
The BeanWrapper used in MongoTemplate.initializeVersionProperty(…) now uses the ConversionService held in the MongoConverter.
2013-02-26 11:39:30 +01:00
Oliver Gierke
8197ff57c8 DATAMONGO-620 - Updating versioned object uses explicit collection name.
We're now handing the collection name given to doSaveVersioned(…) to the update method.
2013-02-26 11:39:22 +01:00
Oliver Gierke
a2136719e1 DATAMONGO-617 - Fixed potential NullPointerException in MongoTemplate.insert(…).
If MongoTemplate.insert(…) was called with a Mongo-simple type (such as a raw DBBobject) it caused a NullPointerException during the lookup of a version property. This is now fixed by correcting the guard.
2013-02-20 12:07:32 +01:00
Oliver Gierke
7bcf142c8d DATAMONGO-613 - Readded JConsole image and upgrade to Spring Data Build 1.1. 2013-02-11 12:41:12 +01:00
Oliver Gierke
d50d03a80e DATAMONGO-612 - Fixed reconfiguration of dist.id. 2013-02-11 12:39:15 +01:00
Spring Buildmaster
ba894a4511 DATAMONGO-609 - Prepare next development iteration. 2013-02-08 13:22:05 +01:00
31 changed files with 718 additions and 310 deletions

133
README.md
View File

@@ -29,19 +29,13 @@ For those in a hurry:
* Download the jar through Maven:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.2.0.BUILD-SNAPSHOT</version>
</dependency>
<repository>
<id>spring-maven-snapshot</id>
<snapshots><enabled>true</enabled></snapshots>
<name>Springframework Maven SNAPSHOT Repository</name>
<url>http://maven.springframework.org/snapshot</url>
</repository>
```xml
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
```
### MongoTemplate
MongoTemplate is the central support class for Mongo database operations. It provides
@@ -54,93 +48,98 @@ Future plans are to support optional logging and/or exception throwing based on
### Easy Data Repository generation
To simplify the creation of Data Repositories a generic Repository interface and default implementation is provided. Furthermore, Spring will automatically create a Repository implementation for you that adds implementations of finder methods you specify on an interface.
To simplify the creation of data repositories a generic `Repository` interface and default implementation is provided. Furthermore, Spring will automatically create a Repository implementation for you that adds implementations of finder methods you specify on an interface.
The Repository interface is
public interface Repository<T, ID extends Serializable> {
```java
public interface Repository<T, ID extends Serializable> {
T save(T entity);
T save(T entity);
List<T> save(Iterable<? extends T> entities);
List<T> save(Iterable<? extends T> entities);
T findById(ID id);
T findById(ID id);
boolean exists(ID id);
boolean exists(ID id);
List<T> findAll();
List<T> findAll();
Long count();
Long count();
void delete(T entity);
void delete(T entity);
void delete(Iterable<? extends T> entities);
void delete(Iterable<? extends T> entities);
void deleteAll();
}
void deleteAll();
}
```
The MongoRepository extends Repository and will in future add more Mongo specific methods.
The `MongoRepository` extends `Repository` and will in future add more Mongo specific methods.
public interface MongoRepository<T, ID extends Serializable> extends
Repository<T, ID> {
}
```java
public interface MongoRepository<T, ID extends Serializable> extends Repository<T, ID> {
}
```
SimpleMongoRepository is the out of the box implementation of the MongoRepository you can use for basid CRUD operations.
`SimpleMongoRepository` is the out of the box implementation of the `MongoRepository` you can use for basid CRUD operations.
To go beyond basic CRUD, extend the MongoRepository interface and supply your own finder methods that follow simple naming conventions such that they can be easily converted into queries.
To go beyond basic CRUD, extend the `MongoRepository` interface and supply your own finder methods that follow simple naming conventions such that they can be easily converted into queries.
For example, given a Person class with first and last name properties, a PersonRepository interface that can query for Person by last name and when the first name matches a regular expression is shown below
For example, given a `Person` class with first and last name properties, a `PersonRepository` interface that can query for `Person` by last name and when the first name matches a regular expression is shown below
public interface PersonRepository extends MongoRepository<Person, Long> {
```java
public interface PersonRepository extends MongoRepository<Person, Long> {
List<Person> findByLastname(String lastname);
List<Person> findByLastname(String lastname);
List<Person> findByFirstnameLike(String firstname);
}
List<Person> findByFirstnameLike(String firstname);
}
```
You can have Spring automatically generate the implemention as shown below
You can have Spring automatically create a proxy for the interface as shown below:
<bean id="template" class="org.springframework.data.document.mongodb.MongoTemplate">
<constructor-arg>
<bean class="com.mongodb.Mongo">
<constructor-arg value="localhost" />
<constructor-arg value="27017" />
</bean>
</constructor-arg>
<constructor-arg value="database" />
<property name="defaultCollectionName" value="springdata" />
</bean>
```xml
<bean id="template" class="org.springframework.data.document.mongodb.MongoTemplate">
<constructor-arg>
<bean class="com.mongodb.Mongo">
<constructor-arg value="localhost" />
<constructor-arg value="27017" />
</bean>
</constructor-arg>
<constructor-arg value="database" />
<property name="defaultCollectionName" value="springdata" />
</bean>
<bean class="org.springframework.data.document.mongodb.repository.MongoRepositoryFactoryBean">
<property name="template" ref="template" />
<property name="repositoryInterface" value="org.springframework.data.document.mongodb.repository.PersonRepository" />
</bean>
<mongo:repositories base-package="com.acme.repository" />
```
This will register an object in the container named PersonRepository. You can use it as shown below
This will find the repository interface and register a proxy object in the container. You can use it as shown below:
@Service
public class MyService {
``java
@Service
public class MyService {
@Autowired
PersonRepository repository;
@Autowired
private final PersonRepository repository;
public void doWork() {
public void doWork() {
repository.deleteAll();
repository.deleteAll();
Person person = new Person();
person.setFirstname("Oliver");
person.setLastname("Gierke");
person = repository.save(person);
Person person = new Person();
person.setFirstname("Oliver");
person.setLastname("Gierke");
person = repository.save(person);
List<Person> lastNameResults = repository.findByLastname("Gierke");
List<Person> lastNameResults = repository.findByLastname("Gierke");
List<Person> firstNameResults = repository.findByFirstnameLike("Oli*");
List<Person> firstNameResults = repository.findByFirstnameLike("Oli*");
}
}
}
}
```
Contributing to Spring Data

View File

@@ -5,7 +5,7 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.2.0.RELEASE</version>
<version>1.2.1.RELEASE</version>
<packaging>pom</packaging>
<name>Spring Data MongoDB</name>
@@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.0.0.RELEASE</version>
<version>1.0.3.RELEASE</version>
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
</parent>
@@ -26,11 +26,10 @@
<module>spring-data-mongodb-distribution</module>
</modules>
<properties>
<project.type>multi</project.type>
<dist.name>spring-data-mongodb</dist.name>
<springdata.commons>1.5.0.RELEASE</springdata.commons>
<dist.id>spring-data-mongodb</dist.id>
<springdata.commons>1.5.1.RELEASE</springdata.commons>
<mongo>2.10.1</mongo>
</properties>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.2.0.RELEASE</version>
<version>1.2.1.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -52,7 +52,7 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.2.0.RELEASE</version>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2013 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.
@@ -34,6 +34,10 @@ import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoException;
/**
* @author Thomas Risberg
* @author Oliver Gierke
*/
public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
private static final String ENTITY_CLASS = "_entity_class";
@@ -58,6 +62,10 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
this.entityManagerFactory = entityManagerFactory;
}
/*
* (non-Javadoc)
* @see org.springframework.data.crossstore.ChangeSetPersister#getPersistentState(java.lang.Class, java.lang.Object, org.springframework.data.crossstore.ChangeSet)
*/
public void getPersistentState(Class<? extends ChangeSetBacked> entityClass, Object id, final ChangeSet changeSet)
throws DataAccessException, NotFoundException {
@@ -100,6 +108,10 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.crossstore.ChangeSetPersister#getPersistentId(org.springframework.data.crossstore.ChangeSetBacked, org.springframework.data.crossstore.ChangeSet)
*/
public Object getPersistentId(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
log.debug("getPersistentId called on " + entity);
if (entityManagerFactory == null) {
@@ -109,6 +121,10 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
return o;
}
/*
* (non-Javadoc)
* @see org.springframework.data.crossstore.ChangeSetPersister#persistState(org.springframework.data.crossstore.ChangeSetBacked, org.springframework.data.crossstore.ChangeSet)
*/
public Object persistState(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
if (cs == null) {
log.debug("Flush: changeset was null, nothing to flush.");
@@ -169,8 +185,13 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
return 0L;
}
/**
* Returns the collection the given entity type shall be persisted to.
*
* @param entityClass must not be {@literal null}.
* @return
*/
private String getCollectionNameForEntity(Class<? extends ChangeSetBacked> entityClass) {
return ClassUtils.getQualifiedName(entityClass);
return mongoTemplate.getCollectionName(entityClass);
}
}

View File

@@ -36,9 +36,14 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
/**
* Integration tests for MongoDB cross-store persistence (mainly {@link MongoChangeSetPersister}).
*
* @author Thomas Risberg
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/META-INF/spring/applicationContext.xml")
public class CrossStoreMongoTests {
@@ -58,7 +63,7 @@ public class CrossStoreMongoTests {
txTemplate = new TransactionTemplate(transactionManager);
clearData(Person.class.getName());
clearData(Person.class);
Address address = new Address(12, "MAin St.", "Boston", "MA", "02101");
@@ -91,11 +96,10 @@ public class CrossStoreMongoTests {
});
}
private void clearData(String collectionName) {
DBCollection col = this.mongoTemplate.getCollection(collectionName);
if (col != null) {
this.mongoTemplate.dropCollection(collectionName);
}
private void clearData(Class<?> domainType) {
String collectionName = mongoTemplate.getCollectionName(domainType);
mongoTemplate.dropCollection(collectionName);
}
@Test
@@ -183,7 +187,7 @@ public class CrossStoreMongoTests {
boolean weFound3 = false;
for (DBObject dbo : this.mongoTemplate.getCollection(Person.class.getName()).find()) {
for (DBObject dbo : this.mongoTemplate.getCollection(mongoTemplate.getCollectionName(Person.class)).find()) {
Assert.assertTrue(!dbo.get("_entity_id").equals(2L));
if (dbo.get("_entity_id").equals(3L)) {
weFound3 = true;

View File

@@ -13,13 +13,12 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.2.0.RELEASE</version>
<version>1.2.1.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
<project.root>${basedir}/..</project.root>
<dist.id>spring-data-mongodb</dist.id>
<dist.key>SDMONGO</dist.key>
</properties>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.2.0.RELEASE</version>
<version>1.2.1.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -1,11 +1,11 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2013 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
* 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,
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.log4j;
import java.net.UnknownHostException;
@@ -21,188 +20,207 @@ import java.util.Arrays;
import java.util.Calendar;
import java.util.Map;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.WriteConcern;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.MDC;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.WriteConcern;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
* Log4j appender writing log entries into a MongoDB instance.
*
* @author Jon Brisbin
* @author Oliver Gierke
*/
public class MongoLog4jAppender extends AppenderSkeleton {
public static final String LEVEL = "level";
public static final String NAME = "name";
public static final String APP_ID = "applicationId";
public static final String TIMESTAMP = "timestamp";
public static final String PROPERTIES = "properties";
public static final String TRACEBACK = "traceback";
public static final String MESSAGE = "message";
public static final String YEAR = "year";
public static final String MONTH = "month";
public static final String DAY = "day";
public static final String HOUR = "hour";
public static final String LEVEL = "level";
public static final String NAME = "name";
public static final String APP_ID = "applicationId";
public static final String TIMESTAMP = "timestamp";
public static final String PROPERTIES = "properties";
public static final String TRACEBACK = "traceback";
public static final String MESSAGE = "message";
public static final String YEAR = "year";
public static final String MONTH = "month";
public static final String DAY = "day";
public static final String HOUR = "hour";
protected String host = "localhost";
protected int port = 27017;
protected String database = "logs";
protected String collectionPattern = "%c";
protected PatternLayout collectionLayout = new PatternLayout(collectionPattern);
protected String applicationId = System.getProperty("APPLICATION_ID", null);
protected WriteConcern warnOrHigherWriteConcern = WriteConcern.SAFE;
protected WriteConcern infoOrLowerWriteConcern = WriteConcern.NORMAL;
protected Mongo mongo;
protected DB db;
protected String host = "localhost";
protected int port = 27017;
protected String database = "logs";
protected String collectionPattern = "%c";
protected PatternLayout collectionLayout = new PatternLayout(collectionPattern);
protected String applicationId = System.getProperty("APPLICATION_ID", null);
protected WriteConcern warnOrHigherWriteConcern = WriteConcern.SAFE;
protected WriteConcern infoOrLowerWriteConcern = WriteConcern.NORMAL;
protected Mongo mongo;
protected DB db;
public MongoLog4jAppender() {
}
public MongoLog4jAppender() {
}
public MongoLog4jAppender(boolean isActive) {
super(isActive);
}
public MongoLog4jAppender(boolean isActive) {
super(isActive);
}
public String getHost() {
return host;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public void setPort(int port) {
this.port = port;
}
public String getDatabase() {
return database;
}
public String getDatabase() {
return database;
}
public void setDatabase(String database) {
this.database = database;
}
public void setDatabase(String database) {
this.database = database;
}
public String getCollectionPattern() {
return collectionPattern;
}
public String getCollectionPattern() {
return collectionPattern;
}
public void setCollectionPattern(String collectionPattern) {
this.collectionPattern = collectionPattern;
this.collectionLayout = new PatternLayout(collectionPattern);
}
public void setCollectionPattern(String collectionPattern) {
this.collectionPattern = collectionPattern;
this.collectionLayout = new PatternLayout(collectionPattern);
}
public String getApplicationId() {
return applicationId;
}
public String getApplicationId() {
return applicationId;
}
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
public void setWarnOrHigherWriteConcern(String wc) {
this.warnOrHigherWriteConcern = WriteConcern.valueOf(wc);
}
public void setWarnOrHigherWriteConcern(String wc) {
this.warnOrHigherWriteConcern = WriteConcern.valueOf(wc);
}
public String getWarnOrHigherWriteConcern() {
return warnOrHigherWriteConcern.toString();
}
public String getWarnOrHigherWriteConcern() {
return warnOrHigherWriteConcern.toString();
}
public String getInfoOrLowerWriteConcern() {
return infoOrLowerWriteConcern.toString();
}
public String getInfoOrLowerWriteConcern() {
return infoOrLowerWriteConcern.toString();
}
public void setInfoOrLowerWriteConcern(String wc) {
this.infoOrLowerWriteConcern = WriteConcern.valueOf(wc);
}
public void setInfoOrLowerWriteConcern(String wc) {
this.infoOrLowerWriteConcern = WriteConcern.valueOf(wc);
}
protected void connectToMongo() throws UnknownHostException {
this.mongo = new Mongo(host, port);
this.db = mongo.getDB(database);
}
protected void connectToMongo() throws UnknownHostException {
this.mongo = new Mongo(host, port);
this.db = mongo.getDB(database);
}
@SuppressWarnings({"unchecked"})
@Override
protected void append(final LoggingEvent event) {
if (null == db) {
try {
connectToMongo();
} catch (UnknownHostException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
/*
* (non-Javadoc)
* @see org.apache.log4j.AppenderSkeleton#append(org.apache.log4j.spi.LoggingEvent)
*/
@Override
@SuppressWarnings({ "unchecked" })
protected void append(final LoggingEvent event) {
if (null == db) {
try {
connectToMongo();
} catch (UnknownHostException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
BasicDBObject dbo = new BasicDBObject();
if (null != applicationId) {
dbo.put(APP_ID, applicationId);
MDC.put(APP_ID, applicationId);
}
dbo.put(NAME, event.getLogger().getName());
dbo.put(LEVEL, event.getLevel().toString());
Calendar tstamp = Calendar.getInstance();
tstamp.setTimeInMillis(event.getTimeStamp());
dbo.put(TIMESTAMP, tstamp.getTime());
BasicDBObject dbo = new BasicDBObject();
if (null != applicationId) {
dbo.put(APP_ID, applicationId);
MDC.put(APP_ID, applicationId);
}
dbo.put(NAME, event.getLogger().getName());
dbo.put(LEVEL, event.getLevel().toString());
Calendar tstamp = Calendar.getInstance();
tstamp.setTimeInMillis(event.getTimeStamp());
dbo.put(TIMESTAMP, tstamp.getTime());
// Copy properties into document
Map<Object, Object> props = event.getProperties();
if (null != props && props.size() > 0) {
BasicDBObject propsDbo = new BasicDBObject();
for (Map.Entry<Object, Object> entry : props.entrySet()) {
propsDbo.put(entry.getKey().toString(), entry.getValue().toString());
}
dbo.put(PROPERTIES, propsDbo);
}
// Copy properties into document
Map<Object, Object> props = event.getProperties();
if (null != props && props.size() > 0) {
BasicDBObject propsDbo = new BasicDBObject();
for (Map.Entry<Object, Object> entry : props.entrySet()) {
propsDbo.put(entry.getKey().toString(), entry.getValue().toString());
}
dbo.put(PROPERTIES, propsDbo);
}
// Copy traceback info (if there is any) into the document
String[] traceback = event.getThrowableStrRep();
if (null != traceback && traceback.length > 0) {
BasicDBList tbDbo = new BasicDBList();
tbDbo.addAll(Arrays.asList(traceback));
dbo.put(TRACEBACK, tbDbo);
}
// Copy traceback info (if there is any) into the document
String[] traceback = event.getThrowableStrRep();
if (null != traceback && traceback.length > 0) {
BasicDBList tbDbo = new BasicDBList();
tbDbo.addAll(Arrays.asList(traceback));
dbo.put(TRACEBACK, tbDbo);
}
// Put the rendered message into the document
dbo.put(MESSAGE, event.getRenderedMessage());
// Put the rendered message into the document
dbo.put(MESSAGE, event.getRenderedMessage());
// Insert the document
Calendar now = Calendar.getInstance();
MDC.put(YEAR, now.get(Calendar.YEAR));
MDC.put(MONTH, String.format("%1$02d", now.get(Calendar.MONTH) + 1));
MDC.put(DAY, String.format("%1$02d", now.get(Calendar.DAY_OF_MONTH)));
MDC.put(HOUR, String.format("%1$02d", now.get(Calendar.HOUR_OF_DAY)));
// Insert the document
Calendar now = Calendar.getInstance();
MDC.put(YEAR, now.get(Calendar.YEAR));
MDC.put(MONTH, String.format("%1$02d", now.get(Calendar.MONTH) + 1));
MDC.put(DAY, String.format("%1$02d", now.get(Calendar.DAY_OF_MONTH)));
MDC.put(HOUR, String.format("%1$02d", now.get(Calendar.HOUR_OF_DAY)));
String coll = collectionLayout.format(event);
String coll = collectionLayout.format(event);
MDC.remove(YEAR);
MDC.remove(MONTH);
MDC.remove(DAY);
MDC.remove(HOUR);
if (null != applicationId) {
MDC.remove(APP_ID);
}
MDC.remove(YEAR);
MDC.remove(MONTH);
MDC.remove(DAY);
MDC.remove(HOUR);
if (null != applicationId) {
MDC.remove(APP_ID);
}
WriteConcern wc;
if (event.getLevel().isGreaterOrEqual(Level.WARN)) {
wc = warnOrHigherWriteConcern;
} else {
wc = infoOrLowerWriteConcern;
}
db.getCollection(coll).insert(dbo, wc);
}
WriteConcern wc;
if (event.getLevel().isGreaterOrEqual(Level.WARN)) {
wc = warnOrHigherWriteConcern;
} else {
wc = infoOrLowerWriteConcern;
}
db.getCollection(coll).insert(dbo, wc);
}
public void close() {
mongo.close();
}
/*
* (non-Javadoc)
* @see org.apache.log4j.AppenderSkeleton#close()
*/
public void close() {
public boolean requiresLayout() {
return true;
}
if (mongo != null) {
mongo.close();
}
}
/*
* (non-Javadoc)
* @see org.apache.log4j.AppenderSkeleton#requiresLayout()
*/
public boolean requiresLayout() {
return true;
}
}

View File

@@ -35,41 +35,41 @@ import org.junit.Test;
*/
public class AppenderTest {
private static final String NAME = AppenderTest.class.getName();
private Logger log = Logger.getLogger(NAME);
private Mongo mongo;
private DB db;
private String collection;
private static final String NAME = AppenderTest.class.getName();
private Logger log = Logger.getLogger(NAME);
private Mongo mongo;
private DB db;
private String collection;
@Before
public void setup() {
try {
mongo = new Mongo("localhost", 27017);
db = mongo.getDB("logs");
Calendar now = Calendar.getInstance();
collection = String.valueOf(now.get(Calendar.YEAR)) + String.format("%1$02d", now.get(Calendar.MONTH) + 1);
db.getCollection(collection).drop();
} catch (UnknownHostException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@Before
public void setup() {
try {
mongo = new Mongo("localhost", 27017);
db = mongo.getDB("logs");
Calendar now = Calendar.getInstance();
collection = String.valueOf(now.get(Calendar.YEAR)) + String.format("%1$02d", now.get(Calendar.MONTH) + 1);
db.getCollection(collection).drop();
} catch (UnknownHostException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@Test
public void testLogging() {
log.debug("DEBUG message");
log.info("INFO message");
log.warn("WARN message");
log.error("ERROR message");
@Test
public void testLogging() {
log.debug("DEBUG message");
log.info("INFO message");
log.warn("WARN message");
log.error("ERROR message");
DBCursor msgs = db.getCollection(collection).find();
assertThat(msgs.count(), is(4));
DBCursor msgs = db.getCollection(collection).find();
assertThat(msgs.count(), is(4));
}
}
@Test
public void testProperties() {
MDC.put("property", "one");
log.debug("DEBUG message");
}
@Test
public void testProperties() {
MDC.put("property", "one");
log.debug("DEBUG message");
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2013 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.mongodb.log4j;
import org.junit.Test;
/**
* Unit tests for {@link MongoLog4jAppender}.
*
* @author Oliver Gierke
*/
public class MongoLog4jAppenderUnitTests {
/**
* @see DATAMONGO-641
*/
@Test
public void closesWithoutMongoInstancePresent() {
new MongoLog4jAppender().close();
}
}

View File

@@ -11,7 +11,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.2.0.RELEASE</version>
<version>1.2.1.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2013 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.mongodb;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.mongodb.core.MongoActionOperation;
import org.springframework.util.Assert;
import com.mongodb.WriteResult;
/**
* Mongo-specific {@link DataIntegrityViolationException}.
*
* @author Oliver Gierke
*/
public class MongoDataIntegrityViolationException extends DataIntegrityViolationException {
private static final long serialVersionUID = -186980521176764046L;
private final WriteResult writeResult;
private final MongoActionOperation actionOperation;
/**
* Creates a new {@link MongoDataIntegrityViolationException} using the given message and {@link WriteResult}.
*
* @param message the exception message
* @param writeResult the {@link WriteResult} that causes the exception, must not be {@literal null}.
* @param actionOperation the {@link MongoActionOperation} that caused the exception, must not be {@literal null}.
*/
public MongoDataIntegrityViolationException(String message, WriteResult writeResult,
MongoActionOperation actionOperation) {
super(message);
Assert.notNull(writeResult, "WriteResult must not be null!");
Assert.notNull(actionOperation, "MongoActionOperation must not be null!");
this.writeResult = writeResult;
this.actionOperation = actionOperation;
}
/**
* Returns the {@link WriteResult} that caused the exception.
*
* @return the writeResult
*/
public WriteResult getWriteResult() {
return writeResult;
}
/**
* Returns the {@link MongoActionOperation} in which the current exception occured.
*
* @return the actionOperation
*/
public MongoActionOperation getActionOperation() {
return actionOperation;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2012 the original author or authors.
* Copyright 2010-2013 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.
@@ -44,7 +44,6 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.authentication.UserCredentials;
@@ -53,6 +52,7 @@ import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.BeanWrapper;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.MongoDataIntegrityViolationException;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
@@ -666,8 +666,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(entity.getClass());
if (mongoPersistentEntity == null || mongoPersistentEntity.hasVersionProperty()) {
BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(entity, null);
if (mongoPersistentEntity != null && mongoPersistentEntity.hasVersionProperty()) {
BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(entity,
this.mongoConverter.getConversionService());
wrapper.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
}
}
@@ -770,8 +771,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
// Fresh instance -> initialize version property
if (version == null) {
beanWrapper.setProperty(versionProperty, 0);
doSave(collectionName, objectToSave, this.mongoConverter);
doInsert(collectionName, objectToSave, this.mongoConverter);
} else {
assertUpdateableIdIfNotSet(objectToSave);
@@ -792,7 +792,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbObject));
Update update = Update.fromDBObject(dbObject, ID_FIELD);
updateFirst(query, update, objectToSave.getClass());
doUpdate(collectionName, query, update, objectToSave.getClass(), false, false);
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbObject));
}
}
@@ -941,7 +941,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
if (entity != null && entity.hasVersionProperty() && !multi) {
if (writeResult.getN() == 0) {
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
+ updateObj.toMap().toString());
+ updateObj.toMap().toString() + " to collection " + collectionName);
}
}
@@ -981,11 +981,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
Assert.notNull(object);
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(object.getClass());
Class<?> objectType = object.getClass();
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(objectType);
MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty();
if (idProp == null) {
throw new MappingException("No id property found for object of type " + entity.getType().getName());
throw new MappingException("No id property found for object of type " + objectType);
}
ConversionService service = mongoConverter.getConversionService();
@@ -1647,7 +1648,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
}
if (writeResultChecking == WriteResultChecking.EXCEPTION) {
throw new DataIntegrityViolationException(message);
throw new MongoDataIntegrityViolationException(message, writeResult, operation);
} else {
LOGGER.error(message);
return;

View File

@@ -832,7 +832,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return conversionService.convert(obj, target);
}
if (null != obj && conversions.isSimpleType(obj.getClass())) {
if (conversions.isSimpleType(obj.getClass())) {
// Doesn't need conversion
return getPotentiallyConvertedSimpleWrite(obj);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 the original author or authors.
* Copyright 2011-2013 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.
@@ -214,7 +214,11 @@ public class QueryMapper {
*/
private String determineKey(String key, MongoPersistentEntity<?> entity) {
if (entity == null && DEFAULT_ID_NAMES.contains(key)) {
if (entity == null) {
return key;
}
if (!entity.hasIdProperty() && DEFAULT_ID_NAMES.contains(key)) {
return "_id";
}

View File

@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.AbstractMap;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
@@ -51,7 +52,7 @@ public class MongoMappingContext extends AbstractMappingContext<BasicMongoPersis
*/
@Override
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
return !MongoSimpleTypes.HOLDER.isSimpleType(type.getType());
return !MongoSimpleTypes.HOLDER.isSimpleType(type.getType()) && !AbstractMap.class.isAssignableFrom(type.getType());
}
/*

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2012 the original author or authors.
* Copyright 2010-2013 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.
@@ -46,22 +46,33 @@ public class Query {
private String hint;
/**
* Static factory method to create a Query using the provided criteria
* Static factory method to create a {@link Query} using the provided {@link Criteria}.
*
* @param critera
* @param criteria must not be {@literal null}.
* @return
*/
public static Query query(Criteria critera) {
return new Query(critera);
public static Query query(Criteria criteria) {
return new Query(criteria);
}
public Query() {
}
/**
* Creates a new {@link Query} using the given {@link Criteria}.
*
* @param criteria must not be {@literal null}.
*/
public Query(Criteria criteria) {
addCriteria(criteria);
}
/**
* Adds the given {@link Criteria} to the current {@link Query}.
*
* @param criteria must not be {@literal null}.
* @return
*/
public Query addCriteria(Criteria criteria) {
CriteriaDefinition existing = this.criteria.get(criteria.getKey());
String key = criteria.getKey();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2012 the original author or authors.
* Copyright 2010-2013 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.
@@ -52,7 +52,10 @@ public class Update {
/**
* Creates an {@link Update} instance from the given {@link DBObject}. Allows to explicitly exlude fields from making
* it into the created {@link Update} object.
* it into the created {@link Update} object. Note, that this will set attributes directly and <em>not</em> use
* {@literal $set}. This means fields not given in the {@link DBObject} will be nulled when executing the update. To
* create an only-updating {@link Update} instance of a {@link DBObject}, call {@link #set(String, Object)} for each
* value in it.
*
* @param object the source {@link DBObject} to create the update from.
* @param exclude the fields to exclude.
@@ -69,7 +72,7 @@ public class Update {
continue;
}
update.set(key, object.get(key));
update.modifierOps.put(key, object.get(key));
}
return update;
@@ -160,7 +163,7 @@ public class Update {
* @return
*/
public Update pop(String key, Position pos) {
addMultiFieldOperation("$pop", key, (pos == Position.FIRST ? -1 : 1));
addMultiFieldOperation("$pop", key, pos == Position.FIRST ? -1 : 1);
return this;
}

View File

@@ -264,7 +264,13 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
private boolean isListOfGeoResult() {
TypeInformation<?> returnType = method.getReturnType();
return returnType.getType().equals(List.class) && GeoResult.class.equals(returnType.getComponentType());
if (!returnType.getType().equals(List.class)) {
return false;
}
TypeInformation<?> componentType = returnType.getComponentType();
return componentType == null ? false : GeoResult.class.equals(componentType.getType());
}
}
}

View File

@@ -11,8 +11,7 @@
<xsd:import namespace="http://www.springframework.org/schema/beans" />
<xsd:import namespace="http://www.springframework.org/schema/tool" />
<xsd:import namespace="http://www.springframework.org/schema/context"
schemaLocation="http://www.springframework.org/schema/context/spring-context.xsd" />
<xsd:import namespace="http://www.springframework.org/schema/context" />
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository-1.0.xsd" />

View File

@@ -11,8 +11,7 @@
<xsd:import namespace="http://www.springframework.org/schema/beans" />
<xsd:import namespace="http://www.springframework.org/schema/tool" />
<xsd:import namespace="http://www.springframework.org/schema/context"
schemaLocation="http://www.springframework.org/schema/context/spring-context.xsd" />
<xsd:import namespace="http://www.springframework.org/schema/context" />
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository.xsd" />

View File

@@ -11,8 +11,7 @@
<xsd:import namespace="http://www.springframework.org/schema/beans" />
<xsd:import namespace="http://www.springframework.org/schema/tool" />
<xsd:import namespace="http://www.springframework.org/schema/context"
schemaLocation="http://www.springframework.org/schema/context/spring-context.xsd" />
<xsd:import namespace="http://www.springframework.org/schema/context" />
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository.xsd" />
@@ -36,7 +35,7 @@ Defines a MongoDbFactory for connecting to a specific database
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:ID" use="optional">
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the mongo definition (by default "mongoDbFactory").]]></xsd:documentation>
@@ -157,7 +156,7 @@ The Mongo URI string.]]></xsd:documentation>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:ID" use="optional">
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the MappingMongoConverter instance (by default "mappingConverter").]]></xsd:documentation>
@@ -336,7 +335,7 @@ The Mongo driver options
<!-- MLP
<xsd:attributeGroup ref="writeConcern" />
-->
<xsd:attribute name="id" type="xsd:ID" use="optional">
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the mongo definition (by default "mongo").]]></xsd:documentation>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 the original author or authors.
* Copyright 2011-2013 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.
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;
import static org.springframework.data.mongodb.core.query.Update.*;
@@ -30,6 +31,7 @@ import java.util.List;
import java.util.Map;
import org.bson.types.ObjectId;
import org.hamcrest.CoreMatchers;
import org.joda.time.DateTime;
import org.junit.After;
import org.junit.Assert;
@@ -42,12 +44,15 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.annotation.Version;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
import org.springframework.data.mongodb.MongoDataIntegrityViolationException;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
@@ -146,6 +151,7 @@ public class MongoTemplateTests {
template.dropCollection(Sample.class);
template.dropCollection(MyPerson.class);
template.dropCollection("collection");
template.dropCollection("personX");
}
@Test
@@ -272,7 +278,8 @@ public class MongoTemplateTests {
} catch (DataIntegrityViolationException e) {
assertThat(
e.getMessage(),
startsWith("Insert list failed: E11000 duplicate key error index: database.person.$_id_ dup key: { : ObjectId"));
CoreMatchers
.startsWith("Insert list failed: E11000 duplicate key error index: database.person.$_id_ dup key: { : ObjectId"));
}
}
@@ -949,6 +956,7 @@ public class MongoTemplateTests {
}
@Test
@SuppressWarnings("deprecation")
public void testUsingReadPreference() throws Exception {
this.template.execute("readPref", new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
@@ -1318,6 +1326,18 @@ public class MongoTemplateTests {
template.save(person);
}
/**
* @see DATAMONGO-617
*/
@Test
public void doesNotFailOnVersionInitForUnversionedEntity() {
DBObject dbObject = new BasicDBObject();
dbObject.put("firstName", "Oliver");
template.insert(dbObject, template.determineCollectionName(PersonWithVersionPropertyOfTypeInteger.class));
}
/**
* @see DATAMONGO-539
*/
@@ -1455,6 +1475,128 @@ public class MongoTemplateTests {
assertThat(template.find(null, PersonWithIdPropertyOfTypeObjectId.class), is(result));
}
/**
* @see DATAMONGO-620
*/
@Test
public void versionsObjectIntoDedicatedCollection() {
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.firstName = "Dave";
template.save(person, "personX");
assertThat(person.version, is(0));
template.save(person, "personX");
assertThat(person.version, is(1));
}
/**
* @see DATAMONGO-621
*/
@Test
public void correctlySetsLongVersionProperty() {
PersonWithVersionPropertyOfTypeLong person = new PersonWithVersionPropertyOfTypeLong();
person.firstName = "Dave";
template.save(person);
assertThat(person.version, is(0L));
}
/**
* @see DATAMONGO-622
*/
@Test(expected = DuplicateKeyException.class)
public void preventsDuplicateInsert() {
template.setWriteConcern(WriteConcern.SAFE);
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.firstName = "Dave";
template.save(person);
assertThat(person.version, is(0));
person.version = null;
template.save(person);
}
/**
* @see DATAMONGO-629
*/
@Test
public void countAndFindWithoutTypeInformation() {
Person person = new Person();
template.save(person);
Query query = query(where("_id").is(person.getId()));
String collectionName = template.getCollectionName(Person.class);
assertThat(template.find(query, HashMap.class, collectionName), hasSize(1));
assertThat(template.count(query, collectionName), is(1L));
}
/**
* @see DATAMONGO-571
*/
@Test
public void nullsPropertiesForVersionObjectUpdates() {
VersionedPerson person = new VersionedPerson();
person.firstname = "Dave";
person.lastname = "Matthews";
template.save(person);
assertThat(person.id, is(notNullValue()));
person.lastname = null;
template.save(person);
person = template.findOne(query(where("id").is(person.id)), VersionedPerson.class);
assertThat(person.lastname, is(nullValue()));
}
/**
* @see DATAMONGO-571
*/
@Test
public void nullsValuesForUpdatesOfUnversionedEntity() {
Person person = new Person("Dave");
template.save(person);
person.setFirstName(null);
template.save(person);
person = template.findOne(query(where("id").is(person.getId())), Person.class);
assertThat(person.getFirstName(), is(nullValue()));
}
/**
* @see DATAMONGO-651
*/
@Test
public void throwsMongoSpecificExceptionForDataIntegrityViolations() {
WriteResult result = mock(WriteResult.class);
when(result.getError()).thenReturn("ERROR");
MongoActionOperation operation = MongoActionOperation.INSERT;
MongoTemplate mongoTemplate = new MongoTemplate(factory);
mongoTemplate.setWriteResultChecking(WriteResultChecking.EXCEPTION);
try {
mongoTemplate.handleAnyWriteResultErrors(result, null, operation);
fail("Expected MonogoDataIntegrityViolationException!");
} catch (MongoDataIntegrityViolationException o_O) {
assertThat(o_O.getActionOperation(), is(operation));
assertThat(o_O.getWriteResult(), is(result));
}
}
static class MyId {
String first;
@@ -1524,4 +1666,11 @@ public class MongoTemplateTests {
String state;
String city;
}
static class VersionedPerson {
@Version
Long version;
String id, firstname, lastname;
}
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.mongodb.core;
import org.springframework.data.mongodb.core.mapping.Version;
import org.springframework.data.annotation.Version;
public class PersonWithVersionPropertyOfTypeInteger {

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import org.springframework.data.annotation.Version;
public class PersonWithVersionPropertyOfTypeLong {
String id;
String firstName;
int age;
@Version
Long version;
@Override
public String toString() {
return "PersonWithVersionPropertyOfTypeInteger [id=" + id + ", firstName=" + firstName + ", age=" + age
+ ", version=" + version + "]";
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 the original author or authors.
* Copyright 2011-2013 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.
@@ -347,6 +347,22 @@ public class QueryMapperUnitTests {
assertThat(object.get("reference"), is(nullValue()));
}
/**
* @see DATAMONGO-629
*/
@Test
public void doesNotMapIdIfNoEntityMetadataAvailable() {
String id = new ObjectId().toString();
Query query = query(where("id").is(id));
DBObject object = mapper.getMappedObject(query.getQueryObject(), null);
assertThat(object.containsField("id"), is(true));
assertThat(object.get("id"), is((Object) id));
assertThat(object.containsField("_id"), is(false));
}
class IdWrapper {
Object id;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011-2013 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.mapping;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.lang.reflect.Field;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.Map;
@@ -80,6 +80,16 @@ public class MongoMappingContextUnitTests {
assertThat(ReflectionUtils.getField(field, context), is(notNullValue()));
}
/**
* @see DATAMONGO-638
*/
@Test
public void doesNotCreatePersistentEntityForAbstractMap() {
MongoMappingContext context = new MongoMappingContext();
assertThat(context.getPersistentEntity(AbstractMap.class), is(nullValue()));
}
class ClassWithMultipleIdProperties {
@Id

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -1,6 +1,36 @@
Spring Data MongoDB Changelog
=============================
Changes in version 1.2.1.GA (2013-04-17)
----------------------------------------
** Bug
* [DATAMONGO-571] - Spring Data for MongoDb doesn't save null values when @Version is added to domain class
* [DATAMONGO-612] - Fix PDF reference documentation name
* [DATAMONGO-613] - Images missing from reference documentation
* [DATAMONGO-617] - NullPointerException in MongoTemplate.initializeVersionProperty(…)
* [DATAMONGO-620] - MongoTemplate.doSaveVersioned(…) does not consider collection handed into the method
* [DATAMONGO-621] - MongoTemplate.initializeVersionProperty(…) does not use ConversionService
* [DATAMONGO-622] - An unversioned object should be created using insert(…) instead of save.
* [DATAMONGO-629] - Different results when using count and find with the same criteria with 'id' field
* [DATAMONGO-638] - MappingContext should not create PersistentEntity instances for native maps
* [DATAMONGO-640] - MongoLog4jAppender suffers from potential NullPointerException when closing Mongo instance
* [DATAMONGO-641] - MongoLog4jAppender suffers from potential NullPointerException when closing Mongo instance
* [DATAMONGO-642] - MongoChangeSetPersister does not use mapped collection name
* [DATAMONGO-646] - Can't insert DBObjects through MongoTemplate
* [DATAMONGO-648] - ID attributes in namespace shouldn't be XSD IDs
** Improvement
* [DATAMONGO-594] - cross-store=> Define document name using annotation
* [DATAMONGO-632] - Polish namespace XSD to avoid errors in STS
* [DATAMONGO-635] - Fix some Sonar warnings
* [DATAMONGO-637] - Typo in Query.query(…)
* [DATAMONGO-651] - WriteResult not available from thrown Exception
* [DATAMONGO-656] - Potential NullPointerException when debugging in MongoTemplate
** Task
* [DATAMONGO-597] - Website is severely out-of-date
* [DATAMONGO-654] - Release 1.2.1
Changes in version 1.2.0.GA (2013-02-08)
----------------------------------------
** Bug

View File

@@ -1,4 +1,4 @@
Spring Data Document 1.1.2
Spring Data Document 1.2.1
Copyright (c) [2010-2013] SpringSource, a division of VMware, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").

View File

@@ -1,4 +1,4 @@
SPRING DATA MongoDB 1.0.0.M5
SPRING DATA MongoDB 1.2.1.GA
----------------------------
Spring Data MongoDB is released under the terms of the Apache Software License Version 2.0 (see license.txt).