3 Replies Latest reply on Oct 16, 2008 12:52 AM by max__

    Remote Types with inheritance not being Converted Properly

    awaterma
      Hi,

      I've been struggling with this for about a week now, so a friend suggested I post to the forums. Basically, I use BlazeDS to call a remote method on a Java service that interacts with some EJBs on our server. This method returns an ArrayList, consisting of "GamePlayer" objects. Flex picks up the correct ActionScript mapped class "GamePlayer.as" and everything works well.

      So, I have a subclass of GamePlayer, "PentePlayer", that is returned in the array by this method in some cases. This class is correctly converted by Flex and mapped to its complimentary AS Class, "PentePlayer.as". So far, so good.

      However, when I extend "PentePlayer" into a third class, "StrategyPlayer", things don't work out so well. (I have written an AS class that maps the two new fields this Java class uses, extended "PentePlayer.as", and set the "remote" meta-tag to properly point to the Java class, "StrategyPlayer"). When I make the call to my service returning a list that mixes PentePlayers with StrategyPlayers, I receive only PentePlayer.as objects. All instances of "StrategyPlayer" are mapped as ASObjects, each containing all of the fields that a PentePlayer.as has, but no indication of inheritance, and, again, no mapping to the ActionScript type (StrategyPlayer.as).

      I've pulled down the BlazeDS source, and can step through code seeing the result get returned properly by my service (as an array of PentePlayer and StrategyPlayer Java objects), but I can't seem to find where the conversion to ASObjects happens. It looks as though this is done on the client side, after the receipt of the Acknowledge message sent by the server (the return result looks to be packed into this Ack message), but I can't find where in the BlazeDS code.

      My questions are:

      1. Has anyone seen these kinds of problems with a remoted AS class on an inheritance chain before?
      2. Does anyone know where I can monitor the conversions of remoted AS objects to Java in the BlazeDS source code?
      3. Can I handle the type conversion process myself? Or push some type of hints into Blaze so this will convert properly?

      Any other comments, advice, would be warmly received.
        • 1. Re: Remote Types with inheritance not being Converted Properly
          SujitG Level 2
          Hi,

          Conversion from Java class type to the AS class type happens on the client side and is done by the Flash player. I never faced problem with the conversion before. Please check if the mapping is propert, try cleaning the project. Also try registering the class alias in the code using the registerClassAlias function. Please find more details on this function at the URL below.

          http://livedocs.adobe.com/flex/3/langref/flash/net/package.html#registerClassAlias()

          It will be great if you can share the PentePlayer, StrategyPlayer Java and ActionScript source files, so that we can see if we something is missing. You can also mail those classes.

          Hope this helps.
          • 2. Re: Remote Types with inheritance not being Converted Properly
            awaterma Level 1
            Hi,

            Many thanks to you for your reply and thoughts towards resolving this issue.

            My friend who I suggested I post to the forums resolved my problem this morning; apparently the Java class, "StrategyPlayer" was not being compiled into the .swf file. He writes:

            quote:

            Conversion problem solved. StrategyPlayer was not getting compiled into the swf. Took me a while to work this out but has been good for learning a bit more about how blazeds works. You were right, all java objects are serialized into an AMF binary stream without checking for the presence of their equivalent actionscript objects. There is no table of relations between actionscript objects and java objects. This is quite normal when you think about it as the server side java code has no awareness of the clientside swf and even if it did it would have to be able to read the compiled swf classes to get the information about their remote mappings. You probably already found this but the serialization of java objects to the AMF binary stream happens in flex.messaging.io.amf.Amf3Output.java, more specifically in the method writePropertyProxy (line 525). So all java objects are serialized and sent to the client. I imagine that when they arrive in the client flashplayer deserializes them as actionscript objects. It's flashplayer therefore that has the table of remote mappings, and for each object it deserializes it must look for a remote mapping and if it doesn't find one instantiate it as a generic flex object. In the case of StrategyPlayer since it was not getting compiled into the swf flashplayer had no way of mapping or instantiating it, hence our problem. I don't know if there are ways to get flashplayer to log its deserialization so that we can detect these types of problems. I'll look into it. Why, you may ask, was StrategyPlayer not getting compiled into the swf? This is the bit that i don't like very much. The flex compiler starts at the main application class (in our case src/main/flex/main.mxml) and compiles its dependencies recursively. OK, all fine, in RegistrationWindow.mxml you had imported StrategyPlayer so it should therefore get compiled into the swf? But this is the odd bit, importing the file is not enough, for the compiler to consider the class a dependency it has to be "used" in the class. This seems like strange behavior to me but i suppose that its a measure taken to optimize the size of the compiled swf's and remove unnecessary imports? So if you don't really need a class in your code but you do need the remote mapping how can you force the compiler to consider that you are "using" the class. Well the cleanest way i have found is simply to write the class name somewhere in some method. I have done this is in the updatePlayers method of PenteGameController but you can move it elsewhere if you prefer.


            The behavior my friend describes looks like it exposes a bug in Flash player, with regards to how Java and AS conversion is handled in the case of inheritance. Flash/Flex should recognize our serialized object "StrategyPlayer" as a member of the "GamePlayer" family. One would expect all subclasses that are not explicitly referenced in the application to be instantiated as the next member of that family of types that the client is aware of, not just instantiated as raw "ASObjects". It seems that Flex should either include all subclasses of Java types that map to ActionScript classes, or some inheritance information that applies to the type should be included in the serialization stream so as to handle objects on the inheritance tree that are not referenced in concrete, local classes.

            We are thinking of posting a bug on the issue, as it's a bit thorny. Love to hear what other Flex developers think!
            • 3. Re: Remote Types with inheritance not being Converted Properly
              max__ Level 1
              I'm not sure that its easy to fix. Let me think...

              1) Blaze serializes java objects into AMF without knowing who is going to consume them
              2) Flashplayer deserializes objects in AMF into actionscript objects according to the remote aliases defined in the swf.

              So for what you are asking for to work the AMF specification would have to contain information about type hierarchies and flash player would have to use this information to search for the first parent type of an object when serializing it.

              The AMF specification is public and can be found here http://download.macromedia.com/pub/labs/amf/amf3_spec_121207.pdf

              As far as i can see there is no information on type hierarchies included in this spec. The spec would have to be changed and the flashplayer code (which i think is closed source) would have to be modified.

              I imagine that the idea behind AMF is that it should be a compact format that only carries the minimum information that the client needs so as to optimize bandwidth etc.

              I'm not sure whether this functionality would conflict with that philosophy but I suppose we could still file a feature request.

              Does anyone know where would be the right place to do this?