1313
1414import java .io .UnsupportedEncodingException ;
1515import java .lang .reflect .Array ;
16- import java .lang .reflect .Constructor ;
1716import java .lang .reflect .Field ;
1817import java .lang .reflect .Modifier ;
1918import java .lang .reflect .ParameterizedType ;
@@ -47,12 +46,13 @@ public class SimpleSerializable implements Cloneable {
4746
4847 public static boolean JSON_EXPAND_MODE = true ;
4948
49+ @ J2SIgnore
50+ private static Object mutex = new Object ();
5051 @ J2SIgnore
5152 private static Map <String , Map <String , Field >> quickFields = new HashMap <String , Map <String , Field >>();
52-
5353 @ J2SIgnore
54- private static Map <String , Constructor <?>> quickConstructors = new HashMap <String , Constructor <?> >();
55-
54+ private static Set <String > expiredClasses = new HashSet <String >();
55+
5656 @ J2SIgnore
5757 private static class DeserializeObject {
5858 Object object ;
@@ -69,11 +69,20 @@ public DeserializeObject(Object object, int index, boolean error) {
6969 };
7070
7171 @ J2SIgnore
72- Map <String , Field > getSerializableFields (String clazzName ) {
73- Map <String , Field > fields = quickFields .get (clazzName );
72+ static Map <String , Field > getSerializableFields (String clazzName , Class <?> clazz , boolean forceUpdate ) {
73+ Map <String , Field > fields = forceUpdate ? null : quickFields .get (clazzName );
7474 if (fields == null ) {
75+ if (!forceUpdate ) {
76+ if (expiredClasses .contains (clazzName )) {
77+ // Load class from bytes. Variable clazz may be out of date
78+ Object inst = SimpleClassLoader .loadSimpleInstance (clazzName );
79+ if (inst != null ) {
80+ // Force updating fields in cache
81+ return getSerializableFields (clazzName , inst .getClass (), true );
82+ }
83+ }
84+ }
7585 fields = new HashMap <String , Field >();
76- Class <?> clazz = this .getClass ();
7786 while (clazz != null && !"net.sf.j2s.ajax.SimpleSerializable" .equals (clazz .getName ())) {
7887 Field [] clazzFields = clazz .getDeclaredFields ();
7988 for (int i = 0 ; i < clazzFields .length ; i ++) {
@@ -86,8 +95,20 @@ Map<String, Field> getSerializableFields(String clazzName) {
8695 }
8796 clazz = clazz .getSuperclass ();
8897 }
89- synchronized (quickFields ) {
90- quickFields .put (clazzName , fields );
98+ synchronized (mutex ) {
99+ if (!forceUpdate ) {
100+ if (expiredClasses .contains (clazzName )) {
101+ // Class already be reloaded. Do not put fields into cache.
102+ return fields ;
103+ }
104+ }
105+ if (forceUpdate || quickFields .get (clazzName ) == null ) {
106+ quickFields .put (clazzName , fields );
107+ if (forceUpdate ) {
108+ // Class and fields are already updated, mark it as updated
109+ expiredClasses .remove (clazzName );
110+ }
111+ }
91112 }
92113 }
93114 return fields ;
@@ -371,7 +392,7 @@ private String serialize(SimpleFilter filter, List<SimpleSerializable> ssObjs) {
371392 buffer .append ("#00000000$" ); // later the number of size will be updated!
372393 int headSize = buffer .length ();
373394
374- Map <String , Field > fields = getSerializableFields (clazzName );
395+ Map <String , Field > fields = getSerializableFields (clazzName , this . getClass (), false );
375396 boolean ignoring = (filter == null || filter .ignoreDefaultFields ());
376397 String [] fMap = fieldMapping ();
377398 try {
@@ -1187,7 +1208,8 @@ private String jsonSerialize(SimpleFilter filter, List<SimpleSerializable> ssObj
11871208 }
11881209 boolean commasAppended = false ;
11891210 boolean ignoring = (filter == null || filter .ignoreDefaultFields ());
1190- Map <String , Field > fieldMap = getSerializableFields (this .getClass ().getName ());
1211+ Class <?> clazzType = this .getClass ();
1212+ Map <String , Field > fieldMap = getSerializableFields (clazzType .getName (), clazzType , false );
11911213 String [] fMap = fieldMapping ();
11921214 for (Iterator <String > itr = fieldMap .keySet ().iterator (); itr .hasNext ();) {
11931215 String fieldName = (String ) itr .next ();
@@ -1945,7 +1967,8 @@ private boolean deserialize(final String str, int start, List<SimpleSerializable
19451967 if (index + size > end ) return false ;
19461968 }
19471969
1948- Map <String , Field > fieldMap = getSerializableFields (this .getClass ().getName ());
1970+ Class <?> clazzType = this .getClass ();
1971+ Map <String , Field > fieldMap = getSerializableFields (clazzType .getName (), clazzType , false );
19491972 int objectEnd = index + size ;
19501973 String [] fMap = fieldMapping ();
19511974 while (index < end && index < objectEnd ) {
@@ -2616,28 +2639,21 @@ private DeserializeObject deserializeArrayItem(String str, int index, int end, L
26162639
26172640 @ J2SIgnore
26182641 public static SimpleSerializable parseInstance (Map <String , Object > properties ) {
2619- Class <?> runnableClass = null ;
26202642 String clazzName = (String )properties .get ("class" );
2621- try {
2622- runnableClass = Class .forName (clazzName ); // !!! JavaScript loading!
2623- if (runnableClass != null ) {
2624- // SimpleRPCRunnale should always has default constructor
2625- Constructor <?> constructor = runnableClass .getConstructor (new Class [0 ]);
2626- Object obj = constructor .newInstance (new Object [0 ]);
2627- if (obj != null && obj instanceof SimpleSerializable ) {
2628- return (SimpleSerializable ) obj ;
2629- }
2630- }
2631- } catch (Exception e ) {
2632- e .printStackTrace ();
2643+ if (clazzName == null ) {
2644+ return null ;
26332645 }
2634- return null ;
2646+ Object inst = SimpleClassLoader .loadSimpleInstance (clazzName );
2647+ if (inst != null && inst instanceof SimpleSerializable ) {
2648+ return (SimpleSerializable ) inst ;
2649+ }
2650+ return UNKNOWN ;
26352651 }
26362652
26372653 @ J2SIgnore
26382654 public void deserialize (Map <String , Object > properties ) {
26392655 String clazzName = (String ) properties .get ("class" );
2640- Map <String , Field > fieldMap = getSerializableFields (clazzName );
2656+ Map <String , Field > fieldMap = getSerializableFields (clazzName , this . getClass (), false );
26412657 String [] fMap = fieldMapping ();
26422658 for (Iterator <String > itr = properties .keySet ().iterator (); itr .hasNext ();) {
26432659 String fieldName = (String ) itr .next ();
@@ -2853,7 +2869,8 @@ protected boolean bytesCompactMode() {
28532869 public Object clone () throws CloneNotSupportedException {
28542870 Object clone = super .clone ();
28552871
2856- Map <String , Field > fields = this .getSerializableFields (this .getClass ().getName ());
2872+ Class <? extends SimpleSerializable > clazz = this .getClass ();
2873+ Map <String , Field > fields = getSerializableFields (clazz .getName (), clazz , false );
28572874 for (Iterator <Field > itr = fields .values ().iterator (); itr .hasNext ();) {
28582875 Field field = (Field ) itr .next ();
28592876 Class <?> type = field .getType ();
@@ -2980,27 +2997,20 @@ public static SimpleSerializable parseInstance(String str, int start, SimpleFilt
29802997 if (filter != null ) {
29812998 if (!filter .accept (clazzName )) return null ;
29822999 }
2983- try {
2984- Constructor <?> constructor = quickConstructors .get (clazzName );
2985- if (constructor == null ) {
2986- Class <?> runnableClass = Class .forName (clazzName );
2987- if (runnableClass != null ) {
2988- // SimpleRPCRunnale should always has a default constructor
2989- constructor = runnableClass .getConstructor (new Class [0 ]);
2990- synchronized (quickConstructors ) {
2991- quickConstructors .put (clazzName , constructor );
2992- }
2993- }
2994- }
2995- if (constructor != null ) {
2996- Object obj = constructor .newInstance (new Object [0 ]);
2997- if (obj != null && obj instanceof SimpleSerializable ) {
2998- return (SimpleSerializable ) obj ;
2999- }
3000- }
3001- } catch (Exception e ) {
3002- e .printStackTrace ();
3000+ Object inst = SimpleClassLoader .loadSimpleInstance (clazzName );
3001+ if (inst != null && inst instanceof SimpleSerializable ) {
3002+ return (SimpleSerializable ) inst ;
30033003 }
30043004 return UNKNOWN ;
30053005 }
3006+
3007+ @ J2SIgnore
3008+ static void removeCachedClassFields (String clazzName ) {
3009+ synchronized (mutex ) {
3010+ // Will force update cached fields in next time retrieving fields
3011+ quickFields .remove (clazzName );
3012+ expiredClasses .add (clazzName );
3013+ }
3014+ }
3015+
30063016}
0 commit comments