Issue Details (XML | Word | Printable)

Key: GDS-584
Type: Bug Bug
Status: Reopened Reopened
Priority: Major Major
Assignee: William Draï
Reporter: Damien Feugas
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
GraniteDS

Deserialization error for flash.* object with Gumbo

Created: 08/Dec/09 08:12 AM   Updated: 15/Feb/10 06:29 PM
Component/s: AMF3 (de)serialization
Affects Version/s: 2.0.0_SP1, 2.1.0_RC1
Fix Version/s: None

Environment: Windows XP SP3


 Description  « Hide
Hi there.

Since I used Gumbo (beta1 and now beta2), I encounter a critical bug which prevent from passing flash.* objects through the AMF channel.

I've some java method :
List<MapObject> getObjects(Point from, Point to, Map map, MapFilter[] filter);

And the corresponding converter :

public class PointConverter extends Converter implements Reverter {

    @Override
    protected boolean internalCanConvert(Object value, Type type) {
     Class<?> targetClass = ClassUtil.classOfType(type);
     return (
            Point.class.isAssignableFrom(targetClass) &&
            (value == null || value instanceof Map<?, ?>)
        );
    }

    @Override
    protected Object internalConvert(Object value, Type type) {
     Point point = null;
     if (value != null) {
         Map<?,?> obj = (Map<?,?>)value;
         Exception failed = null;
         try {
         // On cré le point à partir des coordonnées.
         String xValue = obj.get("x").toString();
         String yValue = obj.get("y").toString();
         point = new Point(Integer.parseInt(xValue),
         Integer.parseInt(yValue));
         } catch (Exception exc) {
         failed = exc;
         }
         if (failed != null) {
         throw new IllegalArgumentException("L'objet AS3 original ne " +
         "contient pas les champs numériques x ou y", failed);
         }
     }
     return point;
    }
    
    public boolean canRevert(Object value) {
        return value instanceof Point;
    }

    public Object revert(Object value) {
     Point point = (Point)value;
     Map<String, Number> obj = new HashMap<String, Number>();
     obj.put("x", point.x);
     obj.put("y", point.y);
        return obj;
    }

Correctly declared in the granite-service.xml

    <converters>
     <converter type="com.myth.chronos.front.granite.converters.PointConverter" />
 

I've got the following error :
08-12-2009 07:55:36:515 ERROR AMFMessageFilter - AMF message error
org.granite.messaging.amf.io.AMF3SerializationException
at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:94)
at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Array(AMF3Deserializer.java:261)
at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:124)
at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:88)
at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Array(AMF3Deserializer.java:261)
at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:124)
at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:403)
at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:126)
at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:88)
at org.granite.messaging.amf.io.AMF0Deserializer.readAMF3Data(AMF0Deserializer.java:310)
at org.granite.messaging.amf.io.AMF0Deserializer.readData(AMF0Deserializer.java:362)
at org.granite.messaging.amf.io.AMF0Deserializer.readArray(AMF0Deserializer.java:225)
at org.granite.messaging.amf.io.AMF0Deserializer.readData(AMF0Deserializer.java:348)
at org.granite.messaging.amf.io.AMF0Deserializer.readBodies(AMF0Deserializer.java:141)
at org.granite.messaging.amf.io.AMF0Deserializer.<init>(AMF0Deserializer.java:79)
at org.granite.messaging.webapp.AMFMessageFilter.doFilter(AMFMessageFilter.java:110)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)
Caused by: org.granite.config.GraniteConfigException: Could not load class: flash.geom.Point
at org.granite.config.GraniteConfig.getElementByType(GraniteConfig.java:810)
at org.granite.config.GraniteConfig.getActionScriptDescriptor(GraniteConfig.java:402)
at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:314)
at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:126)
at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:88)
... 27 more
Caused by: java.lang.ClassNotFoundException: flash.geom.Point
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1387)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1233)
at org.granite.util.ClassUtil.forName(ClassUtil.java:90)
at org.granite.config.GraniteConfig.getElementByType(GraniteConfig.java:808)
... 31 more

After a few investigation, I noticed that in the org.granite.messaging.amf.io.AMF3Deserializer.eadAMF3Object() line 308-315 :

                String className = readAMF3String();
                if (debug) log.debug("readAMF3Object() - className=%s", className);

                // try to find out custom AS3 class descriptor
                Class<? extends ActionScriptClassDescriptor> descriptorType = null;
                if (!"".equals(className))
                    descriptorType = context.getGraniteConfig().getActionScriptDescriptor(className);
                if (debug) log.debug("readAMF3Object() - descriptorType=%s", descriptorType);

The problem seems to be that in Gumbo, for flash.* objects, the classeName is provided in the AMF3 stream, triggering the AMF3Deserializer search for it in the javaclassloader. I suspect that before Gumbo, the className information was not filled for flash.* objects. Unfortunately, I haven't found any clue in Adob's changelogs.

Thanks for all !

Damien.

William Draï added a comment - 29/Dec/09 12:56 PM
I cannot reproduce this with any version of Flex 4.
Are you sure you don't have a library somewhere that sets a flash.net.registerClassAlias("flash.geom.Point", Point) ?

As a workaround, you can probably just create a dummy Java class named flash.geom.Point and handle it in your converter.

Damien Feugas added a comment - 10/Feb/10 08:52 AM
Hello.

I could not work on my project since at least two month...
I created a test project to reproduce the problem, but was unsucessful as you said.

So you can close the bug. I'll investigate further on the cause, visibly due to a GDS misuse in my project, and rather post messages on the forum.

Thank you for your time !

Damien

William Draï added a comment - 10/Feb/10 11:51 AM
ok, no problem

Damien Feugas added a comment - 11/Feb/10 08:55 AM
At last !!!!

The problem was from degrafa (you probably known this famous graphical library).
Somewhere in their code, in class com.degrafa.geometry.command.CommandStackItem, there is a :

registerClassAlias("flash.geom.Point", Point)|| registerClassAlias("flash.geom.Rectangle", Rectangle));

That's why the serialization failed when combining with GDS...

I'll try to post something on their issue tracker, but it seems they often use aliases.
Any idea to combine the two libraries ?

William Draï added a comment - 15/Feb/10 12:49 PM
I reopen the issue, maybe we can improve this behaviour by ignoring ClassNotFound when there is a converter.
Not sure it will do in 2.1.

William Draï added a comment - 15/Feb/10 06:29 PM
That won't be in 2.1.
Quick patch in AMF3Deserializer, line 312 :

                // try to find out custom AS3 class descriptor
                Class<? extends ActionScriptClassDescriptor> descriptorType = null;
                if (!"".equals(className)) {
                 try {
                 descriptorType = context.getGraniteConfig().getActionScriptDescriptor(className);
                 }
                 catch (GraniteConfigException e) {
                 className = "";
                 }
                }

but this is probably not very safe for other cases.