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;
}