SerializeJSON with lowercase keys and override JSONConverter.java

So, reporting back as promised…
In the end I went with a modified version of the code @andreas suggested. See below. Thank you! :slight_smile:

  myJsonConverter = new MyJsonConverter();
  j1 = MyJsonConverter.serializeJsonWithLowerKeyNames( myNestedStruct );
  j2 = MyJsonConverter.serializeJsonWithLowerKeyNames( myArrayOfNestedStructs );

In the CF10 legacy code, I am using Taffy and the serialization is done in just one place, so having this there simplifies the process as I can catch all requests for JSON in the one place. That was preferable to manually changing all the structs at origin because there were many and there was a good chance of missing some, given the way the data objects were being constructed (and it is just me - no team :frowning: )

In terms of overhead, unless the object being serialized is very large, the speed is acceptable:

Average test results comparing the native Lucee SerializeJSON and the convert-to-lowercase function:
17 small records: 985 bytes of json:
native: 85 ms
lowercased: 102 ms

13 large, nested records, 34 Kb of json
native: 5268 ms
lowercased: 5340 ms

3,450 large nested records, 1.4 Mb of json Yes - big!
native: 6630 ms
lowercased: 13320 ms

I also made a language proposal here: Topic 10636

/**
  CFC to call the Lucee serializeJSON() after converting all the keys
  in the passed in data object to lowercase.

  eg:
  myJsonConverter = new MyJsonConverter();
  j1 = MyJsonConverter.serializeJsonWithLowerKeyNames( myNestedStruct );
  j2 = MyJsonConverter.serializeJsonWithLowerKeyNames( myArrayOfNestedStructs );

  See: https://lucee.daemonite.io/t/serializejson-with-lowercase-keys-and-override-jsonconverter-java/10619
  for the rationale and
  credit to @andreas for the initial code in that post. :-)
*/
component displayname="MyJsonConverter.cfc" output="false" {

    public struct function init(){

        return this;

    }

    /**
      PUBLIC
      Uses the Lucee native serializeJSON() to serialize the object to JSON,
      AFTER converting all keys to lowercase.
    */
    public string function serializeJsonWithLowerKeyNames ( any dataobject required ){
        if (isArray( dataobject )) {
          // We might start with an array at the top level
          return "[#serializeJSON( lowerStructKeyNames( arguments.dataobject[1]) )#]";
        } else {
          // Or a struct, or simple value
          return serializeJSON( lowerStructKeyNames( arguments.dataobject ) );
        }
    }

    /**
      PRIVATE
      If the dataobject is a struct or array,
      for all keys in that object convert them to lower case
      and return a new object with those lower case keys.
      If the dataobject is a simple value, just return it unchanged.
    */
    private any function lowerStructKeyNames ( any dataobject required ){
        if (isSimpleValue(dataobject)) {

          // Just return the simple value unchanged
          local.result = dataobject;

        } else {
          local.result=[:];

          arguments.dataobject.each( function( key, value ) {
              if( isStruct( arguments.value )){

                  // Structs recurse ...
                  result.append( { "#lcase(arguments.key)#": lowerStructKeyNames ( arguments.value ) } );

              } else if (isArray( arguments.value )){
                  // Array, iterate and recurse ...
                  var arr = [];
                  arguments.value.each( function (item) {
                    arr.append( lowerStructKeyNames ( item ) );
                  });

                  result.append( { "#lcase(arguments.key)#": #arr# } );
              } else {
                  // Everything else, just transform
                  result.append( { "#lcase(arguments.key)#": arguments.value } );
              }
          });
        }

        return local.result;
    }
}

1 Like