Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

745
LINES

< > BotCompany Repo | #1034648 // structure function (v21, supporting enums, LIVE)

JavaX fragment (include) [tags: use-pretranspiled]

Transpiled version (11649L) is out of date.

1  
sbool structure_showTiming, structure_checkTokenCount;
2  
3  
sS structure(O o) {
4  
  ret structure(o, new structure_Data);
5  
}
6  
7  
sS structure(O o, structure_Data d) {
8  
  new StringWriter sw;
9  
  d.out = new PrintWriter(sw);
10  
  structure_go(o, d);
11  
  S s = str(sw);
12  
  if (structure_checkTokenCount) {
13  
    print("token count=" + d.n);
14  
    assertEquals("token count", l(javaTokC(s)), d.n);
15  
  }
16  
  ret s;
17  
}
18  
19  
svoid structure_go(O o, structure_Data d) {
20  
  structure_1(o, d);
21  
  while (nempty(d.stack))
22  
    popLast(d.stack).run();
23  
}
24  
25  
svoid structureToPrintWriter(O o, PrintWriter out, structure_Data d default new) {
26  
  d.out = out;
27  
  structure_go(o, d);
28  
}
29  
30  
// leave to false, unless unstructure() breaks
31  
static boolean structure_allowShortening = false;
32  
33  
// info on how to serialize objects of a certain class
34  
sclass structure_ClassInfo<A> {
35  
  Class c;
36  
  S shortName;
37  
  L<Field> fields;
38  
  Method customSerializer;
39  
  IVF1<O> serializeObject; // can be set by caller of structure function
40  
  bool special; // various special classes
41  
  bool nullInstances; // serialize all instances as null (e.g. lambdas/anonymous classes)
42  
  bool javafy; // always convert to "j ..."
43  
  O emptyInstance; // to grab default field values from
44  
  
45  
  toString {
46  
    ret commaCombine(
47  
      "Class " + className(c),
48  
      stringIf(+special),
49  
      stringIf(+customSerializer != null),
50  
      stringIf(+javafy),
51  
      stringIf(+nullInstances),
52  
    );
53  
  }
54  
  
55  
  void nullInstances(bool b) {
56  
    this.nullInstances = b;
57  
    if (b) set special;
58  
  }
59  
  
60  
  void javafy(bool b) {
61  
    this.javafy = b;
62  
    if (b) set special;
63  
  }
64  
  
65  
  // overridable - return true if you wrote the object
66  
  bool handle(A o) { false; }
67  
}
68  
69  
sclass structure_Data {
70  
  PrintWriter out;
71  
  int stringSizeLimit;
72  
  int shareStringsLongerThan = 20;
73  
  bool noStringSharing;
74  
  bool storeBaseClasses;
75  
  bool honorFieldOrder = true;
76  
  S mcDollar = actualMCDollar();
77  
  settable bool warnIfUnpersistable = true;
78  
  settable bool stackTraceIfUnpersistable = true;
79  
  
80  
  // skip a field if it has the default value defined in the class
81  
  // -slower, and may cause issues with schema evolution
82  
  // -OTOH, it can serialize null values for a field with default non-null value
83  
  settable bool skipDefaultValues;
84  
  
85  
  structure_Data d() { this; }
86  
87  
  swappable bool shouldIncludeField(Field f) { true; }
88  
89  
  new IdentityHashMap<O, Integer> seen;
90  
  //new BitSet refd;
91  
  new HashMap<S, Int> strings;
92  
  new HashSet<S> concepts;
93  
  HashMap<Class, structure_ClassInfo> infoByClass = new HashMap;
94  
  
95  
  // wrapper for _persistenceInfo field or _persistenceInfo method
96  
  // by class (taking the object instance)
97  
  new HashMap<Class, IF1<O, Map>> persistenceInfo;
98  
  
99  
  int n; // token count
100  
  new L<Runnable> stack;
101  
  
102  
  // append single token
103  
  structure_Data append(S token) { out.print(token); ++n; ret this; }
104  
  structure_Data append(int i) { out.print(i); ++n; ret this; }
105  
  
106  
  // append multiple tokens
107  
  structure_Data append(S token, int tokCount) { out.print(token); n += tokCount; ret this; }
108  
  
109  
  // extend last token
110  
  structure_Data app(S token) { out.print(token); this; }
111  
  structure_Data app(int i) { out.print(i); this; }
112  
  structure_Data app(char c) { out.print(c); this; }
113  
114  
  structure_ClassInfo infoForClass(Class c) {
115  
    structure_ClassInfo info = infoByClass.get(c);
116  
    if (info == null) info = newClass(c);
117  
    ret info;
118  
  }
119  
  
120  
  swappable S realShortName(S name) {
121  
    ret dropPrefix("main$",
122  
      dropPrefix("loadableUtils.utils$",
123  
        dropPrefix(mcDollar, name)));
124  
  }
125  
  
126  
  // called when a new class is detected
127  
  // can be overridden by clients
128  
  structure_ClassInfo newClass(Class c) {
129  
    // special classes here!
130  
    
131  
    var d = d();
132  
    bool isJavaXClass = isJavaXClassName(c.getName(), mcDollar);
133  
    printVars ifdef structure_debug("newClass", +c, +isJavaXClass);
134  
    
135  
    if (c == S)
136  
      ret new structure_ClassInfo<S> {
137  
        @Override bool handle(S o) {
138  
          S s = d.stringSizeLimit != 0 ? shorten((S) o, d.stringSizeLimit) : (S) o;
139  
          if (!d.noStringSharing) {
140  
            if (d.shareStringsLongerThan == Int.MAX_VALUE)
141  
              d.seen.put(o, d.n);
142  
            if (l(s) >= d.shareStringsLongerThan)
143  
              d.strings.put(s, d.n);
144  
          }
145  
          quoteToPrintWriter(s, d.out); d.n++;
146  
          true;
147  
        }
148  
      };
149  
150  
    
151  
    if (c == File)
152  
      ret new structure_ClassInfo<File> {
153  
        @Override bool handle(File o) {
154  
          append("File ").append(quote(o.getPath()));
155  
          true;
156  
        }
157  
      };
158  
159  
    if (!isJavaXClass) {
160  
      if (isSubClassOf(c, Set.class))
161  
        ret new structure_ClassInfo<Set> {
162  
          @Override bool handle(Set o) {
163  
            writeSet(o);
164  
            true;
165  
          }
166  
        };
167  
168  
      if (isSubClassOf(c, Cl))
169  
        ret new structure_ClassInfo<Cl> {
170  
          @Override bool handle(Cl o) {
171  
            writeCollection(o);
172  
            true;
173  
          }
174  
        };
175  
        
176  
      if (isSubClassOf(c, Map))
177  
        ret new structure_ClassInfo<Map> {
178  
          @Override bool handle(Map o) {
179  
            writeMap(o);
180  
            true;
181  
          }
182  
        };
183  
    }
184  
185  
    new structure_ClassInfo info;
186  
    info.c = c;
187  
    infoByClass.put(c, info);
188  
    
189  
    S name = c.getName();
190  
    S shortName = realShortName(name);
191  
    if (startsWithDigit(shortName)) shortName = name; // for anonymous classes
192  
    info.shortName = shortName;
193  
    
194  
    try {
195  
      if (isSyntheticOrAnonymous(c)) {
196  
        info.nullInstances(true);
197  
        ret info;
198  
      }
199  
      
200  
      if (c.isEnum()) {
201  
        info.special = true;
202  
        ret info;
203  
      }
204  
      
205  
      ifdef OurSyncCollections
206  
        if (isSubClassOf(c, SynchronizedMap))
207  
          ret new structure_ClassInfo<SynchronizedMap> {
208  
            @Override bool handle(SynchronizedMap o) {
209  
              append("sync ");
210  
              structure_1(o.m, d);
211  
              true;
212  
            }
213  
          };
214  
          
215  
        if (isSubClassOf(c, SynchronizedList))
216  
          ret new structure_ClassInfo<SynchronizedList> {
217  
            @Override bool handle(SynchronizedList o) {
218  
              append("sync ");
219  
              structure_1(unwrapSynchronizedList(o), d);
220  
              true;
221  
            }
222  
          };
223  
      endifdef
224  
225  
      if (c.isArray()) {
226  
        // info.special?
227  
        ret info;
228  
      }
229  
      
230  
      if ((info.customSerializer = findMethodNamed(c, '_serialize))
231  
        != null) info.special = true;
232  
        
233  
      if (storeBaseClasses) {
234  
        Class sup = c.getSuperclass();
235  
        if (sup != O) {
236  
          append("bc ");
237  
          append(shortDynClassNameForStructure(c));
238  
          out.print(" ");
239  
          append(shortDynClassNameForStructure(sup));
240  
          out.print(" ");
241  
          infoForClass(sup); // transitively write out superclass relations
242  
        }
243  
      }
244  
      
245  
      if (eqOneOf(name, "java.awt.Color", "java.lang.ThreadLocal"))
246  
        info.javafy(true);
247  
      else if (name.startsWith("sun") || !isPersistableClass(c)) {
248  
        info.javafy(true);
249  
        if (warnIfUnpersistable) {
250  
          S msg = "Class not persistable: " + c + " (anonymous or no default constructor), referenced from " + last(stack);
251  
          if (stackTraceIfUnpersistable)
252  
            printStackTrace(new Throwable(msg));
253  
          else
254  
            print(msg);
255  
        }
256  
      } else if (skipDefaultValues) {
257  
        var ctor = getDefaultConstructor(c);
258  
        if (ctor != null)
259  
          info.emptyInstance = invokeConstructor(ctor);
260  
      }
261  
    } catch print e {
262  
      info.nullInstances(true);
263  
    }
264  
    
265  
    ret info;
266  
  }
267  
  
268  
  void setFields(structure_ClassInfo info, L<Field> fields) { 
269  
    info.fields = fields;
270  
  }
271  
  
272  
  void writeObject(O o, S shortName, MapSO fv) {
273  
    S singleField = fv.size() == 1 ? first(fv.keySet()) : null;
274  
  
275  
    append(shortName);
276  
    n += countDots(shortName)*2; // correct token count
277  
    ifdef structure_debug
278  
      print("Fields for " + shortName + ": " + fv.keySet());
279  
    endifdef
280  
  
281  
    int l = n;
282  
    Iterator it = fv.entrySet().iterator();
283  
    
284  
    class WritingObject is Runnable {
285  
      S lastFieldWritten;
286  
      
287  
      run {
288  
        if (!it.hasNext()) {
289  
          if (n != l)
290  
            append(")");
291  
        } else {
292  
          Map.Entry e = cast it.next();
293  
          append(n == l ? "(" : ", ");
294  
          append(lastFieldWritten = (S) e.getKey()).append("=");
295  
          stack.add(this);
296  
          structure_1(e.getValue(), structure_Data.this);
297  
        }
298  
      }
299  
      
300  
      toString { ret shortName + "." + lastFieldWritten; }
301  
    }
302  
    
303  
    stack.add(new WritingObject);
304  
  }
305  
  
306  
  void writeMap(Map o) {
307  
    var d = this;
308  
    S name = o.getClass().getName();
309  
    if (o instanceof LinkedHashMap) d.append("lhm");
310  
    else if (o instanceof HashMap) d.append("hm");
311  
    else if (o cast TreeMap)
312  
      d.append(isCIMap_gen(o) ? "cimap" : "tm");
313  
    else if (name.equals("java.util.Collections$SynchronizedMap")
314  
      || name.equals("java.util.Collections$SynchronizedSortedMap")
315  
      || name.equals("java.util.Collections$SynchronizedNavigableMap")) {
316  
      d.append("sync "); 
317  
      ret with structure_1(unwrapSynchronizedMap(o/Map), d);
318  
    }
319  
    
320  
    d.append("{");
321  
    final int l = d.n;
322  
    final Iterator it = cloneMap((Map) o).entrySet().iterator();
323  
    
324  
    class WritingMap is Runnable {
325  
      bool v;
326  
      Map.Entry e;
327  
      
328  
      toString {
329  
        ret renderVars("WritingMap", e := mapEntryToPair(e), v := !v);
330  
      }
331  
      
332  
      run {
333  
        if (v) {
334  
          d.append("=");
335  
          v = false;
336  
          d.stack.add(this);
337  
          structure_1(e.getValue(), d);
338  
        } else {
339  
          if (!it.hasNext())
340  
            d.append("}");
341  
          else {
342  
            e = (Map.Entry) it.next();
343  
            v = true;
344  
            d.stack.add(this);
345  
            if (d.n != l) d.append(", ");
346  
            structure_1(e.getKey(), d);
347  
          }
348  
        }
349  
      }
350  
    }
351  
    
352  
    d.stack.add(new WritingMap);
353  
  }
354  
355  
  void writeSet(Set o) {
356  
    var d = this;
357  
    S name = o.getClass().getName();
358  
    
359  
    /*O set2 = unwrapSynchronizedSet(o);
360  
    if (set2 != o) {
361  
      d.append("sync");
362  
      o = set2;
363  
    } TODO */
364  
    
365  
    if (o instanceof TreeSet) {
366  
      d.append(isCISet_gen(o) ? "ciset" : "treeset");
367  
      structure_1(new ArrayList(o), d);
368  
      ret;
369  
    }
370  
    
371  
    // assume it's a HashSet or LinkedHashSet
372  
    d.append(o instanceof LinkedHashSet ? "lhs" : "hashset");
373  
    structure_1(new ArrayList(o), d);
374  
  }
375  
376  
  void writeCollection(Cl o) {
377  
    var d = this;
378  
    S name = o.getClass().getName();
379  
    
380  
    print ifdef structure_debug("writeCollection", name);
381  
    
382  
    if (name.equals("java.util.Collections$SynchronizedList")
383  
      || name.equals("java.util.Collections$SynchronizedRandomAccessList")) {
384  
      d.append("sync ");
385  
      ret with structure_1(unwrapSynchronizedList(o/List), d);
386  
    }
387  
    else if (name.equals("java.util.LinkedList"))
388  
      d.append("ll");
389  
    d.append("[");
390  
    int l = d.n;
391  
    Iterator it = cloneList(o).iterator();
392  
    d.stack.add(r {
393  
      if (!it.hasNext())
394  
        d.append("]");
395  
      else {
396  
        d.stack.add(this);
397  
        if (d.n != l) d.append(", ");
398  
        structure_1(it.next(), d);
399  
      }
400  
    });
401  
  }
402  
} // end of class structure_Data
403  
404  
svoid structure_1(O o, structure_Data d) ctex {
405  
  if (o == null) { d.append("null"); ret; }
406  
  
407  
  Class c = o.getClass();
408  
  bool concept = false;
409  
  ifclass Concept
410  
    concept = o instanceof Concept;
411  
  endif
412  
  structure_ClassInfo info = d.infoForClass(c);
413  
  
414  
  print ifdef structure_debug("structure_1 " + c);
415  
416  
  bool isJavaXName = isJavaXClassName(c.getName(), d.mcDollar);
417  
  
418  
  bool referencable = isJavaXName &&
419  
    !(o instanceof Number || o instanceof Char || o instanceof Bool)
420  
    || o instanceof Cl || o instanceof Map
421  
    || o instanceof Rectangle;
422  
    
423  
  printVars ifdef structure_debug(+isJavaXName, +referencable, mcDollar := d.mcDollar);
424  
  
425  
  if (referencable) {
426  
    Int ref = d.seen.get(o);
427  
    if (ref != null) {
428  
      print ifdef structure_debug("Existing reference " + className(o) + " " + ref);
429  
      //d.refd.set(ref);
430  
      d.append("t").app(ref);
431  
      ret;
432  
    }
433  
    
434  
    d.seen.put(o, d.n); // record token number
435  
    print ifdef structure_debug("Recorded reference " + d.n);
436  
  }
437  
      
438  
  if (info.handle(o)) {
439  
    print ifdef structure_debug("handled by " + className(info));
440  
    ret;
441  
  }
442  
  
443  
  if (info.special) {
444  
    if (info.javafy) {
445  
      d.append("j ").append(quote(str(o))); ret; // This is not unstructure-able except for java.awt.Color
446  
    }
447  
    
448  
    if (c.isEnum()) {
449  
      d.append("enum ");
450  
      d.append(info.shortName);
451  
      d.out.append(' ');
452  
      d.append(((Enum) o).ordinal());
453  
      ret;
454  
    }
455  
    
456  
    if (info.customSerializer != null) {
457  
      // custom serialization (_serialize method)
458  
      O o2 = invokeMethod(info.customSerializer, o);
459  
      if (o2 == o) {} // bail out to standard serialization
460  
      else {
461  
        d.append("cu ");
462  
        S name = c.getName();
463  
        S shortName = d.realShortName(name);
464  
        d.append(shortName);
465  
        d.out.append(' ');
466  
        structure_1(o2, d);
467  
        ret;
468  
      }
469  
    } else if (info.nullInstances) ret with d.append("null");
470  
    else if (info.serializeObject != null)
471  
      ret with info.serializeObject.get(o);
472  
    else fail("unknown special type");
473  
  }
474  
    
475  
  L<Field> lFields = info.fields;
476  
  if (lFields == null) {
477  
    // these are never back-referenced (for readability)
478  
    
479  
    if (o instanceof Number) {
480  
      PrintWriter out = d.out;
481  
if (o instanceof Integer) { int i = ((Int) o).intValue(); out.print(i); d.n += i < 0 ? 2 : 1; ret; }
482  
      if (o instanceof Long) { long l = ((Long) o).longValue(); out.print(l); out.print("L"); d.n += l < 0 ? 2 : 1; ret; }
483  
      if (o cast Short) { short s = o.shortValue(); d.append("sh "); out.print(s); d.n += s < 0 ? 2 : 1; ret; }
484  
      if (o instanceof Float) { d.append("fl ", 2); quoteToPrintWriter(str(o), out); ret; }
485  
      if (o instanceof Double) { d.append("d(", 3); quoteToPrintWriter(str(o), out); d.append(")"); ret; }
486  
      if (o instanceof BigInteger) { out.print("bigint("); out.print(o); out.print(")"); d.n += ((BigInteger) o).signum() < 0 ? 5 : 4; ret; }
487  
    }
488  
  
489  
    if (o instanceof Boolean) {
490  
      d.append(((Boolean) o).booleanValue() ? "t" : "f"); ret;
491  
    }
492  
      
493  
    if (o instanceof Character) {
494  
      d.append(quoteCharacter((Character) o)); ret;
495  
    }
496  
      
497  
    S name = c.getName();
498  
    
499  
    if (!isJavaXName) {
500  
      if (o cast Set)
501  
        ret with d.writeSet(o);
502  
      
503  
      if (o cast Cl
504  
        /* && neq(name, "main$Concept$RefL") */) {
505  
        
506  
        ret with d.writeCollection(o);
507  
      }
508  
    
509  
      if (o cast Map)
510  
        ret with d.writeMap(o);
511  
    }
512  
    
513  
    if (c.isArray()) {
514  
      if (o instanceof byte[]) {
515  
        d.append("ba ").append(quote(bytesToHex((byte[]) o))); ret;
516  
      }
517  
  
518  
      final int n = Array.getLength(o);
519  
  
520  
      if (o instanceof bool[]) {
521  
        S hex = boolArrayToHex((bool[]) o);
522  
        int i = l(hex);
523  
        while (i > 0 && hex.charAt(i-1) == '0' && hex.charAt(i-2) == '0') i -= 2;
524  
        d.append("boolarray ").append(n).app(" ").append(quote(substring(hex, 0, i))); ret;
525  
      }
526  
      
527  
      if (o cast short[]) {
528  
        S hex = shortArrayToHex_bigEndian(o);
529  
        d.append("shortarray \"").append(hex).app('\"');
530  
        ret;
531  
      }
532  
      
533  
      if (o cast long[]) {
534  
        S hex = longArrayToHex_bigEndian(o);
535  
        d.append("longarray \"").append(hex).app('\"');
536  
        ret;
537  
      }
538  
      
539  
      S atype = "array"/*, sep = ", "*/; // sep is not used yet
540  
  
541  
      if (o instanceof int[]) {
542  
        //ret "intarray " + quote(intArrayToHex((int[]) o));
543  
        atype = "intarray";
544  
        //sep = " ";
545  
      } else if (o instanceof double[]) {
546  
        atype = "dblarray";
547  
        //sep = " ";
548  
      } else if (o instanceof float[]) {
549  
        atype = "floatarray";
550  
      } else {
551  
        // 2-dimensional and deeper arrays
552  
        Pair<Class, Int> p = arrayTypeAndDimensions(c);
553  
        if (p.a == int.class) atype = "intarray";
554  
        else if (p.a == byte.class) atype = "bytearray";
555  
        else if (p.a == bool.class) atype = "boolarray";
556  
        else if (p.a == double.class) atype = "dblarray";
557  
        else if (p.a == float.class) atype = "floatarray";
558  
        else if (p.a == S) { atype = "array S"; d.n++; }
559  
        else atype = "array"; // fail("Unsupported array type: " + p.a);
560  
        if (p.b > 1) {
561  
          atype += "/" + p.b; // add number of dimensions
562  
          d.n += 2; // 2 additional tokens will be written
563  
        }
564  
      }
565  
      
566  
      d.append(atype).append("{");
567  
      d.stack.add(new Runnable() {
568  
        int i;
569  
        public void run() {
570  
          if (i >= n)
571  
            d.append("}");
572  
          else {
573  
            d.stack.add(this);
574  
            if (i > 0) d.append(", ");
575  
            structure_1(Array.get(o, i++), d);
576  
          }
577  
        }
578  
      });
579  
      ret;
580  
    }
581  
  
582  
    if (o instanceof Class) {
583  
      d.append("class(", 2).append(quote(((Class) o).getName())).append(")"); ret;
584  
    }
585  
      
586  
    if (o instanceof Throwable) {
587  
      d.append("exception(", 2).append(quote(((Throwable) o).getMessage())).append(")"); ret;
588  
    }
589  
      
590  
    if (o instanceof BitSet) {
591  
      BitSet bs = (BitSet) o;
592  
      d.append("bitset{", 2);
593  
      int l = d.n;
594  
      for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
595  
        if (d.n != l) d.append(", ");
596  
        d.append(i);
597  
      }
598  
      d.append("}"); ret;
599  
    }
600  
      
601  
    ifclass Lisp
602  
      if (o instanceof Lisp) {
603  
        d.append("l(", 2);
604  
        final Lisp lisp = cast o;
605  
        structure_1(lisp.head, d);
606  
        final Iterator it = lisp.args == null ? emptyIterator() : lisp.args.iterator();
607  
        d.stack.add(r {
608  
          if (!it.hasNext())
609  
            d.append(")");
610  
          else {
611  
            d.stack.add(this);
612  
            d.append(", ");
613  
            structure_1(it.next(), d);
614  
          }
615  
        });
616  
        ret;
617  
      }
618  
    endif
619  
      
620  
    /*if (name.equals("main$Lisp")) {
621  
      fail("lisp not supported right now");
622  
    }*/
623  
    
624  
    S dynName = shortDynClassNameForStructure(o);
625  
    if (concept && !d.concepts.contains(dynName)) {
626  
      d.concepts.add(dynName);
627  
      d.append("c ");
628  
    }
629  
    
630  
    // serialize an object with fields.
631  
    // first, collect all fields and values in fv.
632  
    
633  
    TreeSet<Field> fields = new TreeSet<Field>(new Comparator<Field>() {
634  
      public int compare(Field a, Field b) {
635  
        ret stdcompare(a.getName(), b.getName());
636  
      }
637  
    });
638  
    
639  
    Class cc = c;
640  
    while (cc != O.class) {
641  
      for (Field field : getDeclaredFields_cached(cc)) {
642  
        if (!d.shouldIncludeField(field)) continue;
643  
        
644  
        S fieldName = field.getName();
645  
        if (fieldName.equals("_persistenceInfo"))
646  
          d.persistenceInfo.put(c, obj -> (Map) fieldGet(field, obj));
647  
        if ((field.getModifiers() & (java.lang.reflect.Modifier.STATIC | java.lang.reflect.Modifier.TRANSIENT)) != 0)
648  
          continue;
649  
650  
        fields.add(field);
651  
        
652  
        // put special cases here...?
653  
      }
654  
        
655  
      cc = cc.getSuperclass();
656  
    }
657  
    
658  
    Method persistenceInfoMethod = findInstanceMethod(c, "_persistenceInfo");
659  
    if (persistenceInfoMethod != null)
660  
      d.persistenceInfo.put(c, obj -> (Map) invokeMethod(persistenceInfoMethod, obj));
661  
    
662  
    lFields = asList(d.honorFieldOrder ? fieldObjectsInFieldOrder(c, fields) : fields);
663  
664  
    // Render this$0/this$1 first because unstructure needs it for constructor call.
665  
    
666  
    int n = l(lFields);
667  
    for (int i = 0; i < n; i++) {
668  
      Field f = lFields.get(i);
669  
      if (f.getName().startsWith("this$")) {
670  
        lFields.remove(i);
671  
        lFields.add(0, f);
672  
        break;
673  
      }
674  
    }
675  
  
676  
    ifdef structure_debug
677  
      print("Saving fields for " + c + ": " + lFields);
678  
    endifdef
679  
    d.setFields(info, lFields);
680  
  } // << if (lFields == null)
681  
682  
  // get _persistenceInfo from field and/or dynamic field
683  
  IF1<O, Map> piGetter = d.persistenceInfo.get(c);
684  
  Map persistenceInfo = piGetter?.get(o);
685  
  
686  
  if (piGetter == null && o instanceof DynamicObject)
687  
    persistenceInfo = (Map) getOptDynOnly(o/DynamicObject, "_persistenceInfo");
688  
689  
  ifdef structure_debug
690  
    print("persistenceInfo for " + c + ": " + persistenceInfo);
691  
  endifdef
692  
  new LinkedHashMap<S, O> fv;
693  
  O defaultInstance = info.emptyInstance;
694  
  if (!referencable)
695  
    fail("Not referencable: " + className(o));
696  
    
697  
  for (Field f : lFields) {
698  
    O value, defaultValue = null;
699  
    try {
700  
      value = f.get(o);
701  
      defaultValue = defaultInstance == null ?: f.get(defaultInstance);
702  
    } catch (Exception e) {
703  
      value = "?";
704  
    }
705  
      
706  
    if (!eq(defaultValue, value) && (persistenceInfo == null
707  
      || !Boolean.FALSE.equals(persistenceInfo.get(f.getName()))))
708  
      fv.put(f.getName(), value);
709  
      
710  
    ifdef structure_debug
711  
      else print("Skipping default value " + defaultValue + " of " + f.getName() + " for " + identityHashCode(o));
712  
    endifdef
713  
  }
714  
  
715  
  S shortName = info.shortName;
716  
    
717  
  // Now we have fields & values. Process fieldValues if it's a DynamicObject.
718  
  
719  
  O classNameFromFV = fv.get("className");
720  
  
721  
  // omit field "className" if equal to class's name
722  
  if (concept && eq(classNameFromFV, shortName))
723  
    fv.remove("className");
724  
          
725  
  if (o cast DynamicObject) {
726  
    putAll(fv, (Map) fv.get("fieldValues"));
727  
    fv.remove("fieldValues");
728  
    if (o.className != null) {
729  
      // TODO: this probably doesn't work with inner classes
730  
      
731  
      shortName = shortDynClassNameForStructure(o);
732  
      fv.remove("className");
733  
      
734  
      // special handling for missing Class objects encoded as DynamicObject
735  
      if (eq(shortName, "java.lang.Class")) {
736  
        d.append("class(");
737  
        d.append(quoted(fv.get("name")));
738  
        d.append(")");
739  
        ret;
740  
      }
741  
    }
742  
  }
743  
  
744  
  d.writeObject(o, shortName, fv);
745  
}

Author comment

Began life as a copy of #1034594

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj, wnsclhtenguj

No comments. add comment

Snippet ID: #1034648
Snippet name: structure function (v21, supporting enums, LIVE)
Eternal ID of this version: #1034648/83
Text MD5: 91e56b46a8a9f58de7616f92d46bd6f1
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2023-05-13 02:03:02
Source code size: 22431 bytes / 745 lines
Pitched / IR pitched: No / No
Views / Downloads: 456 / 979
Version history: 82 change(s)
Referenced in: [show references]