Wednesday, May 23, 2012

MongoDB "norepl" Exception

I was using MongoDB 2.0.4 (mongodb-win32-x86_64-2.0.4) with spring-data-mongodb-1.0.1-RELEASE and spring-framework-3.1.1-RELEASE to do a data insert.

The insert method was as follows:
 public static final String FOO_COLLECTION = "foos";

 @Autowired private MongoTemplate mongoTemplate;

 public void add(Foo foo) {
  mongoTemplate.save(foo, FOO_COLLECTION);
 }
It's supposed to be simple and yet I got the following error:
org.springframework.data.mongodb.UncategorizedMongoDbException: norepl; nested exception is com.mongodb.MongoException: norepl
 at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:70)
 at org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException(MongoTemplate.java:1538)
 at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:370)
 at org.springframework.data.mongodb.core.MongoTemplate.saveDBObject(MongoTemplate.java:784)
 at org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:720)
 at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:707)
 ... ...
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
 at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
 at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
 at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
 at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
 at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
 at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
 at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
 at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
 at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
 at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
 at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
 at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
 at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
 at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
 at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
 at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
 at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
 at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
 at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: com.mongodb.MongoException: norepl
 at com.mongodb.CommandResult.getException(CommandResult.java:87)
 at com.mongodb.CommandResult.throwOnError(CommandResult.java:121)
 at com.mongodb.DBTCPConnector._checkWriteError(DBTCPConnector.java:131)
 at com.mongodb.DBTCPConnector.say(DBTCPConnector.java:155)
 at com.mongodb.DBTCPConnector.say(DBTCPConnector.java:138)
 at com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:261)
 at com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:211)
 at com.mongodb.DBCollection.insert(DBCollection.java:57)
 at com.mongodb.DBCollection.insert(DBCollection.java:87)
 at com.mongodb.DBCollection.save(DBCollection.java:728)
 at org.springframework.data.mongodb.core.MongoTemplate$11.doInCollection(MongoTemplate.java:792)
 at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:368)
 ... 33 more
The data got inserted into MongoDB, but the Exception still got thrown.

I look around and eventually found out that the way I define my "WriteConcern" in the mongoTemplate bean definition in applicationContext.xml caused the Exception.  It seems that anything other than the default will cause the Exception similar to above.

Here's how my mongoTemplate originally defined:
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
        <constructor-arg name="mongoConverter" ref="converter" />
        <property name="writeResultChecking" value="EXCEPTION" />
        <property name="writeConcern" value="NORMAL" />
    </bean>
Here's the changes that "fixed" the Exception:
<beans ...
xmlns:util="http://www.springframework.org/schema/util"
 ...
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
 ... >
     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
        <constructor-arg name="mongoConverter" ref="converter" />
        <property name="writeResultChecking" value="EXCEPTION" />
        <property name="writeConcern">
          <util:constant static-field="com.mongodb.WriteConcern.NORMAL" />
        </property>
    </bean>
Apparently, changing:

<property name="writeConcern" value="SAFE">

to

<property name="writeConcern">
    <util:constant static-field="com.mongodb.WriteConcern.SAFE"></util:constant>
<property>

Seems to resolve the issue.