1

I am trying to create a custom object in AS3 to pass information to and from a server, which in this case will be Red5. In the below screenshots you will see that I am able to send a request for an object from as3, and receive it successfully from the java server. However, when I try to cast the received object to my defined objectType using 'as', it takes the value of null. It is my understanding that that when using "as" you're checking to see if your variable is a member of the specified data type. If the variable is not, then null will be returned.

This screenshot illustrates that I am have successfully received my object 'o' from red5 and I am just about to cast it to the (supposedly) identical datatype testObject of LobbyData:

alt text Enlarge

However, when testObject = o as LobbyData; runs, it returns null. :(

alt text Enlarge

Below you will see my specifications both on the java server and the as3 client. I am confident that both objects are identical in every way, but for some reason flash does not think so. I have been pulling my hair out for a long time, does anyone have any thoughts?

AS3 Object:

import flash.utils.IDataInput;
 import flash.utils.IDataOutput;
 import flash.utils.IExternalizable;
 import flash.net.registerClassAlias; 

 [Bindable]
 [RemoteClass(alias = "myLobbyData.LobbyData")]
 public class LobbyData implements IExternalizable
 { 

 private var sent:int; // java sentinel
 private var u:String; // red5 username
 private var sen:int; // another sentinel?
 private var ui:int;  // fb uid
 private var fn:String; // fb name
 private var pic:String; // fb pic
 private var inb:Boolean; // is in the table?
 private var t:int; // table number
 private var s:int; // seat number

 public function setSent(sent:int):void 
 {
  this.sent = sent;
 }

 public function getSent():int
 {
  return sent;
 }  

 public function setU(u:String):void
 {
  this.u = u;
 }

 public function getU():String
 {
  return u;
 }  

 public function setSen(sen:int):void
 {
  this.sen = sen;
 }

 public function getSen():int
 {
  return sen;
 }  

 public function setUi(ui:int):void
 {
  this.ui = ui;
 }

 public function getUi():int
 {
  return ui;
 }

 public function setFn(fn:String):void
 {
  this.fn = fn;
 }

 public function getFn():String
 {
  return fn;
 }

 public function setPic(pic:String):void
 {
  this.pic = pic;
 }

 public function getPic():String
 {
  return pic;
 }  

 public function setInb(inb:Boolean):void
 {
  this.inb = inb;
 }

 public function getInb():Boolean
 {
  return inb;
 }  

 public function setT(t:int):void
 {
  this.t = t;
 }

 public function getT():int
 {
  return t;
 }

 public function setS(s:int):void
 {
  this.s = s;
 }

 public function getS():int
 {
  return s;
 }

 public function readExternal(input:IDataInput):void
 {
  sent = input.readInt();
  u = input.readUTF();
  sen = input.readInt();
  ui = input.readInt();
  fn = input.readUTF();
  pic = input.readUTF();
  inb = input.readBoolean();
  t = input.readInt();
  s = input.readInt();  
 }


 public function writeExternal(output:IDataOutput):void
 {
  output.writeInt(sent);
  output.writeUTF(u);
  output.writeInt(sen);
  output.writeInt(ui);
  output.writeUTF(fn);
  output.writeUTF(pic);
  output.writeBoolean(inb);
  output.writeInt(t);
  output.writeInt(s);
 }
    }

Java Object:

    package myLobbyData;
    import org.red5.io.amf3.IDataInput;
    import org.red5.io.amf3.IDataOutput;
    import org.red5.io.amf3.IExternalizable;




    public class LobbyData implements IExternalizable
    {
 private static final long serialVersionUID = 115280920;

 private int sent; // java sentinel
 private String u; // red5 username
 private int sen; // another sentinel?
 private int ui;  // fb uid
 private String fn; // fb name
 private String pic; // fb pic
 private Boolean inb; // is in the table?
 private int t; // table number
 private int s; // seat number

 public void setSent(int sent)
 {
  this.sent = sent;
 }

 public int getSent()
 {
  return sent;
 }  

 public void setU(String u)
 {
  this.u = u;
 }

 public String getU()
 {
  return u;
 }  

 public void setSen(int sen)
 {
  this.sen = sen;
 }

 public int getSen()
 {
  return sen;
 }  

 public void setUi(int ui)
 {
  this.ui = ui;
 }

 public int getUi()
 {
  return ui;
 }

 public void setFn(String fn)
 {
  this.fn = fn;
 }

 public String getFn()
 {
  return fn;
 }

 public void setPic(String pic)
 {
  this.pic = pic;
 }

 public String getPic()
 {
  return pic;
 }  

 public void setInb(Boolean inb)
 {
  this.inb = inb;
 }

 public Boolean getInb()
 {
  return inb;
 }  

 public void setT(int t)
 {
  this.t = t;
 }

 public int getT()
 {
  return t;
 }

 public void setS(int s)
 {
  this.s = s;
 }

 public int getS()
 {
  return s;
 }



 @Override
 public void readExternal(IDataInput input) 
 {
  sent = input.readInt();
  u = input.readUTF();
  sen = input.readInt();
  ui = input.readInt();
  fn = input.readUTF();
  pic = input.readUTF();
  inb = input.readBoolean();
  t = input.readInt();
  s = input.readInt();  
 }

 @Override
 public void writeExternal(IDataOutput output)
 {
  output.writeInt(sent);
  output.writeUTF(u);
  output.writeInt(sen);
  output.writeInt(ui);
  output.writeUTF(fn);
  output.writeUTF(pic);
  output.writeBoolean(inb);
  output.writeInt(t);
  output.writeInt(s);
 }

    }

AS3 Client:

public function refreshRoom(event:Event)
{
var resp:Responder=new Responder(handleResp,null);
ncLobby.call("getLobbyData", resp, null);
}
public function handleResp(o:Object):void
{
var testObject:LobbyData=new LobbyData;    
testObject = o as LobbyData;  
trace(testObject);
}

Java Client

 public LobbyData getLobbyData(String param)
 {
LobbyData lobbyData1 = new LobbyData();
 lobbyData1.setSent(5);
 lobbyData1.setU("lawlcats");
 lobbyData1.setSen(5);
 lobbyData1.setUi(5);
 lobbyData1.setFn("lulz");
 lobbyData1.setPic("lulzagain");
 lobbyData1.setInb(true);
 lobbyData1.setT(5);
 lobbyData1.setS(5);
 return lobbyData1;
}
John Russell
  • 1,115
  • 1
  • 15
  • 30
  • 1
    Always use `ClassName(obj)` syntax instead of `obj as ClassName` syntax for casting. The first one will throw an exception if cast fails, whereas the second one silently returns null and causes a null pointer exception to occur some time later. – Amarghosh May 03 '10 at 07:04
  • As Amarghosh said: you should check that the Object is definitely an instance of the LobbyData class. You can do this with `trace(o is LobbyData);` – icio May 03 '10 at 08:18
  • Thanks for the tips. It is just as I feared: TypeError: Error #1034: Type Coercion failed: cannot convert Object@27c7a11 to myLobbyData.LobbyData. at gameLobby/handleResp() I suspect I am not correctly implementing 'IExternalizable' correctly. I should note that I am following this guide: http://gregoire.org/2008/09/12/using-custom-objects-in-amf3-with-red5/ – John Russell May 03 '10 at 08:55
  • Okay so it definitely has to do with [RemoteClass(alias = "myLobbyData.LobbyData")]. I found something here: http://stackoverflow.com/questions/1671668/how-does-remoteclass-work-in-flex-actionscript-can-i-use-it-for-custom-data-bin It's getting late, I will update when I figure out what's going on. – John Russell May 03 '10 at 09:19
  • Okay so to Deserialize the object, I was using the Flex: [RemoteClass(alias = "myLobbyData.LobbyData")] when I should have been using the pure as3 of: registerClassAlias("myLobbyData.LobbyData", LobbyData); However, this still doesn't work. – John Russell May 03 '10 at 19:58
  • 2
    @Amarghosh. I wouldn't say always... In fact, this is a good place for "as", I think. Just check for null. It makes sense since: 1) the data comes from an external service which you should assume will fail at some point; 2) you probably want to deal with that right away (cleaning up and bailing out, for instance) instead of throwing a TypeError up the stack (an error that can be raised by problems somewhere else). If you are catching the error in the same method, a null check is not more complicated than a catch or finally (in fact, it's simpler and it's also faster, but that's secondary). – Juan Pablo Califano May 05 '10 at 03:36
  • @Amarghosh. The constructor style cast and "as" are equally usable, it's really only a style difference: the former makes since if you're a try/catch kind of guy, and the latter makes sense if you routinely check for null after the cast. Either is acceptable. – Adam Smith Apr 02 '11 at 17:43

3 Answers3

2

As you already figured out, you should use registerClassAlias as the RemoteClass works out of the box only for Flex projects (as bindable, etc).

Be sure to call registerClassAlias before any serializing / deserializing occurs.

Also, the debugger is showing you the actual tipe of your "o" parameter, which is object. This shows that the player is not correctly mapping the AMF serialized object's class to any of your classes (so, by default, it goes with Object). You should see a LobbyData object in the debugger; otherwise, no matter how you cast / coerce it, it won't work.

Juan Pablo Califano
  • 12,213
  • 5
  • 29
  • 42
  • Thanks so much! Now, in order to properly serialize my custom object back to the server from AS3 -> Red5, am I able to simply call a function and pass in the LobbyData type? For example: AS3: ncLobby.call("updateLobbyData",null,lobbyData); JAVA: public void updateLobbyData(LobbyData input) { ArrayList lobbyList = new ArrayList(); lobbyList.add(input); . . . } I ask because when I do this, the red5 server receives it as a LobbyType object, but all the values inside are null. Any thoughts? – John Russell May 05 '10 at 08:03
0

The objet needs to be declared before the responder is called.

public function refreshRoom(event:Event)
{
var testObject:LobbyData=new LobbyData;
var resp:Responder=new Responder(handleResp,null);
ncLobby.call("getLobbyData", resp, null);
}
public function handleResp(o:Object):void
{

testObject = o as LobbyData;  
trace(testObject);
}
John Russell
  • 1,115
  • 1
  • 15
  • 30
0

Actually if you want to workaround the type casting you can simply add this to your constructor:

public function dataAwareObject(o:* = null) { //TODO: implement function super(); if(o){ for(var a:* in o) this[a] = o[a]; } } }

Works like a charm.

daynier
  • 99
  • 1
  • 3