11/*
2- * JSONObject class. MIT (c) 2022 miktim@mail.ru
2+ * JSONObject abstract class. MIT (c) 2022 miktim@mail.ru
3+ *
4+ * Unloads/loads Java object accessible fields to/from JSON object.
5+ * - Java final, interface, abstract, transient, strict fields are ignored;
6+ * - see JSON set/get/cast rules for Java object fields in the notes for JSON object
7+ * and JSONAdapter.
8+ *
9+ * Created: april 2022
310 */
411package org .miktim .json ;
512
613import java .lang .reflect .Field ;
714import java .lang .reflect .Modifier ;
815import java .util .Arrays ;
16+ import java .util .LinkedHashMap ;
917
1018public abstract class JSONObject {
1119
@@ -46,31 +54,32 @@ public static boolean isClassName(String fldName) {
4654 return true ;
4755 }
4856
49- private String [] _ignoredFields = new String []{};//
57+ private String [] ignoredFields = new String []{};//
5058
51- protected boolean isIgnored (String fldName ) {
52- return Arrays .binarySearch (_ignoredFields , fldName ) >= 0 ;
59+ protected final boolean isIgnored (String fldName ) {
60+ return Arrays .binarySearch (ignoredFields , fldName ) >= 0 ;
5361 }
5462
5563 protected void setIgnored (String [] fldNames ) {
56- _ignoredFields = fldNames .clone ();
57- Arrays .sort (_ignoredFields );
64+ ignoredFields = fldNames .clone ();
65+ Arrays .sort (ignoredFields );
5866 }
5967
6068 protected String [] getIgnored () {
61- return _ignoredFields ;
69+ return ignoredFields ;
6270 }
6371
6472 private Object toJSON (JSONObject jsonObj ) // returns Object
6573 throws IllegalArgumentException , IllegalAccessException {
6674 String name = jsonObj .getClass ().getName ();
6775 Object json = jsonObj .replacer (name , new JSON ());
6876 if (json instanceof JSON ) {
69- Field [] fields = jsonObj .getClass ().getDeclaredFields ();
70- // Field[] fields = getFields (jsonObj);
77+ // Field[] fields = jsonObj.getClass().getDeclaredFields();
78+ Field [] fields = getAccessibleFields (jsonObj );
7179 for (Field field : fields ) {
72- if (!jsonObj .isIgnored (field )) {
73- name = field .getName ();
80+ name = field .getName ();
81+ // if (!jsonObj.isIgnored(field)) {
82+ if (!jsonObj .isIgnored (name )) {
7483 field .setAccessible (true );
7584 Object value = jsonObj .replacer (name , field .get (jsonObj ));
7685 if (value == null || !value .equals (IGNORED )) {
@@ -90,11 +99,12 @@ private JSONObject fromJSON(JSONObject jsonObj, Object json)
9099 String name = jsonObj .getClass ().getName ();
91100 json = jsonObj .reviver (name , json );
92101 if (json instanceof JSON ) {
93- Field [] fields = jsonObj .getClass ().getDeclaredFields ();
94- // Field[] fields = getFields (jsonObj);
102+ // Field[] fields = jsonObj.getClass().getDeclaredFields();
103+ Field [] fields = getAccessibleFields (jsonObj );
95104 for (Field field : fields ) {
96105 name = field .getName ();
97- if (!jsonObj .isIgnored (field ) && ((JSON ) json ).exists (name )) {
106+ // if (!jsonObj.isIgnored(field) && ((JSON) json).exists(name)) {
107+ if (!jsonObj .isIgnored (name ) && ((JSON ) json ).exists (name )) {
98108 field .setAccessible (true );
99109 Object newValue = jsonObj .reviver (name , ((JSON ) json ).get (name ));
100110 Object value = field .get (jsonObj );
@@ -112,10 +122,35 @@ private JSONObject fromJSON(JSONObject jsonObj, Object json)
112122 return jsonObj ;
113123 }
114124
125+ /*
115126 private boolean isIgnored(Field field) {
116127 return field.isSynthetic() || field.isEnumConstant() //|| field.isAccessible() deprecated
117128 || isIgnored(field.getName())
118129 || (field.getModifiers() & Modifier.FINAL) != 0;
130+ }*/
131+
132+ private Field [] getAccessibleFields (Object obj ) {
133+ LinkedHashMap <String , Field > accessibleFields = new LinkedHashMap <>();
134+ Class cls = obj .getClass ();
135+ Package pkg = cls .getPackage ();
136+ int ignore = Modifier .FINAL | Modifier .TRANSIENT | Modifier .STRICT
137+ | Modifier .INTERFACE | Modifier .ABSTRACT ;
138+ while (cls != null ) {
139+ Field [] fields = cls .getDeclaredFields ();
140+ // for different package ignore NATIVE
141+ int ignored = ignore | (pkg != cls .getPackage () ? Modifier .NATIVE : 0 );
142+ for (Field field : fields ) {
143+ String name = field .getName ();
144+ if (!accessibleFields .containsKey (name )
145+ && (field .getModifiers () & ignored ) == 0 ) {
146+ accessibleFields .put (name , field );
147+ }
148+ }
149+ // for all super classes disable PRIVATE
150+ ignore |= Modifier .PRIVATE ;
151+ cls = cls .getSuperclass ();
152+ }
153+ return accessibleFields .values ().toArray (new Field []{});
119154 }
120155
121156}
0 commit comments