%FromJSON() failing with content larger than 32kb

We have a business service that extends Ens.BusinessService and uses  EnsLib.File.InboundAdapter.

This service polls for json files in a folder.

Method signature is like this:

Method OnProcessInput(pInput As %FileCharacterStream, pOutput As %RegisteredObject) As %Status

And inside that method it tries to read the content like this:

set tData = pInput.ReadLine(,.tStatus, .tEOL)
if ($$$ISERR(tStatus)) quit
set tJSON = {}.%FromJSON(tData)
 

I added some trace calls before and after lines and noticed it's always that last line that fails if content is larger than 32kb.

Any workaround for this? Or is this wrong way to do it to begin with and something else should be there instead?

Our Ensemble version is 2016.2.1

 

 

 

 

  • 0
  • 0
  • 198
  • 6
  • 1

Answers

The ReadLine() method of %FileCharacterStream defaults to a length of 32K.

Have you tried simply passing the stream object, pInput, as the argument to %FromJSON()?

Wow, that actually works! Thanks so much, Jeffrey!

This isn't originally my code so I don't know why that

set tData pInput.ReadLine(,.tStatus, .tEOL)

part is there and tdata is used as argument instead of pinput but probably for some reason? So even thou I'm happy your suggestion actually works, I'm also worried if that change breaks something else. But on the other hand, it did not on my initial tests anyway. I get exactly the same output with those json files that worked earlier but now also larger files work fine. Hmmm...

The only reason I can think of doing it the way it was done is that there was no expectation by the original author of the code that the JSON object would be larger than 32KB. It's also possible that he/she was unfamiliar with the types of objects that %FromJSON() works with and always assumed it was a simple string ... which is what the ReadLine() method returns.

Here's the documentation for for the %FromJSON() method.

Comments

I'd also recommend to remove or change this line:

if ($$$ISERR(tStatus)) quit

because your method signature has a promise to return a %Status:

Method OnProcessInput(pInput As %FileCharacterStream, pOutput As %RegisteredObject) As %Statu

however above mentioned line quits nothing.

You can rewrite it like this (to return status):

if $$$ISERR(tStatus) quit tStatus

or my personal preference like this using postconditionals:

quit:$$$ISERR(tStatus) tStatus

Well in this exact case you need to remove the line altogether because you no longer get status for ReadLine, but it's just some food for thought.

As @Eduard Lebedyuk pointed out, the method should return a status as indicated by its signature, so at the very minimum you should have a "Return $$$OK" at the end of the method.

That said, %FromJSON() throws an exception when it fails, and the generic error you'll get in the Event Log won't tell you (or your support team) much. You may want to wrap a try/catch around the call to %FromJSON() so that you can return a status that provides a little more insight:

    ...

    Try {
        set tJSON = {}.%FromJSON(pInput)
    } Catch {
        Return $$$ERROR($$$GeneralError,"Badly formed JSON")
    }

...

    Return $$$OK
 }

Exception still can contain some useful info, so:

    #dim tSC As %Status = $$$OK
    ...
    try {
        set tJSON = {}.%FromJSON(pInput)
    } Catch ex {
        do ex.Log()
        set tempSC = $$$ERROR($$$GeneralError,"Badly formed JSON")
        set tSC = $$$ADDSC(tempSC, ex.AsStatus())
    }

    quit tSC