2
votes

I am trying to send a date from flex side to java using BlazeDS

field type in flex

private var _scheduleDate:Date;

I have initialized it with new Date() , and if alert it, correct date and time is displayed as on my system. now when the object is sent to java. the date get changed.

Please note that my flex application and java (JBoss server is running on same machine). If i independently print a date on java side initialized with new Date(), it also display correct date as of the system.

Now conversion part: on flex it was

25/04/2013 12:30 PM (as Alert displayed)

when i print this passed date(at java side), its

25/04/2013 02:30 PM (2 hours difference)

I have read many blogs etc for the solution, they refer it a time zone issue, but i didnt get it, if client and server are both on single system, how could time zone issue causes this problem.

Alert(flex) and println(java) with new Date() display correct date as of the system, so how that timezone issue comes in. only i can think of is, BlazeDS is causing this issue.

Here in this link they have refered some custom marshling for blazeDS but it went above my head Custom Marshalling from Java to Flex via BlazeDS

Right now i have only one solution for this problem to send date in String as plain text instead of Date object and convert String back to Date object on java side.

Is there any better solution or if there is any issue with my understanding can someone please point out that.

Thanks,

2
Struggling same problem for last few daysTimofei Davydik
Is the date being converted to UTC when passing from client to server, but somehow not getting converted back?JeffryHouser
I am not sure but when i print received date in java the string value includes "CDT" which i googled and its (Central Daylight Time) otherwise if i print new Date() on java or flex both display it as GMT+5 in string valuePHP Avenger

2 Answers

2
votes

I suggest the following solution.

First, send client timezone offset and store it as a session attribute.

Flex

ro.setClientTimezoneOffset(-new Date().getTimezoneOffset() * 60 * 1000);

Java

public void setClientTimezoneOffset(Long t) {
    FlexContext.getFlexSession().setAttribute("clientTimezoneOffset", t);
}

Create our own endpoint class extending flex.messaging.endpoints.AMFEndpoint and point it at channel definition:

services-config.xml

<channel-definition id="my-amf"
            class="mx.messaging.channels.AMFChannel">
    <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" 
                class="com.package.AMFEndpoint"/>
</channel-definition>

AMFEndpoint.java

package com.package;

public class AMFEndpoint extends flex.messaging.endpoints.AMFEndpoint {

    @Override
    protected String getSerializerClassName() {
        return Serializer.class.getName();
    }

    @Override
    protected String getDeserializerClassName() {
        return Deserializer.class.getName();
    }
}

Extend amf serializer, deserializer, amf input/output:

Serializer.java

package com.package;

import flex.messaging.io.MessageIOConstants;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfMessageSerializer;
import flex.messaging.io.amf.AmfTrace;

import java.io.OutputStream;

public class Serializer extends AmfMessageSerializer {
    @Override
    public void initialize(SerializationContext context, OutputStream out, AmfTrace trace) {
        amfOut = new AMF0Output(context);
        amfOut.setOutputStream(out);
        amfOut.setAvmPlus(version >= MessageIOConstants.AMF3);

        debugTrace = trace;
        isDebug = trace != null;
        amfOut.setDebugTrace(debugTrace);
    }
}

Deserializer.java

package com.package;

import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfMessageDeserializer;
import flex.messaging.io.amf.AmfTrace;

import java.io.InputStream;

public class Deserializer extends AmfMessageDeserializer {
    @Override
    public void initialize(SerializationContext context, InputStream in, AmfTrace trace) {
        amfIn = new AMF0Input(context);
        amfIn.setInputStream(in);

        debugTrace = trace;
        isDebug = debugTrace != null;
        amfIn.setDebugTrace(debugTrace);
    }
}

AMF0Input.java

package com.package;

import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf0Input;

import java.io.IOException;

public class AMF0Input extends Amf0Input {
    public AMF0Input(SerializationContext context) {
        super(context);
    }

    @Override
    public Object readObject() throws ClassNotFoundException, IOException {
        if (avmPlusInput == null) {
            avmPlusInput = new AMF3Input(context);
            avmPlusInput.setDebugTrace(trace);
            avmPlusInput.setInputStream(in);
        }
        return super.readObject();
    }
}

AMF0Output.java

package com.package;    

import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf0Output;

public class AMF0Output extends Amf0Output {
    public AMF0Output(SerializationContext context) {
        super(context);
    }

    @Override
    protected void createAMF3Output()
    {
        avmPlusOutput = new AMF3Output(context);
        avmPlusOutput.setOutputStream(out);
        avmPlusOutput.setDebugTrace(trace);
    }
}

And finally you extend amf 3 input/output classes, where date is serialized and deserialized. You apply offset difference.

AMF3Input.java

package com.package;

import flex.messaging.FlexContext;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Input;

import java.io.IOException;
import java.util.Date;

public class AMF3Input extends Amf3Input {
    @Override
    protected Date readDate() throws IOException {
        Date d = super.readDate();
        if (d != null) {
            Long clientOffset = (Long) FlexContext.getFlexSession().getAttribute("clientTimezoneOffset");
            Long serverOffset = (Long) (-d.getTimezoneOffset() * 60L * 1000);
            d.setTime(d.getTime() - (serverOffset - clientOffset));
        }
        return d;
    }

    public AMF3Input(SerializationContext context) {
        super(context);
    }
}

AMF3Output.java

package com.package;

import flex.messaging.FlexContext;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Output;

import java.io.IOException;
import java.util.Date;

public class AMF3Output extends Amf3Output {
    public AMF3Output(SerializationContext context) {
        super(context);
    }

    @Override
    protected void writeAMFDate(Date d) throws IOException {
        if (d != null) {
            Long clientOffset = (Long) FlexContext.getFlexSession().getAttribute("clientTimezoneOffset");
            Long serverOffset = (Long) (-d.getTimezoneOffset() * 60L * 1000);
            d.setTime(d.getTime() + (serverOffset - clientOffset));
        }
        super.writeAMFDate(d);
    }
}

Now all dates, passed between Flex front-end and BlazeDS back-end will be automatically converted. Note, that you actually change the date.

Assume server time zone is GMT+6, and client is in GMT+2 timezome. You're retrieving date from database. The date on java is 01.01.2013 10.00.00 GMT+6, normally flex would get 01.01.2013 06.00.00 GMT+2. It's the same date, but String equivalent differs. In our case flex will get 01.01.2013 10.00.00 GMT+2. We changed the date. But string equivalent is the same.

0
votes

In addition create another class for compatibility with previous versions of Java:

package br.com.ultreia.flex;

import java.io.OutputStream;

import flex.messaging.io.MessageIOConstants;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfTrace;

public class Java15AmfMessageSerializer extends flex.messaging.io.amf.Java15AmfMessageSerializer{
    @Override
    public void initialize(SerializationContext context, OutputStream out, AmfTrace trace) {
        amfOut = new AMF0Output(context);
        amfOut.setOutputStream(out);
        amfOut.setAvmPlus(version >= MessageIOConstants.AMF3);

        debugTrace = trace;
        isDebug = trace != null;
        amfOut.setDebugTrace(debugTrace);
    }
}

And I changed the class AMFEndpoint.java

public class AMFEndpoint extends flex.messaging.endpoints.AMFEndpoint {

    public AMFEndpoint(){
        super();
    }

    @Override
    protected String getSerializerClassName() {
        return Serializer.class.getName();
    }

    @Override
    protected String getSerializerJava15ClassName() {
        return Java15AmfMessageSerializer.class.getName();
    }

    @Override
    protected String getDeserializerClassName() {
        return Deserializer.class.getName();
    }
}