Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at the ColdFusion Centaur And Bolt User Group Tour (Jun. 2009) with: Ben Forta
Ben Nadel at the ColdFusion Centaur And Bolt User Group Tour (Jun. 2009) with: Ben Forta@benforta )

Strange MongoDB Error When Incrementing A Document Property In Lucee CFML 5.2.9.31

By Ben Nadel on
Tags: ColdFusion

Yesterday, I ran into a really strange error when trying to increment a numeric value on an in-memory MongoDB document in Lucee CFML 5.2.9.31. Google didn't really provide any answers; so, I wanted to document the error here and share the work-around that I finally used.

My ColdFusion code was attempting to read-in a MongoDB document that had a numeric property. Then, I was performing some logic around said document before incrementing that numeric property and saving the document back to the MongoDB database.

At first, I used the post-increment operator: ++. This resulted in two different errors, randomly depending on the request:

  • java.lang.IncompatibleClassChangeError - vtable stub

  • java.lang.IncompatibleClassChangeError - Class org.bson.Document does not implement the requested interface lucee.runtime.type.Collection

I have no idea what that first error, "vtable stub", means - I've never seen that one before. Most of the time, the issue manifested as the second error about the Lucee Collection interface. This makes me think the issue has something to do with how this CFML code is being compiled (ie, it's probably not an issue with the Java driver for MongoDB itself); but, that's just a guess on my part.

Eventually, I replaced the ++ post-increment operator with a full re-assignment of the numeric value and that worked. To see this in action, take a look at this minimal reproduction code - it creates a MongoDB document with a numeric count property. Then, it reads that document back into the ColdFusion memory-space and attempts to increment the count using several different expressions:

<cfscript>

	// Create an instance of the MongdDB Java Driver, version 3.9.1.
	mongoDB = createObject( "java", "com.mongodb.MongoClient" )
		.init( "mongo36", 27018 )
	;

	// Get our collection and TRUNCATE it so that our Insert will result in a single
	// document within the collection.
	collection = mongoDB
		.getDatabase( "testing" )
		.getCollection( "values" )
	;
	collection.drop();

	// Insert our test document - notice that the COUNT value is a NUMBER.
	collection.insertOne(
		createObject( "java", "org.bson.Document" ).init({
			count: 1
		})
	);

	// Read the document we just inserted.
	doc = collection
		.find()
		.into( [] )
		.first()
	;

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	// Let's output the read-in document so we can see the data-types.
	dump( doc );
	dump( getMetadata( doc.count ).getName() );
	echo( "<hr />" );

	// First, let's try to use the POST-INCREMENT operator to increase the count.
	try {

		echo( "<p> Trying Post-Increment Operator. </p>" );
		doc.count++;

	} catch ( any error ) {

		dump(
			label = "Post-Increment error",
			var = error,
			hide = "additional,ErrorCode,Extended_Info,ExtendedInfo,StackTrace,TagContext"
		);

	}

	// Second, let's try to use the ADDITION-ASSIGNMENT operator to increase the count. 
	try {

		echo( "<p> Trying Addition-Assignment Operator. </p>" );
		doc.count += 1;

	} catch ( any error ) {

		dump(
			label = "Addition-Assignment error",
			var = error,
			hide = "additional,ErrorCode,Extended_Info,ExtendedInfo,StackTrace,TagContext"
		);

	}

	// Finally, let's try a full re-assignment operator.
	try {

		echo( "<p> Trying Re-Assignment Operator. </p>" );
		doc.count = ( doc.count + 1 );

	} catch ( any error ) {

		dump(
			label = "Re-Assignment error",
			var = error,
			hide = "additional,ErrorCode,Extended_Info,ExtendedInfo,StackTrace,TagContext"
		);

	}

</cfscript>

As you can see, we're using three different approaches when incrementing the count property value:

  • doc.count++
  • doc.count += 1
  • doc.count = ( doc.count + 1 )

The first two throw an error, the third one succeeds:

Various attempts to increment a numeric MongoDB document property in Lucee CFML 5.2.9.31.

To me, these three assignment operations are equivalent. Which makes me think this is just something strange in the way the Lucee CFML code is being compiled to Java Byte code. With that said, I just used the full re-assignment operation and moved on with my ColdFusoin application development. I'm just sharing this here in case anyone else tries to Google for the same problem.



Reader Comments

I just tested this on Lucee CFML 5.3.3.62 and it results in the same error (though, I was using a different MongoDB Java driver - 3.4.2 - which I installed via the Lucee Server admin).

Reply to this Comment

Ben, did you put in a ticket for this? I just had a similar ticket this week related to Lucee not properly being able to do a for in loop over a Java "Set" because it wasn't a Lucee Collection. Micha already fixed it just yesterday. Mongo seems common enough he may be able to make Lucee recognise that Document class as a collection as well.

Reply to this Comment

@Brad,

I have not. Can you point me to how to submit tickets. I've honestly tried to do it a few times, and I never quite figure it out. Is it documented anywhere?

Reply to this Comment

The Lucee ticket tracker is located here:

https://luceeserver.atlassian.net/

They use an on-demand JIRA instance and it's free and quick to sign up for an account.

I would recommend keeping the ticket simple. Explain it will come in handy for anyone using MongoDB and include a very simple reproducible example that shows the error.

Reply to this Comment

In the past, I worked on a project that used Marc Esher's CFMongoDB.

Similar errors occasionally occurred during daily development. The first step in diagnosis was to determine if the java mongo document was being converted to a native Lucee struct via the toCF() function within cfmongodb.core.MongoUtil .

While I'm not sure if this is applicable to your issue, the conversion of native java to CF was generally a huge hair pulling deterrent. :)

Cheers!

Reply to this Comment

@MrV,

Good insight, I am not sure how the data is being converted under the hood. That said, one of the things that I am loving about Lucee CFML is that, because of the native data types and ordered structs, I can actually get much closer to the MongoDB API. For example, being able to create a org.bson.Document document directly from a Lucee Struct, and then being able to pipe it right into an Array with .into([]) is just a game-changer in terms of complexity.

Every day, I'm just loving Lucee CFML more and more.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.