Getting all of the variables of a dart class for json encoding - json

I have a class
class Person{
String _fn, _ln;
Person(this._fn, this._ln);
}
Is there a way to get a list of variables and then serialize it? Essentially i want to make a toJson, but i wanted to have it generic enough such that key is the variable name, and the value is the value of the variable name.
In javascript it would be something like:
var myObject = {}; //.... whatever you want to define it as..
var toJson = function(){
var list = Object.keys(myObject);
var json = {};
for ( var key in list ){
json[list[key]] = myObject[list[key]] ;
}
return JSON.stringify(json);
}

Dart doesn't have a built in functionality for serialization. There are several packages with different strategies available at pub.dartlang.org. Some use mirrors, which is harmful for client applications because it results in big or huge JS output size. The new reflectable packages replaces mirrors without the disadvantage but I don't know if serialization packages are already ported to use it instead. There are also packages that use code generation.
There is a question with an answer that lists available solutions. I'll look it up when I'm back.

Related

Can you navigate the contents of a Vector's index via a String?

Is it possible to do something similar to this in Haxe?
private var _bindingsFiltered:Vector<String>;
_bindingsFiltered = new Vector<String>();
_controller_touched_binding.action = "meta_start";
What I would like to be able to do:
_bindingsFiltered[_controller_touched_binding.action] = "BUTTON_13";
trace(_bindingsFiltered["meta_start"]); //result: "BUTTON_13"
I want to be able to override a specific index too (still accessed via a string), with a new value, rather than keep pushing new content to the end of the vector. I have been using 'openfl.utils.Object' to cheat for now but I am looking for a more reliable approach for the long run.
Is there a way to do this in Haxe?
If not, what are my options?
I would also be interested in a solution for this in AS3, if there is one (avoiding the Array class).
My goal is to find a method that I can use in both languages seamlessly (next-to-none, differences).
Vector's cannot be indexed by string in Haxe. A vector is an array with a fixed size. This is the Haxe manual on that subject.
Instead of vectors, you can use a Map.
class Test {
private var vector:Map<String, String> = new Map<String, String>();
public function new() {
var str = 'haxe';
vector[str] = "is great";
trace(vector[str]);
}
static function main() {
new Test();
}
}
https://try.haxe.org/#F74Ba
I think you could do this using flash.utils.Dictionary:
ActionScript
import flash.utils.Dictionary;
...
var _bindingsFiltered:Dictionary = new Dictionary ();
_bindingsFiltered[_controller_touched_binding.action] = "BUTTON_13";
trace(_bindingsFiltered["meta_start"]); //result: "BUTTON_13"
Haxe
import openfl.utils.Dictionary;
...
var _bindingsFiltered = new Dictionary<String, String> ();
_bindingsFiltered[_controller_touched_binding.action] = "BUTTON_13";
trace(_bindingsFiltered["meta_start"]); //result: "BUTTON_13"
First, do you really want an array / vector / list, or do you really want a hashmap of key / value pairs? How are you using the collection? Why do you want String keys? And related, is this mostly about access symantics (you want to type it this way), or are the runtime reasons you'd want to use strings (serialization / etc)?
From what you've described, it sounds like what you really want is an Object like the ones in AS3/JS/ECMAScript, with square-bracket access symantics -- obj[key]
Yes, you can do that in Haxe. The openfl.utils.Object class is a helper to do exactly this, using Dynamic objects and reflection. It should compile to exactly what you want on all Haxe targets.
In any case, if you'd like to feel like you're not bound to OpenFL, no problem. Copy the openfl/utils/Object.hx file and place it anywhere you like in your project's class path (and update the package statement).
There's nothing particularly OpenFL-ish about that code. It's pure Haxe code with no dependencies. It provides array access with String keys, as well as toString, toLocaleString, propertyIsEnumerable, iterator, isPrototypeOf, and hasOwnProperty functions (which ECMA-folk are used to.)
The transition from AS3/JS to Haxe is a little weird, especially when it comes to dynamic objects, and I've been meaning to blog more about it. ;) Good luck!
ETA: In truth, you probably want to get away from Dynamic/Reflection, and embrace a more type-strict approach. AS3/JS devs don't understand this at first, but it is where the benefits of Haxe come from. If you don't then your Haxe experience is likely to be unplesant.
Short answer: yes, you can.
abstract MyVector<T>(Vector<T>) {
public function new(l:Int) this = new Vector<T>(l);
#:op([]) public function set<K:T>(s:String, v:K) {
switch (s) {
case "FIRST": this[0] = v;
case "SECOND": this[1] = v;
default: return;
}
}
#:op([]) public function get(s:String) {
switch (s) {
case "FIRST": return this[0];
case "SECOND": return this[1];
default: return cast 0;
}
}
}
var mv = new MyVector<String>(2);
mv["SECOND"] = "Second";
trace(mv["SECOND"]); // outputs Second
You can inline get and set methods if you want.

AS3: How to Deep Copy an Object

i have an object that i need to copy to my SharedObject data.
The problem is that the data property of shared object is read-only, so i can't clone my 'source' object and assign it to the shared object data, i have to make a copy of them in this way:
var so: SharedObject = SharedObject.getLocal("appData");
copyObject(sourceObj, so.data);
so.flush();
and the copy method:
public static function copyObject(sourceObject:Object, destinationObject:Object):void{
// this would be the code that i need
}
Also have in mind that my object has properties that are objects, so it has inside n leves of objects. That is why i can't simply make a for each and assign all properties on the first level, so what i need is to make a DEEP copy, probably recursive. I tried for hours to make this copyObject method with no success. Also i've searched on the internet but i didn't find any object copy that suits me.
Can someone please help me with this method? I would really apreciate it!
Thank you for your help!
The solution is to write your object to a byte array, encoded it to a string(optional - you can probably save the byte array as well, haven't looked it up) and save it to your shared object.
This function will take an object and turn it into a string
public static function serializeToString(value:Object):String{
if(value==null){
throw new Error("null isn't a legal serialization candidate");
}
var bytes:ByteArray = new ByteArray();
bytes.writeObject(value);
bytes.position = 0;
return Base64.encodeByteArray(bytes);
}
This one will get your object back from a string.
public static function readObjectFromStringBytes(value:String):Object{
var result:ByteArray = Base64.decodeToByteArray( value) as ByteArray;
result.position = 0;
return result.readObject();
}
The Base 64 encoding class you can find here https://github.com/juancgarcia/screenshotify/blob/master/Downloadify-652377f/src/com/dynamicflash/util/Base64.as.
You need to implement IExternalizable on all objects you want to store this way. The implementation includes making writeExternal method called against a ByteArray when you do writeObject(), and readExternal methods, that's called against a newly created instance, so your class should write the necessary metadata in order to make your object deep-cloned, including writing property objects.
Manual on IExternalizable
And on a side note, you should not store one object in the entire so.data, you'd better assign a field in so.data and stuff your object copy in there.
For complex objects I would use RegisterClassAlias:
import flash.net.registerClassAlias;
registerClassAlias("YourClassName", YourClassName);
var so:SharedObject = SharedObject.getLocal("objectName");
so.data.yourData = YourClassName.instance;
so.flush();
For simple Object type with deep level of simple data (primitives including arrays) I would simply use JSON.stringify() and JSON.parse() when reading back the data.

How to export data from LinqPAD as JSON?

I want to create a JSON file for use as part of a simple web prototyping exercise. LinqPAD is perfect for accessing the data from my DB in just the shape I need, however I cannot get it out as JSON very easily.
I don't really care what the schema is, because I can adapt my JavaScript to work with whatever is returned.
Is this possible?
A more fluent solution is to add the following methods to the "My Extensions" File in Linqpad:
public static String DumpJson<T>(this T obj)
{
return
obj
.ToJson()
.Dump();
}
public static String ToJson<T>(this T obj)
{
return
new System.Web.Script.Serialization.JavaScriptSerializer()
.Serialize(obj);
}
Then you can use them like this in any query you like:
Enumerable.Range(1, 10)
.Select(i =>
new
{
Index = i,
IndexTimesTen = i * 10,
})
.DumpJson();
I added "ToJson" separately so it can be used in with "Expessions".
This is not directly supported, and I have opened a feature request here. Vote for it if you would also find this useful.
A workaround for now is to do the following:
Set the language to C# Statement(s)
Add an assembly reference (press F4) to System.Web.Extensions.dll
In the same dialog, add a namespace import to System.Web.Script.Serialization
Use code like the following to dump out your query as JSON
new JavaScriptSerializer().Serialize(query).Dump();
There's a solution with Json.NET since it does indented formatting, and renders Json dates properly. Add Json.NET from NuGet, and refer to Newtonsoft.Json.dll to your “My Extensions” query and as well the following code :
public static object DumpJson(this object value, string description = null)
{
return GetJson(value).Dump(description);
}
private static object GetJson(object value)
{
object dump = value;
var strValue = value as string;
if (strValue != null)
{
var obj = JsonConvert.DeserializeObject(strValue);
dump = JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented);
}
else
{
dump = JsonConvert.SerializeObject(value, Newtonsoft.Json.Formatting.Indented);
}
return dump;
}
Use .DumpJson() as .Dump() to render the result. It's possible to override more .DumpJson() with different signatures if necessary.
As of version 4.47, LINQPad has the ability to export JSON built in. Combined with the new lprun.exe utility, it can also satisfy your needs.
http://www.linqpad.net/lprun.aspx

Typed AS3 JSON Encoder and Decoder?

I need to encode and Decode AS3 Objects in a typed manner. http://code.google.com/p/as3corelib/ only supports untyped encoding and decoding.
http://code.google.com/p/ason/ supports some kind of typed objects but is not very robust, e.g. it fails on Date Objects. Any Recommendations ?
To make it clear: It MUST be JSON and it MUST be strong typed and robust.
JSON is built in in AS3. The preferred method to transmit data over the wire is AMF, which does provide you typed objects.
If you have to use JSON, then I guess that you might have to do with some sort of custom protocol to be able encode/decode with types.
You would actually need a reflection utility that read beans in JSON format and then produce your object. It really depends on how deep you want to go.
as3Commons has a reflect package that could help. They also have a JSONTypeProvider, which is not exactly what you need but can put you in the right tract.
You could modify any of the IOC frameworks to produce the context by parsing JSON instead of the regular XML most of them use.
You could modify ASON and add a custom type parser. You would have to send a variable in your JSON object containing the type of the object. And use that in with flash.utils.getDefinitionByName.
Another approach would be to just parse the objects with a regular JSON parser and then if it has a defined type create an instance of that objet, and initialize the properties.
Something like this, to get you started:
var beanInfo:Object = JSON.decode( jsonString );
beanInfo = _parseBean( beanInfo );
private function _parseBean(beanInfo:Object):Object{
if ( beanInfo.hasOwnProperty("_type") ) {
var clazz:Class = getDefinitionByName( beanInfo._type ) as Class;
beanInfo.__clazz = clazz;
var instance:Object = new clazz;
for( var prop:String in beanInfo ) {
if( instance.hasOwnProperty(prop) ) target[prop] = _getPropertyFrom(beanInfo[prop]);
}
}
}
private function _getPropertyFrom(property:String):* {
var xml:XML = describeType( beanInfo.__clazz );
//find the type of the current property.
var type:String = xml...
//if is a simple object then do something like
switch( type ) {
case "number":
return parseFloat(property ) as Number;
break;
case "int":
case "uint":
return parseInt( property );
break;
case "string":
return property as String;
break;
...
default
//As it is it does not suppor complex objects.
//You would use reflection. But then you could save the whole switch...
break;
}
}
Flash has its own serialization system.
var serializer:ByteArray = new ByteArray();
serializer.writeObject(new Sprite());
serializer.position = 0;
var data:String = serializer.readUTFBytes(serializer.bytesAvailable);
trace(data); //Will show you the binary jibberish
You can use registerClassAlias to add support for custom classes.
JSON doens't really define a means to convey type information. It's just strings and ints and arrays and so on. So basically you need some sort of "pickle" for AS3 that's based on JSON. I would suggest you look into Flex/Flash remoting solutions and see how they package objects to be transmitted for RPC; you might be able to modify that solution to use JSON. I'm actually doubtful you'll find a library like this. Does it have to be JSON? I'm pretty sure there are XML based libraries that do this.
JSON is not implemented in the flash virtual machine, and therefore there is no typed object "JSON" as there is "Xml." So basically you can decode JSON just fine, but the type you're going to get is Object. You can them access data using the key in the object as an associative array.
http://blog.alien109.com/2009/02/11/php5-json-as3corelib-a-beautiful-thing/
JSON lib/utils official from adobe:
http://code.google.com/p/as3corelib/source/browse/#svn%2Ftrunk%2Fsrc%2Fcom%2Fadobe%2Fserialization%2Fjson
As good as it gets. :)
There are two operations you need to consider: 1) serializing an object of a particular type into JSON and 2) deserializing a JSON string into an object of a particular type.
The serialization part is easy - just use the built-in JSON.stringify(). Deserializing a JSON string into an object of a particular type in ActionScript is where it gets interesting (and where the answer to your question is). You need to write your own deserialization function for the classe(s) you will need to deserialize. In that function, you need to provide a reviver function to JSON.parse(), which allows you to customize how the JSON gets deserialized.
For example:
public static function deserializeComplexObject(json:String):ComplexObject
{
if (null == json || "null" == json)
{
return null;
}
var complexObject:ComplexObject = new ComplexObject();
var parsedObject:Object = JSON.parse(
json,
function (key:String, value:Object):*
{
switch (key)
{
case “keyForNumber”:
return value;
case “keyForComplexObject2”:
return deserializeComplexObject2(JSON.stringify(value));
case “keyForComplexObject3”:
return deserializeComplexObject3(JSON.stringify(value));
case “keyForString”:
return value;
case “keyForBoolean”:
return value;
default:
return value;
}
}
);
complexObject.keyForNumber = parsedObject.keyForNumber;
complexObject.keyForComplexObject2 = parsedObject.keyForComplexObject2;
// continue setting fields
// …
return complexObject;
}
Each case statement corresponds to a top-level key in the JSON string. You don't actually need separate case statements for every key - you can use the default case to handle all keys that map to values that are one of the simple types (Object, Array, String, Number, Boolean, null) by returning the value as-is.
I have now forked the json part of http://code.google.com/p/as3corelib/ and added typed object support...

Is it possible to get all member variables in flash(AS3)?

I am trying grab all the member variables in AS3, and then foreach one i would like to process it in various ways. I would need the name and then if it is a collection of some type I would like to loop through that collection as well. I am attempting to essentially serialize in a somewhat custom fashion.
Thanks!
If you're looking to serialize an object, you will definitely want to use JSON.
JSON basically converts objects into strings and also the other way round using an encode()/serialize() and decode()/deserialize() function.
There is a built-in JSON class in AS3, and it's really easy to use.
Once you do something like:
var myObject:Object = {};
var myObjectString:String = JSON.serialize(myObject);
After getting the string, you can do all your switch logic to manipulate each of your different variables and convert it back into an object via the deserialize() function.
You could use describeType. That returns information about the object as XML. By default, you can iterate over public properties in objects. You could try something like...
// the object to iterate over
var someObj:Object = {};
for(var prop:String in someObj) {
// check to see if its something you want to iterate over
if (someObj[prop] is Array) {
// iterator over the property here
}
}
I hope this answers your question.