AS3 Custom Object to ByteArray then to Custom Object - actionscript-3

Having problem reading bytearray of custom objects. Any help is appreciated
public class CustomObject extends Object {
public function CustomObject() {
public var _x:Number = 100
public var _y:Number = 10
public var _z:Number = 60
}
}
var cObj:CustomObject = new CustomObject()
var bytes:ByteArray = new ByteArray()
bytes.writeObject(cObj)
bytes.compress()
//read
try { bytes.uncompress() } catch (e:Error) { }
var obj:CustomObject = bytes.readObject() as CustomObject
trace(obj) // null why?!
trace(obj._z) // Obviously - TypeError: Error #1009: Cannot access a property or method of a null object reference.

What you want to do is use the registerClassAlias method to register type information along with the data. That way Flash will know how to serialize/deserialize your object. Here's some sample code from Adobe's documentation:
registerClassAlias("com.example.eg", ExampleClass);
var eg1:ExampleClass = new ExampleClass();
var ba:ByteArray = new ByteArray();
ba.writeObject(eg1);
ba.position = 0;
var eg2:* = ba.readObject();
trace(eg2 is ExampleClass); // true
It should be noted that all types that should be serialized must be registered for the type information to be saved. So if you have another type that is referenced by your type, it too must be registered.

Your CustomObject class is wrong , it should throw an error actually , it should be this instead
public class CustomObject
{
public var _x:Number = 100
public var _y:Number = 10
public var _z:Number = 60
public function CustomObject()
{
}
}
Edit:
Sounds like macke has a point, because this works...
//read
try { bytes.uncompress() } catch (e:Error) { }
var obj:Object = bytes.readObject();
trace(obj) // [object Object]
trace(obj._z) // 60

Look at object that ByteArray.readObject() returns. You'll probably see that all properties are there, but type information is lost. So, you can solve this by creating some
public static function fromObject(value:Object):CustomObject {
var result:CustomObject = new CustomObject();
result._x = value._x;
//and so on...
return result;
}

To serialize custom classes to the ByteArray, you must put registerClassAlias in the constructor of the class calling the byteArray.writeObject() function.
If you don't, your custom class will be serialized as Object type. I was calling registerClassAlias in the serialize function below and my custom class keeps getting serialized as Object until I moved the registerClassAlias to the constructor.
public class MyClass{
public function MyClass(){
registerClassAlias("com.myclass", MyClass); // Ok, serializes as MyClass
serialize( new MyClass() );
}
private function serialize( _c:MyClass ){
var byteArray:ByteArray = new ByteArray();
byteArray.writeObject( _c );
//registerClassAlias("com.myclass", MyClass); Not ok, serialized as Object
EncryptedLocalStorage.setItem('key', byteArray);
}
}

Related

Json.net contractResolver is failling

I have implemented the custom contract resolver to remove the some properties from serialized Json. Most of the time below code works but occasionally this code fails. Sometime it loops through the list and skips item I want to exclude which causing to appear that properties which I wanted to exclude.
class TestClass
{
public static void Test()
{
var objectToSerialise = //Coming from some WebAPI calls
string[] stringToSkip = {"skip1", "skip2"};
var settings = new JsonSerializerSettings
{
ContractResolver = new MyContractResolver(stringToSkip)
};
var json = JsonConvert.SerializeObject(objectToSerialise, settings);
}
}
public class MyContractResolver : DefaultContractResolver {
private string[] _skipthis;
public MyContractResolver(string[] skipthis)
{
_skipthis = skipthis;
}
private JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization){
var property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = (prop) =>{
return !(_skipthis.Where(n => property.PropertyName.Contains(n)).Any());
};
return property;
}
}
Can someone please suggest why this code is failing silently intermittently with out throwing any kind of exception?
Note that skipthis array is not modified outside this. I want to skip the property when property name exist or substring of propertyname exist in skipthis array.

copy method of util class is not working

I am having a class Employee as:
public class Employee
{
public var name:String;
public function Employee(name:String)
{
this.name = name;
}
}
Now I am trying to create copy of an ArrayCollection of employees using ObjectUtil as:
protected function button1_clickHandler(event:MouseEvent):void
{
var newEmployees = ObjectUtil.copy(employees);
for each(var emp:Employee in newEmployees) {
Alert.show(emp.name);
}
}
But it is throwing exception:
Main Thread (Suspended: TypeError: Error #1034: Type Coercion failed:
cannot convert Object#ef41a19 to objectutil.Employee.)
objectutil::ObjectUtilCopyCheck/button1_clickHandler
objectutil::ObjectUtilCopyCheck/___ObjectUtilCopyCheck_Button1_click
Can anyone identify what is wrong here? TIA.
The method copy internally makes copy using native serialization technique:
public static function copy(value:Object):Object
{
var buffer:ByteArray = new ByteArray();
buffer.writeObject(value);
buffer.position = 0;
var result:Object = buffer.readObject();
return result;
}
If we use remoting tag then it is easy. For example:
//assume employee has [RemoteClass] metadata.
var newEmployees = Employee (ObjectUtil.copy(emp));
Else you need to register this class as (assuming that com.app.vo.Employee is the package of class Employee ):
registerClassAlias("com.app.vo.Employee",Employee);
//Now we can copy and caste
var newEmployees = Employee (ObjectUtil.copy(emp));
Hope this will help you.

Serializing object using messagepack and as3

This is a vary simple question, but can't find any docs on it.
I have a simple class:
public class User
{
public var name:String;
public var age:int;
}
I would like to serialize it using this:
var user:User = new User();
user.age = 15;
user.name = "mike";
//now serialize
var bytes:ByteArray = MessagePack.encoder.write(vo);
But I get an error:
Error: MessagePack handler for type base not found
How do I let MessagePack know what the User class is, how to serialize it?
MessagePack doesn't look like being able to serialize Class, like most serializer.
I suggest you to add a toObject method to your User class :
public function toObject():Object
{
return {age:this.age, name:this.name}:
}
Then you can serialize your user :
var bytes:ByteArray = MessagePack.encoder.write(user.toObject());
You can also add a static fromObject method which takes an object and returns a new User initialized with this object.
static public function fromObject(o:Object):User
{
var u = new User();
u.age = o.age;
u.name = o.name;
return u;
}

Need some help in creating XML log in Adobe Air

I need to create XML log file in Adobe Air. My first thought was to use some kind of automated serialization. And I've found FlexXB library. I've created simple logger and marked the class with annotations in the following way
package loggingTools
{
[XmlClass]
[ConstructorArg(reference="timeStamp")]
[ConstructorArg(reference="item")]
[ConstructorArg(reference="action")]
[ConstructorArg(reference="arguments")]
[ConstructorArg(reference="success")]
[Bindable]
public class MessageAction
{
[XmlAttribute()]
public var timeStamp:Date;
[XmlAttribute()]
public var item:String;
[XmlAttribute()]
public var action:String;
[XmlAttribute()]
public var arguments:String;
[XmlAttribute()]
public var success:Boolean;
public function MessageAction(timeStamp:Date, item:String, action:String, arguments:String, success:Boolean) {
this.timeStamp = timeStamp;
this.item = item;
this.action = action;
this.arguments = arguments;
this.success = success;
}
}
I'm trying to serialize the single object:
public class PlainXMLLogger
{
//private static var isStarted:Boolean;
private var logFile:XML;
[XmlArray(alias = "Log", type="loggingTools.MessageAction")]
[ArrayElementType("loggingTools.MessageAction")]
public var messages:Array;
public function addMessageAction(item:String, action:String, arguments:String, success:Boolean):void {
var newMessageAction:MessageAction;
newMessageAction = new MessageAction(new Date(), item, action, arguments, success);
messages.push(newMessageAction);
}
public function close():void {
var logXML:XML = FlexXBEngine.instance.serialize(messages);
trace(">> XML LOG ");
trace(logXML.toString() );
}
}
Now, serialization produces an error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at com.googlecode.flexxb.core::SerializationCore/serialize()
Sure, I can serialize all objects in collection one-by-one, but I consider, that this is a bad idea.
Here is the answer on my question, provided by creators of FlexXB tool
https://groups.google.com/forum/?hl=ru&fromgroups#!topic/flexxb/g912jkxwldE

Get AS3 instance method reference from Class object

class Foo {
public function bar():void { ... }
}
var clazz:Class = Foo;
// ...enter the function (no Foo literal here)
var fun:Function = clazz["bar"]; // PROBLEM: returns null
// later
fun.call(new Foo(), ...);
What is the correct way to do the above? The Java equivalent of what I want to do is:
Method m = Foo.class.getMethod("bar", ...);
m.invoke(new Foo(), ...);
Actual code (with workaround):
class SerClass {
public var className:String;
public var name:String;
private var ser:String = null;
private var unser:Function = null;
public function SerClass(clazz:Class):void {
var type:XML = describeType(clazz);
className = type.#name;
// determine name
name = type.factory.metadata.(#name=="CompactType").arg.(#key=="name").#value;
// find unserializer
var mdesc:XML = XML(type.method.metadata.(#name=="Unserialize")).parent();
if (mdesc is XML) {
unser = clazz[mdesc.#name];
}
// find serializer
var sdesc:XML = XML(type.factory.method.metadata.(#name=="Serialize")).parent();
if (sdesc is XML) {
ser = sdesc.#name;
}
}
public function serialize(obj:Object, ous:ByteArray):void {
if (ser == null) throw new Error(name + " is not serializable");
obj[ser](ous);
}
public function unserialize(ins:ByteArray):Object {
if (unser == null) throw new Error(name + " is not unserializable");
return unser.call(null, ins);
}
}
Here the function bar only exist when your class is instanciated :
var foo:Foo = new Foo()
var fun:Function = foo.bar // <-- here you can get the function from the new instance
if you want to access it directlty you have to make it static:
class Foo {
public static function bar():void{ ... }
}
now you can access your function from the class Foo:
var fun:Function = Foo.bar
or
var clazz:Class = Foo
var fun:Function = clazz["bar"]
I am not sure about what you are intending to do.
However AS3Commons, especially the reflect package have API's that let you work with methods, instances and properties of a class.
There are also API methods to create instances of certain class types on the fly and call their respective methods.
Cheers
It's not
fun.call(new Foo(), ...);
Use instead since no parameters are required for the function
fun.call(clazz);
The first parameter as specified by adobe docs.
An object that specifies the value of thisObject within the function body.
[EDIT]
Forgot to point out you have to instantiate a non-static class with the "new" keyword.
var clazz:Class = new Foo();
[EDIT2]
Ok I played around and think I got what you want.
base.as
package{
public class Base {
public function Base() {
trace('Base constructor')
}
public function someFunc( ){
trace('worked');
}
}
}
//called with
var b:Base = new Base( );// note I am not type casting to Class
var func:Function = b.someFunc;
func.call( );
My workaround is to store the function name instead of the Function object.
var fun:String = "bar";
// later...
new Foo()[fun](...);