JsonObject.java

/*
** Module   : JsonObject.java
** Abstract : Implementation of the Progress.Json.Objectmodel.JsonObject builtin class.
**
** Copyright (c) 2018-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
** 001 OM  20181218 First version.
** 002 GES 20190308 Added a basic implementation.
** 003 CA  20190423 Added LegacyResource annotation.
** 004 CA  20190527 Added annotations for property accessors and class event methods.
** 005 CA  20190706 Added Write(OUTPUT target AS CHARACTER).
** 006 HC  20190701 Implemented most of the legacy methods.
**     HC  20190707 Implemented read(dataSet) and read(tempTable) methods of JsonObject legacy class.
** 007 HC  20190803 Fixed an NPE condition in read().
** 008 CA  20191024 Added method support levels and updated the class support level.
** 009 CA  20191013 read(handle) can load either a TEMP-TABLE or DATASET.
** 010 ME  20210215 Fixing read methods.
** 011 CA  20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy signature.
**     CA  20210304 Fixed date, datetime and datetimetz literal parsing.
** 012 ME  20210319 Fix error handling, implement missing methods (OE12.2).
**     ME  20210323 Format error message when buffer isn't from a temp-table.
**     OM  20210809 Added missing add() methods.
**     CA  20210816 Fixed clone() - object references must be incremented.
**     OM  20210825 getJsonDataTypeName() is static now.
**     VVT 20210917 Javadoc fixed. 
**     ME  20210929 Fix return value on clone method.
**     CA  20220923 Variable definitions (including associated with parameters) must be done always outside of 
**                  the BlockManager API
**     TJD 20220504 Upgrade do Java 11 minor changes
**     CA  20220513 Renamed _BaseObject_.clone() to legacyClone(), as it can be overriden by sub-classes and
**                  the access mode may collide with the Java's Object.clone().
**     CA  20230116 Avoid using handle.unwrap, handle.getReference or other BDT usage from within FWD runtime.
** 013 VVT 20230318 The getNames() method return value type fixed. See #3827.
** 014 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
** 015 CA  20231113 The 'execute' method must be annotated with LegacySignature Type.Execute, and also can be
**                  dropped if is a no-op.
** 016 CA  20240227 Fixed SERIALIZE-ROW to not include a root buffer name key when exporting to JsonObject. 
*/

/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
**
**   0. Attribution Requirement.
**
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
**
**   1. No License To Use Trademarks.
**
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
**
**   2. No Misrepresentation of Affiliation.
**
**     You may not represent yourself as Golden Code Development Corporation or FWD.
**
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
**
**   3. No Misrepresentation of Source or Origin.
**
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/

package com.goldencode.p2j.oo.json.objectmodel;

import com.goldencode.p2j.oo.json.*;
import com.goldencode.p2j.oo.lang.*;
import com.goldencode.p2j.persist.*;
import com.goldencode.p2j.persist.serial.*;
import com.goldencode.p2j.util.*;
import com.goldencode.p2j.util.ErrorManager;
import com.goldencode.p2j.util.BlockManager.Action;
import com.goldencode.p2j.util.BlockManager.Condition;
import com.goldencode.p2j.util.logging.*;

import java.io.*;
import java.util.*;
import java.util.function.*;
import java.util.logging.*;
import java.util.stream.Collectors;

import static com.goldencode.p2j.util.BlockManager.*;
import static com.goldencode.p2j.report.ReportConstants.*;
import static com.goldencode.p2j.util.InternalEntry.Type;

/**
 * Implementation of the Progress.Json.Objectmodel.JsonObject builtin class.
 */
@LegacyResource(resource = "Progress.Json.ObjectModel.JsonObject")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
public class JsonObject
extends JsonConstruct
{
   /** Logger. */
   private static final CentralLogger LOG = CentralLogger.get(JsonObject.class);

   /**
    *
    * Properties of the json object, we sacrifice safety for performance here and directly store primitive
    * types together with JsonObject and JsonArray in the map
    */
   private final Map<String, Object> properties = new LinkedHashMap<>();

   @LegacySignature(type = Type.EXECUTE)
   public void __json_objectmodel_JsonObject_execute__()
   {
      onBlockLevel(Condition.ERROR, Action.THROW);
   }

   @LegacySignature(type = Type.CONSTRUCTOR)
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public void __json_objectmodel_JsonObject_constructor__()
   {
      internalProcedure(this, "__json_objectmodel_JsonObject_constructor__", new Block((Body) () -> 
      {
         __json_objectmodel_JsonConstruct_constructor__();
      }));
   }

   /**
    * Destructor for this class.  Cleanup/delete any created resources.
    */
   @LegacySignature(type = Type.DESTRUCTOR)
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public void __json_objectmodel_JsonObject_destructor__()
   {
      internalProcedure(this, "__json_objectmodel_JsonObject_destructor__", new Block((Body) () ->
      {
         clear();
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final character _val)
   {
      character prop = TypeFactory.initInput(_prop);
      character val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "COMHANDLE", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final comhandle _val)
   {
      character prop = TypeFactory.initInput(_prop);
      comhandle val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "DATE", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final date _val)
   {
      character prop = TypeFactory.initInput(_prop);
      date val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "DATETIME", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final datetime _val)
   {
      character prop = TypeFactory.initInput(_prop);
      datetime val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "DATETIMETZ", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final datetimetz _val)
   {
      character prop = TypeFactory.initInput(_prop);
      datetimetz val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "DECIMAL", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final decimal _val)
   {
      character prop = TypeFactory.initInput(_prop);
      decimal val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "HANDLE", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final handle _val)
   {
      character prop = TypeFactory.initInput(_prop);
      handle val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "INT64", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final int64 _val)
   {
      character prop = TypeFactory.initInput(_prop);
      int64 val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "INTEGER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final integer _val)
   {
      character prop = TypeFactory.initInput(_prop);
      integer val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "LOGICAL", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final logical _val)
   {
      character prop = TypeFactory.initInput(_prop);
      logical val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "LONGCHAR", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final longchar _val)
   {
      character prop = TypeFactory.initInput(_prop);
      longchar val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "MEMPTR", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final memptr _val)
   {
      character prop = TypeFactory.initInput(_prop);
      memptr val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "RAW", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final raw _val)
   {
      character prop = TypeFactory.initInput(_prop);
      raw val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "RECID", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final recid _val)
   {
      character prop = TypeFactory.initInput(_prop);
      recid val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "ROWID", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final rowid _val)
   {
      character prop = TypeFactory.initInput(_prop);
      rowid val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "OBJECT", qualified = "progress.json.objectmodel.jsonarray", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, final object<? extends com.goldencode.p2j.oo.json.objectmodel.JsonArray> _val)
   {
      character prop = TypeFactory.initInput(_prop);
      object<? extends com.goldencode.p2j.oo.json.objectmodel.JsonArray> val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }
   
   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters =
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "BLOB", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, blob _val)
   {
      character prop = TypeFactory.initInput(_prop);
      blob val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () -> addPropertyImpl(prop, val)));
   }
   
   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters =
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "CLOB", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add(final character _prop, clob _val)
   {
      character prop = TypeFactory.initInput(_prop);
      clob val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () -> addPropertyImpl(prop, val)));
   }
   
   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Add", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "OBJECT", qualified = "progress.json.objectmodel.jsonobject", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical add_1(final character _prop, final object<? extends com.goldencode.p2j.oo.json.objectmodel.JsonObject> _val)
   {
      character prop = TypeFactory.initInput(_prop);
      object<? extends com.goldencode.p2j.oo.json.objectmodel.JsonObject> val = TypeFactory.initInput(_val);
      
      return function(this, "Add", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "AddNull", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical addNull(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "AddNull", logical.class, new Block((Body) () ->
      {
         addPropertyImpl(prop, null, "AddNull");
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "AddNumber", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical addNumber(final character _prop, final character _val)
   {
      character prop = TypeFactory.initInput(_prop);
      character val = TypeFactory.initInput(_val);
      
      return function(this, "AddNumber", logical.class, new Block((Body) () ->
      {
         checkPropNotExists(prop, "AddNumber");
         
         try
         {
            addPropertyImpl(prop.toStringMessage(), val.isUnknown() ? (Object) null : Double.parseDouble(val.getValue()));
         }
         catch (NumberFormatException e)
         {
            undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("value", this,
                     "AddNumber", "Not a valid JSON number."), 16053));
         }
      }));
   }

   @LegacySignature(returns = "OBJECT", type = Type.METHOD, name = "Clone", qualified = "progress.lang.object")
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   @Override
   public object<? extends com.goldencode.p2j.oo.lang._BaseObject_> legacyClone()
   {
      object<JsonObject> cloned = TypeFactory.object(JsonObject.class);
      
      return function(this, "Clone", object.class, new Block((Body) () ->
      {
         cloned.assign(ObjectOps.newInstance(JsonObject.class));
         
         for (Map.Entry<String, Object> prop : properties.entrySet())
         {
            Object val = prop.getValue();
            if (val instanceof JsonConstruct)
            {
               val = ((JsonConstruct) val).legacyClone().ref();
            }
            cloned.ref().addPropertyImpl(prop.getKey(), val);
         }

         returnNormal(cloned);
      }));
   }

   @LegacySignature(returns = "CHARACTER", type = Type.METHOD, name = "GetCharacter", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public character getCharacter(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetCharacter", character.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetCharacter", 1, o -> new character((String) o), unknown::new);
      }));
   }

   @LegacySignature(returns = "COMHANDLE", type = Type.METHOD, name = "GetCOMHandle", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public comhandle getComhandle(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetCOMHandle", comhandle.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetCOMHandle", 2, o -> comhandle.fromResourceId(((Number) o).longValue()), comhandle::new);
      }));
   }

   @LegacySignature(returns = "DATE", type = Type.METHOD, name = "GetDate", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public date getDate(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetDate", date.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetDate", 1, o -> date.parseLiteral((String) o), date::new);
      }));
   }

   @LegacySignature(returns = "DATETIME", type = Type.METHOD, name = "GetDatetime", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public datetime getDatetime(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetDatetime", datetime.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetDatetime", 1, o-> datetime.parseLiteral((String) o), datetime::new);
      }));
   }

   @LegacySignature(returns = "DATETIMETZ", type = Type.METHOD, name = "GetDatetimeTZ", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public datetimetz getDatetimeTz(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetDatetimeTZ", datetimetz.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetDatetimeTZ", 1, o -> datetimetz.parseLiteral((String) o), datetimetz::new);
      }));
   }

   @LegacySignature(returns = "DECIMAL", type = Type.METHOD, name = "GetDecimal", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public decimal getDecimal(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetDecimal", decimal.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetDecimal", 2, o -> new decimal((Number) o), decimal::new);
      }));
   }

   @LegacySignature(returns = "HANDLE", type = Type.METHOD, name = "GetHandle", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public handle getHandle(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetHandle", handle.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetHandle", 2, o -> handle.fromResourceId(((Number) o).longValue()), handle::new);
      }));
   }

   @LegacySignature(returns = "INT64", type = Type.METHOD, name = "GetInt64", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public int64 getInt64(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetInt64", int64.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetInt64", 2, o -> new int64((Number) o), int64::new);
      }));
   }

   @LegacySignature(returns = "INTEGER", type = Type.METHOD, name = "GetInteger", parameters =
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public integer getInteger(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetInteger", integer.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetInteger", 2, o -> new integer((Number) o), integer::new);
      }));
   }

   @LegacySignature(returns = "OBJECT", type = Type.METHOD, name = "GetJsonArray", qualified = "progress.json.objectmodel.jsonarray", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public object<? extends com.goldencode.p2j.oo.json.objectmodel.JsonArray> getJsonArray(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetJsonArray", object.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetJsonArray", 5, o -> new object((JsonArray) o), object::new);
      }));
   }

   @LegacySignature(returns = "OBJECT", type = Type.METHOD, name = "GetJsonObject", qualified = "progress.json.objectmodel.jsonobject", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public object<? extends com.goldencode.p2j.oo.json.objectmodel.JsonObject> getJsonObject(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetJsonObject", object.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetJsonObject", 4, o -> new object((JsonObject) o), object::new);
      }));
   }

   @LegacySignature(returns = "LONGCHAR", type = Type.METHOD, name = "GetJsonText")
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public longchar getJsonText()
   {
      return function(this, "GetJsonText", longchar.class, new Block((Body) () ->
      {
         getJsonTextImpl(this);
      }));
   }

   @LegacySignature(returns = "LONGCHAR", type = Type.METHOD, name = "GetJsonText", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public longchar getJsonText(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetJsonText", longchar.class, new Block((Body) () ->
      {
         checkPropExists(prop, "GetJsonText");
         
         try
         {
            returnNormal(getJsonText(properties.get(prop.toStringMessage())));
         }
         catch (IOException e)
         {
            LOG.log(Level.WARNING, "", e);
            returnError(ObjectOps.newInstance(JsonError.class));
         }
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "GetLogical", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical getLogical(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetLogical", logical.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetLogical", 3, o -> new logical((Boolean) o), logical::new);
      }));
   }

   @LegacySignature(returns = "LONGCHAR", type = Type.METHOD, name = "GetLongchar", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public longchar getLongchar(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetLongchar", longchar.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetLongchar", 1, o -> new longchar((String) o), longchar::new);
      }));
   }

   @LegacySignature(returns = "LONGCHAR", type = Type.METHOD, name = "GetLongchar", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "cp", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public longchar getLongchar(final character _prop, final character _cp)
   {
      character prop = TypeFactory.initInput(_prop);
      character cp = TypeFactory.initInput(_cp);
      longchar res = TypeFactory.longchar();
      
      return function(this, "GetLongchar", longchar.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetLongchar", 1, o ->
         {
            if (!TextOps.isEmpty(cp))
               res.fixCodePage(cp);
            res.assign(o);
            
            return res;
         },
            longchar::new);
      }));
   }

   @LegacySignature(returns = "MEMPTR", type = Type.METHOD, name = "GetMemptr", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public memptr getMemptr(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetMemptr", memptr.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetMemptr", 1, o -> new memptr(Base64.getDecoder().decode((String) o)), unknown::new);
      }));
   }

   @LegacySignature(returns = "CHARACTER", type = Type.METHOD, name = "GetNames", extent = -1)
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public longchar[] getNames()
   {
      return extentFunction(this, "GetNames", longchar.class, new Block((Body) () ->
      {
         List<longchar> names = properties.keySet().stream().map(longchar::new).collect(Collectors.toList());
         returnExtentNormal(names.toArray(new longchar[names.size()]));
      }));
   }

   @LegacySignature(returns = "RAW", type = Type.METHOD, name = "GetRaw", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public raw getRaw(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetRaw", raw.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetRaw", 1,
                         o -> new raw(Base64.getDecoder().decode((String) o)), raw::instantiateUnknownRaw);
      }));
   }

   @LegacySignature(returns = "RECID", type = Type.METHOD, name = "GetRecid", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public recid getRecid(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetRecid", recid.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetRecid", 2, o -> new recid(((Number) o).longValue()), recid::new);
      }));
   }

   @LegacySignature(returns = "ROWID", type = Type.METHOD, name = "GetRowid", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public rowid getRowid(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetRowid", rowid.class, new Block((Body) () ->
      {
         getPropertyImpl(prop, "GetRowid", 1, o ->
         {
            Base64.Decoder dec = Base64.getDecoder();
            return new rowid(Utils.bytesToLongLE(dec.decode((String) o)));
         },
            rowid::new);
      }));
   }

   @LegacySignature(returns = "INTEGER", type = Type.METHOD, name = "GetType", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public integer getType(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "GetType", integer.class, new Block((Body) () ->
      {
         checkPropExists(prop, "GetType");
         
         Object value = properties.get(prop.toStringMessage());
         returnNormal(new integer(JsonBackend.getJsonDataType(value)));
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Has", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical has(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "Has", logical.class, new Block((Body) () ->
      {
         checkValidPropName(prop, "Has");
         returnNormal(new logical(properties.containsKey(prop.toStringMessage())));
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "IsNull", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical isNull(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "IsNull", logical.class, new Block((Body) () ->
      {
         checkPropExists(prop, "IsNull");
         
         Object val = properties.get(prop.toStringMessage());
         returnNormal(new logical(val == null));
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = 
   {
      @LegacyParameter(name = "bh", type = "HANDLE", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical read(final handle _bh)
   {
      return read(_bh, new logical(false), new logical(false));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = 
   {
      @LegacyParameter(name = "bh", type = "HANDLE", mode = "INPUT"),
      @LegacyParameter(name = "omit", type = "LOGICAL", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical read(final handle _bh, final logical _omit)
   {
      return read(_bh, _omit, new logical(false));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = 
   {
      @LegacyParameter(name = "bh", type = "HANDLE", mode = "INPUT"),
      @LegacyParameter(name = "omit", type = "LOGICAL", mode = "INPUT"),
      @LegacyParameter(name = "b4img", type = "LOGICAL", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical read(final handle _bh, final logical _omit, final logical _b4img)
   {
      handle bh = TypeFactory.initInput(_bh);
      logical omit = TypeFactory.initInput(_omit);
      logical b4img = TypeFactory.initInput(_b4img);
           
      return function(this, "Read", logical.class, new Block((Body) () ->
      {
         if (!bh.isUnknown())
         {
            WrappedResource res = bh.getResource();
            if (res instanceof BufferImpl)
            {
               BufferImpl buf = (BufferImpl) res;
               returnNormal(readImpl(buf, omit));
            }
            else if (res instanceof TempTable)
            {
               TempTable tt = (TempTable) res;
               TemporaryBuffer tb = (TemporaryBuffer) ((BufferImpl) tt.defaultBufferHandleNative()).buffer();
               returnNormal(readImpl(tb, omit));
            }
            else if (res instanceof DataSet)
            {
               DataSet ds = (DataSet) res;
               returnNormal(readImpl(ds, omit, b4img));
            }
         }
         
         undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("handle", this,
                  "Read", "Not initialized or not a handle to a temp-table/dataset/buffer."), 16070));
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Remove", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical remove(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "Remove", logical.class, new Block((Body) () ->
      {
         checkPropExists(prop, "Remove");
         
         Object o = properties.remove(prop.toStringMessage());
         if (o instanceof JsonConstruct)
         {
            ObjectOps.decrement((_BaseObject_) o);
         }
         returnNormal(new logical(true));
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final character _val)
   {
      character prop = TypeFactory.initInput(_prop);
      character val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "COMHANDLE", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final comhandle _val)
   {
      character prop = TypeFactory.initInput(_prop);
      comhandle val = TypeFactory.initInput(_val);

      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "DATE", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final date _val)
   {
      character prop = TypeFactory.initInput(_prop);
      date val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "DATETIME", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final datetime _val)
   {
      character prop = TypeFactory.initInput(_prop);
      datetime val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "DATETIMETZ", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final datetimetz _val)
   {
      character prop = TypeFactory.initInput(_prop);
      datetimetz val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "DECIMAL", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final decimal _val)
   {
      character prop = TypeFactory.initInput(_prop);
      decimal val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "HANDLE", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final handle _val)
   {
      character prop = TypeFactory.initInput(_prop);
      handle val = TypeFactory.initInput(_val);

      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "INT64", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final int64 _val)
   {
      character prop = TypeFactory.initInput(_prop);
      int64 val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "INTEGER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final integer _val)
   {
      character prop = TypeFactory.initInput(_prop);
      integer val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "LOGICAL", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final logical _val)
   {
      character prop = TypeFactory.initInput(_prop);
      logical val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "LONGCHAR", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final longchar _val)
   {
      character prop = TypeFactory.initInput(_prop);
      longchar val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "MEMPTR", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final memptr _val)
   {
      character prop = TypeFactory.initInput(_prop);
      memptr val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "RAW", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final raw _val)
   {
      character prop = TypeFactory.initInput(_prop);
      raw val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "RECID", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final recid _val)
   {
      character prop = TypeFactory.initInput(_prop);
      recid val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "ROWID", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set(final character _prop, final rowid _val)
   {
      character prop = TypeFactory.initInput(_prop);
      rowid val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "OBJECT", qualified = "progress.json.objectmodel.jsonarray", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set_1(final character _prop, final object<? extends com.goldencode.p2j.oo.json.objectmodel.JsonArray> _val)
   {
      character prop = TypeFactory.initInput(_prop);
      object<? extends com.goldencode.p2j.oo.json.objectmodel.JsonArray> val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Set", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "OBJECT", qualified = "progress.json.objectmodel.jsonobject", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical set_2(final character _prop, final object<? extends com.goldencode.p2j.oo.json.objectmodel.JsonObject> _val)
   {
      character prop = TypeFactory.initInput(_prop);
      object<? extends com.goldencode.p2j.oo.json.objectmodel.JsonObject> val = TypeFactory.initInput(_val);
      
      return function(this, "Set", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, val);
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "SetNull", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical setNull(final character _prop)
   {
      character prop = TypeFactory.initInput(_prop);
      
      return function(this, "SetNull", logical.class, new Block((Body) () ->
      {
         setPropertyImpl(prop, null, "SetNull");
      }));
   }

   @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "SetNumber", parameters = 
   {
      @LegacyParameter(name = "prop", type = "CHARACTER", mode = "INPUT"),
      @LegacyParameter(name = "val", type = "CHARACTER", mode = "INPUT")
   })
   @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
   public logical setNumber(final character _prop, final character _val)
   {
      character prop = TypeFactory.initInput(_prop);
      character val = TypeFactory.initInput(_val);
      
      return function(this, "SetNumber", logical.class, new Block((Body) () ->
      {
         checkPropExists(prop, "SetNumber");
         
         try
         {
            addPropertyImpl(prop.toStringMessage(), val.isUnknown() ? (Object) null : Double.parseDouble(val.getValue()));
         }
         catch (NumberFormatException e)
         {
            undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("value", this,
                     "SetNumber", "Not a valid JSON number."), 16053));
         }
      }));
   }

   @Override
   public void addElement(String name, object<? extends JsonConstruct> value)
   {
      addPropertyImpl(name, value.ref());
   }

   /**
    * Adds a json element (object property or array element) to the json object.
    *
    * @param   name
    *          Name of the json element. This parameter is ignored if this is a json array.
    * @param   value
    *          Value of the json element.
    */
   @Override
   public void addElement(String name, String value)
   {
      addPropertyImpl(name, value);
   }

   /**
    * Adds a json element (object property or array element) to the json object.
    *
    * @param   name
    *          Name of the json element. This parameter is ignored if this is a json array.
    * @param   value
    *          Value of the json element.
    */
   @Override
   public void addElement(String name, Number value)
   {
      addPropertyImpl(name, value);
   }

   /**
    * Adds a json element (object property or array element) to the json object.
    *
    * @param   name
    *          Name of the json element. This parameter is ignored if this is a json array.
    * @param   value
    *          Value of the json element.
    */
   @Override
   public void addElement(String name, Boolean value)
   {
      addPropertyImpl(name, value);
   }

   /**
    * Adds null json element (object property or array element) to the json object.
    *
    * @param   name
    *          Name of the json element. This parameter is ignored if this is a json array.
    */
   @Override
   public void addElementNull(String name)
   {
      addPropertyImpl(name, null);
   }

   /**
    * Returns json properties of this json object.
    *
    * @return  see above.
    */
   public Iterable<Map.Entry<String, Object>> getProperties()
   {
      return properties.entrySet();
   }
   
   /**
    * Merge all properties from the source to this object.  No collision checks are performed.
    * 
    * @param    src
    *           The source object.
    */
   public void copy(JsonObject src)
   {
      for (Map.Entry<String, Object> entry : src.getProperties())
      {
         addPropertyImpl(entry.getKey(), entry.getValue());
      }
   }

   /**
    * Removes all values from this json object or array.
    */
   protected void clear()
   {
      for (Map.Entry<String, Object> e : properties.entrySet())
      {
         Object o = e.getValue();
         if (o instanceof JsonConstruct)
         {
            ObjectOps.decrement((_BaseObject_) o);
         }
      }

      properties.clear();
   }

   /**
    * Adds the supplied property to the this json object. The allowed property value types are
    * {@linkplain JsonConstruct}, {@linkplain String}, {@linkplain Number}, {@linkplain Boolean}, or
    * {@code null}. It is up to the caller to supply the correct type.
    *
    * @param   name
    *          Property name.
    * @param   value
    *          Property value.
    */
   private void addPropertyImpl(String name, Object value)
   {
      if (value instanceof JsonConstruct)
      {
         ObjectOps.increment((_BaseObject_) value);
      }
      properties.put(name, value);
   }

   /**
    * Implements the {@code add} legacy methods for adding json property to this instance.
    *
    * @param   name
    *          Property name.
    * @param   value
    *          Property value.
    */
   private void addPropertyImpl(character name, BaseDataType value)
   {
      addPropertyImpl(name, value, "Add");
   }
   
   /**
    * Implements the {@code add} legacy methods for adding json property to this instance.
    *
    * @param   name
    *          Property name.
    * @param   value
    *          Property value.
    * @param   method
    *          Calling method name, used for error message.
    */
   private void addPropertyImpl(character name, BaseDataType value, String method)
   {
      checkPropNotExists(name, method);
      
      try
      {
         Object newValue = value != null ? JsonBackend.convertLegacyValueToJson(value) : null;
         addPropertyImpl(name.toStringMessage(), newValue);
         returnNormal(new logical(true));
      }
      catch (ClassCastException e)
      {
         returnError(ObjectOps.newInstance(JsonError.class));
      }
   }

   /**
    * Implements the {@code set} legacy methods for setting json property in this instance.
    *
    * @param   name
    *          Property name.
    * @param   value
    *          Property value.
    */
   private void setPropertyImpl(character name, BaseDataType value)
   {
      setPropertyImpl(name, value, "Set");
   }
   
   /**
    * Implements the {@code set} legacy methods for setting json property in this instance.
    *
    * @param   name
    *          Property name.
    * @param   value
    *          Property value.
    */
   private void setPropertyImpl(character name, BaseDataType value, String method)
   {
      checkPropExists(name, method);
      
      try
      {
         Object newValue = value != null ? JsonBackend.convertLegacyValueToJson(value) : null;
         addPropertyImpl(name.toStringMessage(), newValue);
         returnNormal(new logical(true));
      }
      catch (ClassCastException e)
      {
         returnError(ObjectOps.newInstance(JsonError.class));
      }
   }

   /**
    * Checks whether the supplied value is valid json property name.
    *
    * @param   property
    *          Property name.
    * @param   method
    *          Calling method name, used for error message.
    */
   private void checkValidPropName(character property, String method)
   {
      if (TextOps.isEmpty(property))
      {
         undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("name", this,
                  method, "Can not be UNKNOWN (?) or empty string."), 16055));
      }
   }

   /**
    * Checks whether the supplied value is valid json property name and whether the property exists.
    *
    * @param   property
    *          Property name.
    * @param   method
    *          Calling method name, used for error message.
    */
   private void checkPropExists(character property, String method)
   {
      checkValidPropName(property, method);
      
      String key = property.toStringMessage();
      
      if (!properties.containsKey(key))
      {
         undoThrow(JsonError.newInstance(String.format("Call to Progress.Json.ObjectModel.JsonObject:%s( ) failed. Property '%s' was not found.", 
                  method, key), 16058));
      }
   }

   /**
    * Checks whether the supplied value is valid json property name and whether the property not exists.
    *
    * @param   property
    *          Property name.
    * @param   method
    *          Calling method name, used for error message.
    */
   private void checkPropNotExists(character property, String method)
   {
      checkValidPropName(property, method);
      
      String key = property.toStringMessage();
      
      if (properties.containsKey(key))
      {
         undoThrow(JsonError.newInstance(String.format("Call to Progress.Json.ObjectModel.JsonObject:%s( ) failed. Attempted to add duplicate property '%s'.", 
                  method, key), 16056));
      }
   }
   
   /**
    * Implements the {@code get} legacy methods.
    *
    * @param   propName
    *          Property name.
    * @param   method
    *          The actual 'get' method name, used for error message.
    * @param   type
    *          The expected JSON type.
    * @param   converter
    *          The function that will convert the stored Java value instance to a legacy instance.
    * @param   nullSupplier
    *          When the stored element is {@code null} this supplier will be used to retrieve the
    *          corresponding legacy value.
    */
   private void getPropertyImpl(character propName,
                                String method, 
                                int type,
                                Function<Object, BaseDataType> converter,
                                Supplier<BaseDataType> nullSupplier)
   {
      checkPropExists(propName, method);
      Object val = properties.get(propName.toStringMessage());
      int vtype = JsonBackend.instance().getJsonDataType(val);
      
      if (vtype == 6)
         returnNormal(nullSupplier.get());
      
      if (vtype != type)
      {
         undoThrow(JsonError.newInstance(String.format("Call to Progress.Json.ObjectModel.JsonObject:%s( ) failed. Expected a JSON %s value, found a JSON %s value.", 
                  method, JsonBackend.getJsonDataTypeName(type), JsonBackend.getJsonDataTypeName(vtype)), 16060));
      }
      
      BaseDataType res = null;
      
      try
      {
         if (val == null)
         {
            res = nullSupplier.get();
         }
         else
         {
            res = converter.apply(val);
         }
      }
      catch(Exception ex)
      {
         LOG.log(Level.WARNING, "", ex);
         returnError(ObjectOps.newInstance(JsonError.class));
      }
      returnNormal(res);
   }
   
   protected logical readImpl(TemporaryBuffer tb, final logical omit)
   {
      return function(this, "Read", logical.class, new Block((Body) () -> {
         ObjectBuilder jb = new ObjectBuilder(this);
         JsonExport export = new JsonExport();

         this.clear();
         
         try
         {
            export.serializeTempTable(jb, tb, false, !omit.isUnknown() && omit.booleanValue());
            returnNormal(new logical(true));
         }
         catch (IOException e)
         {
            LOG.log(Level.WARNING, "", e);
            returnError(ObjectOps.newInstance(JsonError.class));
         }
      }));
   }
   
   protected logical readImpl(BufferImpl buffer, final logical omit)
   {
      return function(this, "Read", logical.class, new Block((Body) () -> {
         
         if (!buffer._available())
         {
            undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("buffer-handle", this,
                     "Read", "No record in buffer."), 16065));
         }
         
         if (!buffer.buffer().isTemporary())
         {
            ErrorManager.recordOrThrowError(15378, "JSON methods are only allowed on TEMP-TABLE buffers", false, false);
         }
         
         ObjectBuilder jb = new ObjectBuilder(this);
         JsonExport export = new JsonExport();

         this.clear();
         
         try
         {
            export.serializeRecord(jb, (TemporaryBuffer) buffer.buffer(), !omit.isUnknown() && omit.booleanValue());
            returnNormal(new logical(true));
         }
         catch (IOException e)
         {
            LOG.log(Level.WARNING, "", e);
            returnError(ObjectOps.newInstance(JsonError.class));
         }
      }));
   }
   
   protected logical readImpl(DataSet pds, final logical omit, final logical b4img)
   {
      return function(this, "Read", logical.class, new Block((Body) () -> {
         ObjectBuilder jb = new ObjectBuilder(this);
         JsonExport export = new JsonExport();

         this.clear();
         
         try
         {
            export.serializeDataSet(jb, pds, 
                     !omit.isUnknown() && omit.booleanValue(), 
                     false,
                     !b4img.isUnknown() && b4img.booleanValue());
            
            returnNormal(new logical(true));
         }
         catch (IOException e)
         {
            LOG.log(Level.WARNING, "", e);
            returnError(ObjectOps.newInstance(JsonError.class));
         }
      }));
   }
}