1212import org .json .JSONException ;
1313import org .json .JSONObject ;
1414
15- import java .lang .reflect .Member ;
16- import java .lang .reflect .Modifier ;
1715import java .util .ArrayList ;
1816import java .util .Arrays ;
1917import java .util .Collection ;
2927import java .util .Map ;
3028import java .util .Set ;
3129import java .util .concurrent .Callable ;
32- import java .util .concurrent .ConcurrentHashMap ;
3330import java .util .concurrent .atomic .AtomicBoolean ;
3431import java .util .concurrent .locks .Lock ;
3532
@@ -72,11 +69,6 @@ public class ParseObject {
7269 // and not check after a while
7370 private static final String KEY_IS_DELETING_EVENTUALLY_OLD = "isDeletingEventually" ;
7471
75- private static final Map <Class <? extends ParseObject >, String > classNames =
76- new ConcurrentHashMap <>();
77- private static final Map <String , Class <? extends ParseObject >> objectTypes =
78- new ConcurrentHashMap <>();
79-
8072 private static ParseObjectController getObjectController () {
8173 return ParseCorePlugins .getInstance ().getObjectController ();
8274 }
@@ -85,6 +77,10 @@ private static LocalIdManager getLocalIdManager() {
8577 return ParseCorePlugins .getInstance ().getLocalIdManager ();
8678 }
8779
80+ private static ParseObjectSubclassingController getSubclassingController () {
81+ return ParseCorePlugins .getInstance ().getSubclassingController ();
82+ }
83+
8884 /** package */ static class State {
8985
9086 public static Init <?> newBuilder (String className ) {
@@ -360,23 +356,15 @@ public ParseObject(String theClassName) {
360356 "You must specify a Parse class name when creating a new ParseObject." );
361357 }
362358 if (AUTO_CLASS_NAME .equals (theClassName )) {
363- theClassName = getClassName ( this . getClass ());
359+ theClassName = getSubclassingController (). getClassName ( getClass ());
364360 }
365361
366362 // If this is supposed to be created by a factory but wasn't, throw an exception.
367- if (this .getClass ().equals (ParseObject .class ) && objectTypes .containsKey (theClassName )
368- && !objectTypes .get (theClassName ).isInstance (this )) {
363+ if (!getSubclassingController ().isSubclassValid (theClassName , getClass ())) {
369364 throw new IllegalArgumentException (
370365 "You must create this type of ParseObject using ParseObject.create() or the proper subclass." );
371366 }
372367
373- // If this is an unregistered subclass, throw an exception.
374- if (!this .getClass ().equals (ParseObject .class )
375- && !this .getClass ().equals (objectTypes .get (theClassName ))) {
376- throw new IllegalArgumentException (
377- "You must register this ParseObject subclass before instantiating it." );
378- }
379-
380368 operationSetQueue = new LinkedList <>();
381369 operationSetQueue .add (new ParseOperationSet ());
382370 estimatedData = new HashMap <>();
@@ -410,17 +398,7 @@ public ParseObject(String theClassName) {
410398 * @return A new {@code ParseObject} for the given class name.
411399 */
412400 public static ParseObject create (String className ) {
413- if (objectTypes .containsKey (className )) {
414- try {
415- return objectTypes .get (className ).newInstance ();
416- } catch (Exception e ) {
417- if (e instanceof RuntimeException ) {
418- throw (RuntimeException ) e ;
419- }
420- throw new RuntimeException ("Failed to create instance of subclass." , e );
421- }
422- }
423- return new ParseObject (className );
401+ return getSubclassingController ().newInstance (className );
424402 }
425403
426404 /**
@@ -434,7 +412,7 @@ public static ParseObject create(String className) {
434412 */
435413 @ SuppressWarnings ("unchecked" )
436414 public static <T extends ParseObject > T create (Class <T > subclass ) {
437- return (T ) create (getClassName (subclass ));
415+ return (T ) create (getSubclassingController (). getClassName (subclass ));
438416 }
439417
440418 /**
@@ -497,13 +475,7 @@ public static ParseObject createWithoutData(String className, String objectId) {
497475 */
498476 @ SuppressWarnings ({"unused" , "unchecked" })
499477 public static <T extends ParseObject > T createWithoutData (Class <T > subclass , String objectId ) {
500- return (T ) createWithoutData (getClassName (subclass ), objectId );
501- }
502-
503- private static boolean isAccessible (Member m ) {
504- return Modifier .isPublic (m .getModifiers ())
505- || (m .getDeclaringClass ().getPackage ().getName ().equals ("com.parse" )
506- && !Modifier .isPrivate (m .getModifiers ()) && !Modifier .isProtected (m .getModifiers ()));
478+ return (T ) createWithoutData (getSubclassingController ().getClassName (subclass ), objectId );
507479 }
508480
509481 /**
@@ -515,41 +487,11 @@ private static boolean isAccessible(Member m) {
515487 * The subclass type to register.
516488 */
517489 public static void registerSubclass (Class <? extends ParseObject > subclass ) {
518- String className = getClassName (subclass );
519- if (className == null ) {
520- throw new IllegalArgumentException ("No ParseClassName annotation provided on " + subclass );
521- }
522- if (subclass .getDeclaredConstructors ().length > 0 ) {
523- try {
524- if (!isAccessible (subclass .getDeclaredConstructor ())) {
525- throw new IllegalArgumentException ("Default constructor for " + subclass
526- + " is not accessible." );
527- }
528- } catch (NoSuchMethodException e ) {
529- throw new IllegalArgumentException ("No default constructor provided for " + subclass );
530- }
531- }
532- Class <? extends ParseObject > oldValue = objectTypes .get (className );
533- if (oldValue != null && subclass .isAssignableFrom (oldValue )) {
534- // The old class was already more descendant than the new subclass type. No-op.
535- return ;
536- }
537- objectTypes .put (className , subclass );
538- if (oldValue != null && !subclass .equals (oldValue )) {
539- if (className .equals (getClassName (ParseUser .class ))) {
540- ParseUser .getCurrentUserController ().clearFromMemory ();
541- } else if (className .equals (getClassName (ParseInstallation .class ))) {
542- ParseInstallation .getCurrentInstallationController ().clearFromMemory ();
543- }
544- }
490+ getSubclassingController ().registerSubclass (subclass );
545491 }
546492
547493 /* package for tests */ static void unregisterSubclass (Class <? extends ParseObject > subclass ) {
548- unregisterSubclass (getClassName (subclass ));
549- }
550-
551- /* package for tests */ static void unregisterSubclass (String className ) {
552- objectTypes .remove (className );
494+ getSubclassingController ().unregisterSubclass (subclass );
553495 }
554496
555497 /**
@@ -3516,26 +3458,6 @@ public boolean hasSameId(ParseObject other) {
35163458 }
35173459 }
35183460
3519- /**
3520- * Gets the class name based on the {@link ParseClassName} annotation associated with a class.
3521- *
3522- * @param clazz
3523- * The class to inspect.
3524- * @return The name of the Parse class, if one is provided. Otherwise, {@code null}.
3525- */
3526- static String getClassName (Class <? extends ParseObject > clazz ) {
3527- String name = classNames .get (clazz );
3528- if (name == null ) {
3529- ParseClassName info = clazz .getAnnotation (ParseClassName .class );
3530- if (info == null ) {
3531- return null ;
3532- }
3533- name = info .value ();
3534- classNames .put (clazz , name );
3535- }
3536- return name ;
3537- }
3538-
35393461 /**
35403462 * Called when a non-pointer is being created to allow additional initialization to occur.
35413463 */
0 commit comments