11package com .genexus .gam .utils ;
22
33import com .genexus .GxUserType ;
4- import com .google .gson .Gson ;
5- import com .google .gson .GsonBuilder ;
6- import com .google .gson .JsonParser ;
7- import com .google .gson .JsonElement ;
8- import com .google .gson .JsonPrimitive ;
9- import com .google .gson .JsonSyntaxException ;
4+ import com .google .gson .*;
105import com .google .gson .reflect .TypeToken ;
6+ import com .google .gson .stream .JsonReader ;
7+ import com .google .gson .stream .JsonWriter ;
118
9+ import java .io .IOException ;
1210import java .lang .reflect .Type ;
1311import java .util .LinkedHashMap ;
1412import java .util .List ;
@@ -23,7 +21,42 @@ public class Dictionary {
2321
2422 public Dictionary () {
2523 this .userMap = new LinkedHashMap <>();
26- this .gson = new GsonBuilder ().serializeNulls ().create ();
24+ this .gson = new GsonBuilder ().serializeNulls ()
25+ .addSerializationExclusionStrategy (new ExclusionStrategy () {
26+ @ Override
27+ public boolean shouldSkipField (FieldAttributes f ) {
28+ // exclude only the field 'map' inherited from org.json.JSONObject
29+ return f .getName ().equals ("map" ) &&
30+ f .getDeclaringClass () == org .json .JSONObject .class ;
31+ }
32+
33+ @ Override
34+ public boolean shouldSkipClass (Class <?> clazz ) {
35+ return false ;
36+ }
37+ })
38+ .registerTypeHierarchyAdapter (Number .class , new TypeAdapter <Number >() {
39+ @ Override
40+ public void write (JsonWriter out , Number value ) throws IOException {
41+ if (value == null ) {
42+ out .nullValue ();
43+ return ;
44+ }
45+
46+ double d = value .doubleValue ();
47+ if (d == Math .rint (d )) {
48+ out .value (value .longValue ()); // 1.0 → 1
49+ } else {
50+ out .value (d ); // 1.5 → 1.5
51+ }
52+ }
53+
54+ @ Override
55+ public Number read (JsonReader in ) throws IOException {
56+ return in .nextDouble ();
57+ }
58+ })
59+ .create ();
2760 }
2861
2962 public Object get (String key ) {
@@ -54,40 +87,59 @@ private Map<String, Object> jsonStringToMap(String jsonString) {
5487 return this .gson .fromJson (jsonString , type );
5588 }
5689
57- private void objectToMap (String key , Object value ) {
58- if (value == null ) {
59- this .userMap .put (key , null );
60- } else if (value instanceof Number || value instanceof Boolean || value instanceof Map || value instanceof List ) {
61- this .userMap .put (key , value );
62- } else if (value instanceof GxUserType ) {
63- this .userMap .put (key , jsonStringToMap (((GxUserType ) value ).toJSonString ()));
64- } else if (value instanceof String ) {
65- String str = (String ) value ;
66-
67- // Try to parse as JSON
90+ private Object deepConvert (Object value ) {
91+ if (value == null ) return null ;
92+
93+ if (value instanceof Number || value instanceof Boolean ) {
94+ return value ;
95+ }
96+
97+ if (value instanceof String ) {
6898 try {
69- JsonElement parsed = JsonParser .parseString (str );
99+ JsonElement parsed = JsonParser .parseString (( String ) value );
70100 if (parsed .isJsonObject ()) {
71- this .userMap .put (key , this .gson .fromJson (parsed , Map .class ));
72- } else if (parsed .isJsonArray ()) {
73- this .userMap .put (key , this .gson .fromJson (parsed , List .class ));
74- } else if (parsed .isJsonPrimitive ()) {
75- JsonPrimitive primitive = parsed .getAsJsonPrimitive ();
76- if (primitive .isBoolean ()) {
77- this .userMap .put (key , primitive .getAsBoolean ());
78- } else if (primitive .isNumber ()) {
79- this .userMap .put (key , primitive .getAsNumber ());
80- } else if (primitive .isString ()) {
81- this .userMap .put (key , primitive .getAsString ());
82- }
101+ return gson .fromJson (parsed , Map .class );
83102 }
84- } catch (JsonSyntaxException e ) {
85- // Invalid JSON: it is left as string
86- this .userMap .put (key , str );
103+ if (parsed .isJsonArray ()) {
104+ return gson .fromJson (parsed , List .class );
105+ }
106+ return ((JsonPrimitive ) parsed ).getAsString ();
107+ } catch (Exception e ) {
108+ return value ;
87109 }
88- } else {
89- // Any other object: it is converted to string
90- this .userMap .put (key , value .toString ());
91110 }
111+
112+ // SDT => Map
113+ if (value instanceof GxUserType ) {
114+ String s = ((GxUserType ) value ).toJSonString ();
115+ return jsonStringToMap (s );
116+ }
117+
118+ // Map => deep convert values
119+ if (value instanceof Map ) {
120+ Map <String ,Object > newMap = new LinkedHashMap <>();
121+ ((Map <?,?>) value ).forEach ((k ,v ) -> newMap .put (k .toString (), deepConvert (v )));
122+ return newMap ;
123+ }
124+
125+ // List => deep convert each element
126+ if (value instanceof List ) {
127+ List <Object > newList = new java .util .ArrayList <>();
128+ for (Object o : (List <?>) value ) newList .add (deepConvert (o ));
129+ return newList ;
130+ }
131+
132+ // Catch: JSONObjectWrapper
133+ if (value .getClass ().getName ().contains ("JSONObjectWrapper" ) ||
134+ value instanceof org .json .JSONObject ) {
135+ // Convert org.json to Map
136+ return jsonStringToMap (value .toString ());
137+ }
138+
139+ return value .toString ();
140+ }
141+
142+ private void objectToMap (String key , Object value ) {
143+ this .userMap .put (key , deepConvert (value ));
92144 }
93145}
0 commit comments