[contentbox 2.1.0.00122] Post service save bug

Hello again all.

I am continuing the work on a custom module and have encountered an issue that I cannot figure out how to troubleshoot. The problem is surely in my code, but the error results and location are baffling me at the moment.

I have a custom content type (extends contentbox.model.content.BaseContent) that I have a related service for (closely mimics the other content types). In my service, I have a saveCustomContentType function, just as the built-in services do. When this function is called, everything works fine, but the moment it exits the function back to the calling function (an event in my handler), it crashes with the error:

The root cause of this exception was: coldfusion.orm.hibernate.HibernateSessionException: The value for property java.lang.String cannot be retrieved from object of type contentID. Expected object type is cbContent.

The exact location line 135 of coldbox.system.aop.MethodInvocation.cfc: return instance.interceptors[ instance.interceptorIndex ].invokeMethod( this.incrementInterceptorIndex() );

This is in the proceed() function, inside the if( instance.interceptorIndex LTE instance.interceptorLen ){ conditional. If I put a try/catch around this line and allow processing to continue, the code continues to run.

Back to where in my code this throws the error. If I abort processing just before the return at the end of my saveCustomContentType function, the error is not thrown. If I put the abort immediately following the exit from my saveCustomContentType function, the error is thrown. Obviously the issue is that some update in the transaction is not correct (like other types, my saveCustomContentType function is transactional). But I’m unsure why:

  1. It’s throwing an error now when earlier in the development process the save did not throw the error (I know, not very helpful)
  2. What interceptor is running via return instance.interceptors[ instance.interceptorIndex ].invokeMethod( this.incrementInterceptorIndex() ); when the error is thrown. There is only one element in the instance.interceptors array, I just don’t know how to figure out where the interceptor is, and what interception point is running? I’ve searched for the ORMPostUpdate interception, but I can’t find anything that intercepts that point.
    I should note that the problem only occurs when I try to publish my custom content. A normal save does not throw any errors.

Like I said, the problem is obviously in my code, I just need help figuring out where the actual error is being thrown so that I can debug it.

Thanks,
John

Code, please. It is hard to decipher any issue with code that you have written without examples to reproduce.

I absolutely agree, but due to contractual restrictions I cannot post the several files that I would need to post. I’m just trying to get a sense of where to look. The best thing I can tell you is to look at the Page model and the PageService. The save function in my service is an exact copy of the savePage() function in PageService, just without the “Update all affected child pages if any on slug updates” portion. My custom content model was copied from the Page model, though I removed all the Page specific properties.

The other change was to make my customContent the parent object for two other custom content models.

I’m making headway at this point, so I will post when I figure out what I did wrong so anyone else making custom content types can avoid the same mistakes.

Thanks.

It sounds like it is running the cbContent save and not your save, when saving.

No, I’ve checked that. It is indeed running my save function.

I’ve changed my customObject’s Service to be like a ContentStore:

saveCustomObject( required any customObject, boolean transactional=true) {

instead of being like a page:

saveCustomObject( required any customObject) transactional {

Making this change alters a bit how the code is run as it directly calls the BaseORMService instead of injecting it.

Processing order (simplified) is:
handlers.customObject.save > model.customObjectService.saveCustomObject > BaseORMService.save > BaseORMService.$transactioned

Within $transactioned, the transactionCommit(); function throws the error (same error as previously thrown). Strangely, if I set the object’s save to not be a transaction, it succeeds!?!?!? This doesn’t work for me, though, as I have child objects that subsequently get saved.

Looking at my customObject, I only have one additional column:

property name=“name”
notnull=“true”
length=“50”
default="";

By only having one, none-relational column, I don’t think this is the issue.

So now I’m looking at the child objects. I have two different types of child objects, we’ll call them customObjectA and customObjectB (both custom objects that extend the BaseContent object in the same way that content store objects do). I want these customObjects to be related to the main parent customObject (we’ll call it’s type customObjectMain - it is the object that is not properly saving). I am setting the FK_parentID in these objects prior to save. The relationships are thus:

  • customObjectMain
  • customObjectA
  • customObjectB
  • customObjectB- customObjectA
  • customObjectB
  • customObjectB
    So the FK_parentID of customObjectA is set to the contentID of a customObjectMain.

FK_parentID of customObjectB is set to the contentID of a customObjectA.

My manually setting these relationships in the children save functions shouldn’t be an issue, but I can’t think of anything else that would be. I mean, why would it succeed when not in a transaction? I am not aware of anything about transactions that would make Hibernate fail where it succeeds otherwise.

One more note: I was previously incorrect about a QuickSave succeeding. The javascript was failing to send the quicksave. I’ve fixed that and it now incurs the same error.

correction, The page method of saving intercepts, not injects.

And another correction: save does not succeed if transactions are off. It just doesn’t throw an error. So it acts like it succeeds, but it doesn’t do anything. Arggg.

For those who have come to this post with similar issues, I finally figured out my error.

In my customContentType’s handler, when I copied Pages as the basis for my custom type I had simply removed the portion of code that sets the parent since I knew my customContentType would never have a parent. Like an idiot, I forgot I needed to lave the “else” portion to make sure I properly cast the null value for ORM.

Handler: pages.cfc

if( rc.parentPage NEQ “null” AND page.getContentID() NEQ rc.parentPage ){
page.setParent( pageService.get( rc.parentPage ) );
// update slug
page.setSlug( page.getParent().getSlug() & “/” & page.getSlug() );
}
// Remove parent
else if( rc.parentPage EQ “null” ){
page.setParent( javaCast(“null”, “”) );
}

Handler: customContentType.cfc

// Null parent

customObject.setParent( javaCast(“null”, “”) );

That’s the proper code. So it was a simple failure to properly prep the value for ORM. Don’t forget you’ll need to properly cast any field you create that relates to another object.

Ugh… so much time wasted.