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.
Related
I creat two people that are instances of the Person Class
var personOne = new Person;
var personTwo = new Person;
later I create an Object called Chuck;
var Chuck = {age:32, name:"Chuck"}
Now I want to make personOne be a "person" with the properties of "chuck:Object";
Cannot convert Object to Display Object. // Output
If you want to set properties of an object when it is created, you can let the constructor accept them as parameters.
For example:
package
{
public class Person
{
private var _age:uint, _name:String;
public function Person (age:uint, name:String)
{
_age = age;
_name = name;
}
}
}
You use it like so:
var chuck:Person = new Person(32, "Chuck");
This is probably not what you need, but it is what you asked.
var personOne :Person = new Person();
var object:Object = { age:23, name:"efefw" };
for (var prop:String in object)
{
personOne[prop] = object[prop];
}
This will only work for public properties.
I think Im having a really noob moment, Im returning a remote object from coldfusion and I want to specify the object type. i.e Im getting an worker from coldfusion and I have a Value object Worker.
Heres what I have been trying
public function ResultHandler_GetWorker(event:ResultEvent):void
{
var result:ArrayCollection = ArrayCollection(event.result);
var worker:WorkerVO = WorkerVO(result[0]);
model.worker = worker;
}
Result[0] is an employee object. Its structure from debug looks like this.
workerAddress "24b fake Ave"
workerCity "Wellton"
workerCountry "Ameriland"
workerEmail "Afake#me.com"
workerFName "Foo"
workerHPhone "435234"
workerID 1
workerImage null
workerIsAdmin true
workerLName "Foo"
workerMPhone "827271903"
workerPassword "password"
workerPosition "Leader"
workerState ""
workerSuburb "Birkenhead"
workerWPhone null
my class looks like this:
public class WorkerVO
{
public var _workerAddress:String
public var _workerCity:String
public var _workerCountry:String
public var _workerEmail:String
public var _workerFName:String
public var _workerHPhone:String
public var _workerID:uint;
public var _workerImage:String
public var _workerIsAdmin:Number;
public var _workerLName:String
public var _workerMPhone:String;
public var _workerPassword:String;
public var _workerPosition:String;
public var _workerState:String;
public var _workerSuburb:String;
public var _workerWPhone:String;
public function WorkerVO()
{
}
//Getters & Setters
}
Error #1034: Type Coercion failed: cannot convert Object#114eeb251 to com.cavej03.sitesafe.vo.WorkerVO.
Am I doing it completely wrong. Am I simply meant to make a function or constructor that accepts this object and maps its fields to a new WorkerVO
You're missing a RemoteClass metadata tag. This tag tells your application which server-side VO a given client-side VO is mapped to.
Use it like this:
[RemoteClass(alias="path.to.WorkerVO")] //this is the servers-side path
public class WorkerVO {
...
}
Furthermore from what you're showing it looks like the names of your properties don't match: the client-side one has prepended underscores while the server-side one doesn't.
The property names of the client-side VO and the server-side one should be exactly the same. For instance:
/* Java VO */
public class WorkerVO {
private String workerAddress;
public String getWorkerAddress() {
return workerAddress;
}
public void setWorkerAddress(String workerAddress) {
this.workerAddress = workerAddress;
}
}
/* ActionScript VO */
[RemoteClass(alias="path.to.WorkerVO")]
public class WorkerVO {
public var workerAddress:String;
}
This is an example with a Java VO, but the same applies to ColdFusion.
Assign the returned object to a property within WorkerVO, and prepare getters for each of them like so:
public class WorkerVO
{
private var _base:Object;
public function WorkerVO(base:Object)
{
_base = base;
}
public function get address():String{ return _base.workerAddress; }
public function get city():String{ return _base.workerCity; }
// Etc.
}
And the definition of a worker just needs the new keyword added:
var worker:WorkerVO = new WorkerVO(result[0]);
trace(worker.address);
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
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](...);
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);
}
}