You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by ah...@apache.org on 2018/10/26 19:45:06 UTC

[royale-asjs] branch develop updated: get ObjectUtil working well enough in JS to allow HTTPService to work again

This is an automated email from the ASF dual-hosted git repository.

aharui pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git


The following commit(s) were added to refs/heads/develop by this push:
     new cf7cb3d  get ObjectUtil working well enough in JS to allow HTTPService to work again
cf7cb3d is described below

commit cf7cb3daea3d8f811860d90ad5482af38d291929
Author: Alex Harui <ah...@apache.org>
AuthorDate: Fri Oct 26 12:44:40 2018 -0700

    get ObjectUtil working well enough in JS to allow HTTPService to work again
---
 .../royale/org/apache/royale/utils/Language.as     |  57 +++
 .../src/main/royale/mx/utils/ObjectUtil.as         | 416 ++++++++++++++++++++-
 .../org/apache/royale/reflection/TypeDefinition.as |   1 +
 .../org/apache/royale/reflection/describeType.as   |   2 +-
 .../royale/reflection/getQualifiedClassName.as     |   2 +-
 5 files changed, 472 insertions(+), 6 deletions(-)

diff --git a/frameworks/projects/Language/src/main/royale/org/apache/royale/utils/Language.as b/frameworks/projects/Language/src/main/royale/org/apache/royale/utils/Language.as
index 382cdc7..21e6b93 100644
--- a/frameworks/projects/Language/src/main/royale/org/apache/royale/utils/Language.as
+++ b/frameworks/projects/Language/src/main/royale/org/apache/royale/utils/Language.as
@@ -290,6 +290,63 @@ package org.apache.royale.utils
             return boundMethod;
         };
 
+        /**
+         * @param	arr
+         * @param	names
+         * @param	opt
+         */
+        public static function sort(arr:Array,...args):void{
+            var compareFunction:Function = null;
+            var opt:int = 0;
+            if (args.length == 1)
+            {
+                if (typeof args[0] === "function")
+                    compareFunction = args[0];
+                else
+                    opt = args[0];
+            }
+            else if (args.length == 2)
+            {
+                compareFunction = args[0];
+                opt = args[1];
+            }
+                
+            muler = (Array.DESCENDING & opt) > 0?-1: 1;
+            if (compareFunction)
+                arr.sort(compareFunction);
+            else if (opt & Array.NUMERIC){
+                arr.sort(compareAsNumber);
+            }else if (opt & Array.CASEINSENSITIVE){
+                arr.sort(compareAsStringCaseinsensitive);
+            }else{
+                arr.sort(compareAsString);
+            }
+        }
+        
+        private static function compareAsStringCaseinsensitive(a:Object, b:Object):int{
+            var v:int = (a||zeroStr).toString().toLowerCase().localeCompare((b||zeroStr).toString().toLowerCase());
+            if (v != 0){
+                return v*muler;
+            }
+            return 0;
+        }
+        private static function compareAsString(a:Object, b:Object):int{
+            var v:int = (a||zeroStr).toString().localeCompare((b||zeroStr).toString());
+            if (v != 0){
+                return v*muler;
+            }
+        return 0;
+        }
+        
+        private static function compareAsNumber(a:Object, b:Object):int{
+            if (a>b){
+                return muler;
+            }else if (a<b){
+                    return -muler;
+            }
+            return 0;
+        }
+        
 		/**
 		 * @param	arr
 		 * @param	names
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ObjectUtil.as b/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ObjectUtil.as
index ef849ea..5621f95 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ObjectUtil.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ObjectUtil.as
@@ -25,7 +25,20 @@ import flash.utils.Dictionary;
 import flash.utils.getQualifiedClassName;
 import flash.xml.XMLNode;
 */
+COMPILE::SWF
+{
+import flash.utils.Dictionary;
+import flash.utils.describeType;
+}
+COMPILE::JS
+{
+    import org.apache.royale.reflection.describeType;
+    import org.apache.royale.reflection.TypeDefinition;
+    import org.apache.royale.reflection.AccessorDefinition;
+    import org.apache.royale.reflection.VariableDefinition;
+}
 import mx.collections.IList;
+import org.apache.royale.reflection.getQualifiedClassName;
 
 /**
  *  The ObjectUtil class is an all-static class with methods for
@@ -737,8 +750,381 @@ public class ObjectUtil
                                         excludes:Array = null,
                                         options:Object = null):Object
     {   
-		trace("getClassInfo not implemented");
-		return null;
+        COMPILE::SWF
+        {
+        var n:int;
+        var i:int;
+        
+        //if (obj is ObjectProxy)
+        //    obj = ObjectProxy(obj).object_proxy::object;
+        
+        if (options == null)
+            options = { includeReadOnly: true, uris: null, includeTransient: true };
+        
+        var result:Object;
+        var propertyNames:Array = [];
+        var cacheKey:String;
+        
+        var className:String;
+        var classAlias:String;
+        var properties:XMLList;
+        var prop:XML;
+        var isDynamic:Boolean = false;
+        var metadataInfo:Object;
+        
+        if (typeof(obj) == "xml")
+        {
+            className = "XML";
+            properties = obj.text();
+            if (properties.length())
+                propertyNames.push("*");
+            properties = obj.attributes();
+        }
+        else
+        {
+            var classInfo:XML = /*DescribeTypeCache.*/describeType(obj).typeDescription;
+            className = classInfo.@name.toString();
+            classAlias = classInfo.@alias.toString();
+            isDynamic = classInfo.@isDynamic.toString() == "true";
+            
+            if (options.includeReadOnly)
+                properties = classInfo..accessor.(@access != "writeonly") + classInfo..variable;
+            else
+                properties = classInfo..accessor.(@access == "readwrite") + classInfo..variable;
+            
+            var numericIndex:Boolean = false;
+        }
+        
+        // If type is not dynamic, check our cache for class info...
+        if (!isDynamic)
+        {
+            cacheKey = getCacheKey(obj, excludes, options);
+            result = CLASS_INFO_CACHE[cacheKey];
+            if (result != null)
+                return result;
+        }
+        
+        result = {};
+        result["name"] = className;
+        result["alias"] = classAlias;
+        result["properties"] = propertyNames;
+        result["dynamic"] = isDynamic;
+//        result["metadata"] = metadataInfo = recordMetadata(properties);
+        
+        var excludeObject:Object = {};
+        if (excludes)
+        {
+            n = excludes.length;
+            for (i = 0; i < n; i++)
+            {
+                excludeObject[excludes[i]] = 1;
+            }
+        }
+        
+        var isArray:Boolean = (obj is Array);
+        /*var isDict:Boolean  = (obj is Dictionary);
+        
+        if (isDict)
+        {
+            // dictionaries can have multiple keys of the same type,
+            // (they can index by reference rather than QName, String, or number),
+            // which cannot be looked up by QName, so use references to the actual key
+            for (var key:* in obj)
+            {
+                propertyNames.push(key);
+            }
+        }
+        else*/ if (isDynamic)
+        {
+            for (var p:String in obj)
+            {
+                if (excludeObject[p] != 1)
+                {
+                    if (isArray)
+                    {
+                        var pi:Number = parseInt(p);
+                        if (isNaN(pi))
+                            propertyNames.push(new QName("", p));
+                        else
+                            propertyNames.push(pi);
+                    }
+                    else
+                    {
+                        propertyNames.push(new QName("", p));
+                    }
+                }
+            }
+            numericIndex = isArray && !isNaN(Number(p));
+        }
+        
+        if (isArray /*|| isDict */|| className == "Object")
+        {
+            // Do nothing since we've already got the dynamic members
+        }
+        else if (className == "XML")
+        {
+            n = properties.length();
+            for (i = 0; i < n; i++)
+            {
+                p = properties[i].name();
+                if (excludeObject[p] != 1)
+                    propertyNames.push(new QName("", "@" + p));
+            }
+        }
+        else
+        {
+            n = properties.length();
+            var uris:Array = options.uris;
+            var uri:String;
+            var qName:QName;
+            for (i = 0; i < n; i++)
+            {
+                prop = properties[i];
+                p = prop.@name.toString();
+                uri = prop.@uri.toString();
+                
+                if (excludeObject[p] == 1)
+                    continue;
+                
+                //if (!options.includeTransient && internalHasMetadata(metadataInfo, p, "Transient"))
+                //    continue;
+                
+                if (uris != null)
+                {
+                    if (uris.length == 1 && uris[0] == "*")
+                    {   
+                        qName = new QName(uri, p);
+                        try
+                        {
+                            obj[qName]; // access the property to ensure it is supported
+                            propertyNames.push();
+                        }
+                        catch(e:Error)
+                        {
+                            // don't keep property name 
+                        }
+                    }
+                    else
+                    {
+                        for (var j:int = 0; j < uris.length; j++)
+                        {
+                            uri = uris[j];
+                            if (prop.@uri.toString() == uri)
+                            {
+                                qName = new QName(uri, p);
+                                try
+                                {
+                                    obj[qName];
+                                    propertyNames.push(qName);
+                                }
+                                catch(e:Error)
+                                {
+                                    // don't keep property name 
+                                }
+                            }
+                        }
+                    }
+                }
+                else if (uri.length == 0)
+                {
+                    qName = new QName(uri, p);
+                    try
+                    {
+                        obj[qName];
+                        propertyNames.push(qName);
+                    }
+                    catch(e:Error)
+                    {
+                        // don't keep property name 
+                    }
+                }
+            }
+        }
+        
+        propertyNames.sort(Array.CASEINSENSITIVE | (numericIndex ? Array.NUMERIC : 0));
+        
+        // dictionary keys can be indexed by an object reference
+        // there's a possibility that two keys will have the same toString()
+        // so we don't want to remove duplicates
+        //if (!isDict)
+        //{
+            // for Arrays, etc., on the other hand...
+            // remove any duplicates, i.e. any items that can't be distingushed by toString()
+            for (i = 0; i < propertyNames.length - 1; i++)
+            {
+                // the list is sorted so any duplicates should be adjacent
+                // two properties are only equal if both the uri and local name are identical
+                if (propertyNames[i].toString() == propertyNames[i + 1].toString())
+                {
+                    propertyNames.splice(i, 1);
+                    i--; // back up
+                }
+            }
+        //}
+        
+        // For normal, non-dynamic classes we cache the class info
+        // Don't cache XML as it can be dynamic
+        if (!isDynamic && className != "XML")
+        {
+            cacheKey = getCacheKey(obj, excludes, options);
+            CLASS_INFO_CACHE[cacheKey] = result;
+        }
+        
+        return result;
+        }
+        COMPILE::JS
+        {
+            var n:int;
+            var i:int;
+            
+            //if (obj is ObjectProxy)
+            //    obj = ObjectProxy(obj).object_proxy::object;
+            
+            if (options == null)
+                options = { includeReadOnly: true, uris: null, includeTransient: true };
+            
+            var result:Object;
+            var propertyNames:Array = [];
+            var cacheKey:String;
+            
+            var className:String;
+            var classAlias:String;
+            var isDynamic:Boolean = false;
+            var metadataInfo:Object;
+            
+            if (obj is XML)
+            {
+                className = "XML";
+                var xmlproperties:XMLList = obj.text();
+                if (xmlproperties.length())
+                    propertyNames.push("*");
+                xmlproperties = obj.attributes();
+                n = xmlproperties.length();
+                for (i = 0; i < n; i++)
+                {
+                    p = xmlproperties[i].name();
+                    if (excludeObject[p] != 1)
+                        propertyNames.push(new QName("", "@" + p));
+                }
+            }
+            else
+            {
+                var classInfo:TypeDefinition = describeType(obj);
+                if (classInfo == null) // probably not a Royale class
+                {
+                    className == "Object";
+                    //classAlias = null;
+                    isDynamic = true;
+                }
+                else
+                {
+                    className = classInfo.qualifiedName;
+                    //classAlias = classInfo.@alias.toString();
+                    //isDynamic = classInfo.@isDynamic.toString() == "true";
+                
+                    var accessors:Array = classInfo.accessors;
+                    for each (var accessor:AccessorDefinition in accessors)
+                    {
+                        if (excludeObject[accessor.name] == 1)
+                            continue;
+                        if (options.includeReadOnly)
+                        {
+                            if (accessor.access != "writeonly")
+                                propertyNames.push(accessor.name);
+                        }
+                        else
+                        {
+                            if (accessor.access != "readwrite")
+                                propertyNames.push(accessor.name);                        
+                        }
+                    }
+                    var variables:Array = classInfo.variables;
+                    for each (var variable:VariableDefinition in variables)
+                    {
+                        if (excludeObject[variable.name] == 1)
+                            continue;
+                        propertyNames.push(variable.name);
+                    }
+                    
+                    var numericIndex:Boolean = false;
+                }
+            }
+            
+            // If type is not dynamic, check our cache for class info...
+            if (!isDynamic)
+            {
+                cacheKey = getCacheKey(obj, excludes, options);
+                result = CLASS_INFO_CACHE[cacheKey];
+                if (result != null)
+                    return result;
+            }
+            
+            result = {};
+            result["name"] = className;
+            result["alias"] = classAlias;
+            result["properties"] = propertyNames;
+            result["dynamic"] = isDynamic;
+//            result["metadata"] = metadataInfo = recordMetadata(properties);
+            
+            var excludeObject:Object = {};
+            if (excludes)
+            {
+                n = excludes.length;
+                for (i = 0; i < n; i++)
+                {
+                    excludeObject[excludes[i]] = 1;
+                }
+            }
+            
+            var isArray:Boolean = (obj is Array);
+            if (isDynamic)
+            {
+                for (var p:String in obj)
+                {
+                    if (excludeObject[p] != 1)
+                    {
+                        if (isArray)
+                        {
+                            var pi:Number = parseInt(p);
+                            if (isNaN(pi))
+                                propertyNames.push(new QName("", p));
+                            else
+                                propertyNames.push(pi);
+                        }
+                        else
+                        {
+                            propertyNames.push(new QName("", p));
+                        }
+                    }
+                }
+                numericIndex = isArray && !isNaN(Number(p));
+            }
+            
+            propertyNames.sort(Array.CASEINSENSITIVE | (numericIndex ? Array.NUMERIC : 0));
+            
+            // for Arrays, etc., on the other hand...
+            // remove any duplicates, i.e. any items that can't be distingushed by toString()
+            for (i = 0; i < propertyNames.length - 1; i++)
+            {
+                // the list is sorted so any duplicates should be adjacent
+                // two properties are only equal if both the uri and local name are identical
+                if (propertyNames[i].toString() == propertyNames[i + 1].toString())
+                {
+                    propertyNames.splice(i, 1);
+                    i--; // back up
+                }
+            }
+            
+            // For normal, non-dynamic classes we cache the class info
+            // Don't cache XML as it can be dynamic
+            if (!isDynamic && className != "XML")
+            {
+                cacheKey = getCacheKey(obj, excludes, options);
+                CLASS_INFO_CACHE[cacheKey] = result;
+            }
+            
+            return result;            
+        }
     }
 
     /**
@@ -970,8 +1356,30 @@ public class ObjectUtil
      */
     private static function getCacheKey(o:Object, excludes:Array = null, options:Object = null):String
     {
-		trace("getCacheKey not implemented");
-		return null;
+        var key:String = getQualifiedClassName(o);
+        
+        if (excludes != null)
+        {
+            var length:int = excludes.length;
+            for (var i:uint = 0; i < length; i++)
+            {
+                var excl:String = excludes[i] as String;
+                if (excl != null)
+                    key += excl;
+            }
+        }
+        
+        if (options != null)
+        {
+            for (var flag:String in options)
+            {
+                key += flag;
+                var value:String = options[flag];
+                if (value != null)
+                    key += value.toString();
+            }
+        }
+        return key;
     }
 
     /**
diff --git a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/TypeDefinition.as b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/TypeDefinition.as
index 63ccf26..dd64e86 100755
--- a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/TypeDefinition.as
+++ b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/TypeDefinition.as
@@ -109,6 +109,7 @@ COMPILE::SWF {
          * @return a TypeDefinition representing the class or interface represented by the parameters
          */
         public static function getDefinition(name:String, rawData:Object = null):TypeDefinition {
+            if (rawData == null) return null;
             return _cache ? (_cache[name] || new TypeDefinition(name, rawData)) : new TypeDefinition(name, rawData);
         }
 
diff --git a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/describeType.as b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/describeType.as
index 389302a..f5dd23a 100755
--- a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/describeType.as
+++ b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/describeType.as
@@ -49,7 +49,7 @@ COMPILE::SWF
         COMPILE::JS
         {
             var qname:String = getQualifiedClassName(value);
-            return TypeDefinition.getDefinition(qname, value.ROYALE_CLASS_INFO || value.prototype.ROYALE_CLASS_INFO);
+            return TypeDefinition.getDefinition(qname, value.ROYALE_CLASS_INFO || (value.prototype != null) ? value.prototype.ROYALE_CLASS_INFO : null);
         }
     }
 }
diff --git a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getQualifiedClassName.as b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getQualifiedClassName.as
index b4a3437..599d59e 100755
--- a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getQualifiedClassName.as
+++ b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/getQualifiedClassName.as
@@ -49,7 +49,7 @@ COMPILE::SWF
             
             if (value.ROYALE_CLASS_INFO == null)
             {
-                if (value.prototype.ROYALE_CLASS_INFO == null)
+                if (value.prototype == null || value.prototype.ROYALE_CLASS_INFO == null)
                     return "Object";
                 value = value.prototype;
             }