November 25, 2020, 08:15:42 AM

Author Topic: [bmx] Convert an Object to JSON by N [ 1+ years ago ]  (Read 775 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bmx] Convert an Object to JSON by N [ 1+ years ago ]
« on: June 29, 2017, 12:28:38 AM »
Title : Convert an Object to JSON
Author : N
Posted : 1+ years ago

Description : This does about what it says, using reflection.  The only thing that doesn't really work too well is multidim arrays, because those are grade-A insanity to work with.  Objects that have already been converted are referenced only by their handle (which is, to be perfectly honest, just the their memory address, but it works well enough) - no type name is provided for them, since they've already been mentioned at least once before the current object/field/what have you in the JSON.

To use it, you call ObjectToJSON(obj, map) where obj is the object you want to convert to JSON and map is a TMap you'll use to store which objects have already been converted to JSON.  If objects have dependencies on one-another or reference each other, you should try to create one TMap for that group of objects so as to reduce the size of the JSON output.


Code :
Code: BlitzMax
  1. SuperStrict
  2.  
  3. Private
  4. Function _objtoptr:Byte Ptr(obj:Byte Ptr)
  5.         Return obj
  6. End Function
  7. Global ObjToPtr:Byte Ptr(obj:Object)=Byte Ptr(_objtoptr)
  8.  
  9. Function FieldToJSON:String(fid:TField, forObject:Object, map:TMap)
  10.         Select fid.TypeId()
  11.                 Case IntTypeId,ShortTypeId,ByteTypeId
  12.                         Return String(fid.GetInt(forObject))
  13.                 Case LongTypeId
  14.                         Return String(fid.GetLong(forObject))
  15.                 Case DoubleTypeId
  16.                         Return String(fid.GetDouble(forObject))
  17.                 Case FloatTypeId
  18.                         Return String(fid.GetFloat(forObject))
  19.                 Default
  20.                         Return ObjectToJSON(fid.Get(forObject), map)
  21.         End Select
  22. End Function
  23.  
  24. Public
  25.  
  26. ' The map argument is used to record what objects have already been put in a prior part of any JSON string
  27. Function ObjectToJSON:String(obj:Object, map:TMap)
  28.         Assert map Else "Inspection map not present"
  29.        
  30.         Local name$ = Int(ObjToPtr(obj))
  31.         Local result$
  32.        
  33.         Local tid:TTypeId = TTypeId.ForObject(obj)
  34.        
  35.         If tid = Null Then
  36.                 Return "null"
  37.         EndIf
  38.        
  39.         If tid <> StringTypeId And tid._class <> ArrayTypeId._class And map.Contains(name) Then
  40.                 Return "{~qhandle~q: "+name+"}"
  41.         EndIf
  42.        
  43.         map.Insert(name,name)
  44.        
  45.         If tid._class = ArrayTypeId._class Then
  46.                 If tid.Name().StartsWith("Null[") Then
  47.                         Return "null"
  48.                 EndIf
  49.                
  50.                 result = "{~qhandle~q: "+name+", ~qtype~q: ~q"+tid.Name()+"~q"
  51.                 Local elemt:TTypeId = tid.ElementType()
  52.                 If elemt Then
  53.                         Local dimensions:Int = tid.ArrayDimensions(obj)
  54.                         result :+ ", dimensions: ["
  55.                        
  56.                         Local dimString$ = ""
  57.                         Local last:Int = 1
  58.                         For Local dim:Int = dimensions-1 To 0 Step -1
  59.                                 Local dimLength:Int = tid.ArrayLength(obj, dim)
  60.                                
  61.                                 If dim < dimensions-1 Then
  62.                                         dimString = ", " + dimString
  63.                                 EndIf
  64.                                
  65.                                 dimString = (dimLength / last) + dimString
  66.                                 last = dimLength
  67.                         Next
  68.                         result :+ dimString
  69.                         result :+ "]"
  70.                        
  71.                         Local elems:String[] = New String[tid.ArrayLength(obj, 0)]
  72.                         For Local i:Int = 0 Until elems.Length
  73.                                 Select elemt
  74.                                         Case IntTypeId, ShortTypeId, ByteTypeId, LongTypeId, DoubleTypeId, FloatTypeId
  75.                                                 elems[i] = String(tid.GetArrayElement(obj, i))
  76.                                         Default
  77.                                                 elems[i] = ObjectToJSON(tid.GetArrayElement(obj, i), map)
  78.                                 End Select
  79.                         Next
  80.                        
  81.                         result :+ ", ~qcontent~q: ["+(", ".Join(elems))+"]}"
  82.                 Else
  83.                         result :+ ", ~qcontent~q: []}"
  84.                 EndIf
  85.         ElseIf tid = StringTypeId
  86.                 If String(obj) = Null Then
  87.                         Return "~q~q"
  88.                 EndIf
  89.                 result = "~q" + String(obj).Replace("~q", "~q").Replace("~n", "
  90. ").Replace("~t", "      ").Replace("~r", "
  91. ").Replace("~0", "") + "~q"
  92.         Else
  93.                 If Not obj Then
  94.                         Return "null"
  95.                 EndIf
  96.                
  97.                 result = "{~qhandle~q: "+name+", ~qtype~q: ~q"+tid.Name()+"~q"
  98.                
  99.                 Local fields:TList = tid.EnumFields()
  100.                 Local enum:TListEnum = fields.ObjectEnumerator()
  101.                
  102.                 While enum.HasNext()
  103.                         Local fid:TField = TField(enum.NextObject())
  104.                         result :+ ", ~q."+fid.Name()+"~q: "+FieldToJSON(fid, obj, map)
  105.                 Wend
  106.                
  107.                 result :+ "}"
  108.         EndIf
  109.        
  110.         Return result
  111. End Function


Comments :


N(Posted 1+ years ago)

 Updated to have slightly better multidimensional array support.  An array of integers called 'dimensions' will precede the 'content' field for storing array data.  This contains the length of each array dimension (for some reason brl.Reflection's TTypeID#ArrayLength reports the length of a dimension in terms of every element accessible from a dimension onward, so this only includes the size of each dimension on its own).


 

SimplePortal 2.3.6 © 2008-2014, SimplePortal