0

I have a problem when passing back an int from flex to java. The int in question is an ID and I seemed to have hit a threshold this morning because things started breaking.

I am passing back 922927950 in flex through blaze to java. By the time the java gets it has been converted to 9.2292795E8

My code in flex is

service.getRemoteObject().sendData(objectIds);

where object ids is an ArrayCollection. In this I can debug and see the number is 922927950. I can then debug the java and see that it has been converted to 9.2292795E8

sendData has the following signature

public void sendData(List<Integer> objectIds) {...}

I have tried changing the flex objectids array to contain numbers and not ints but this does not work either. In java as far as I know to store 9.2292795E8 the number has to be a float. Float does fit inside integer in java so I presume that is why I do not get type mismatch errors. The trouble is that the ids are now in scientific notation that breaks my jpa query which uses them.

Does anyone know why the number is converted into scientific notation?

Thanks

UPDATE

after some more investigation it gets even weirder. I tried the following code in my java

public void sendData(List<Integer> objectIds) {
    List<Integer> converted = new ArrayList<Integer>();

    for (Integer objectId : objectIds) {
        converted.add(objectId);
    }
    ...
}

I now get class cast exceptions saying that I cannot convert double to integer on the converted.add(objectId) line

 java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer

This happens when in flex I cast 922927950 to Number which I presume maps to Double. Is my problem here that I am using generics on the java side and BlazeDs does not consider these so just matches on the signature without generics?

RNJ
  • 15,272
  • 18
  • 86
  • 131

2 Answers2

1

First, look at the Amf3Types documentation:

The maximum value for an int that will avoid promotion to an ActionScript Number when sent via AMF 3 is 2^28 - 1, or 0x0FFFFFFF

This is 268,435,455 in decimal representation and 922,927,950 is far over this limit. Note that it is a serialization issue: the int data type is able to hold a 2^31 - 1 value, just like a regular 32-bits int type.

Now, you should try this with your code:

public void sendData(List<?> objectIds) {
    List<Integer> converted = new ArrayList<Integer>();

    for (Object objectId : objectIds) {
        converted.add(((Number)objectId).intValue());
    }
    ...
}

If you need better control over type conversions and advanced numeric types, you should consider using GraniteDS instead of BlazeDS. See documentation here and here.

Regards, Franck.

Franck Wolff
  • 341
  • 2
  • 5
  • Thanks Franck. I have just done something similar ;) I logged into SO to add this where I was converting the double to an int – RNJ Aug 31 '12 at 15:14
  • Interestingly if i use Number in my flex then this does not work either. I have Integer on my java side so perhaps the mapping is not quite correct there – RNJ Aug 31 '12 at 15:16
  • It doesn't work because BlazeDS isn't trying to convert your list to an integer list (hence the classcast exception). So: with a Flex int above 2^28 - 1 or a Flex Number, you get a Java Double after serialization and this Double can't be directly cast to an Integer... – Franck Wolff Aug 31 '12 at 15:30
  • Thanks Franck. I looked at this earlier and I think it confused me. It said ints are 2^31 although it looks like it is wrong http://stackoverflow.com/a/1249935/846476 – RNJ Aug 31 '12 at 15:36
  • It's actually right: you can store (2^31 - 1) into an int variable in Flash/Flex/ActionScript3. It's only a AMF3 serialization issue because they (Adobe) choose to use variable-length encoding. If you are interesting, read this: http://osflash.org/documentation/amf3 (the "0x04: integer" section). Basically, if your int is in the range [-2^28, +2^28 - 1], it will stay an integer after serialization (you get a Java Integer). Otherwise, it is promoted to a Number and you get a Double on the Java side. Crazy but that's that ;) – Franck Wolff Aug 31 '12 at 16:07
  • :) thanks for the detail Franck. I'll look at that link later tonight – RNJ Aug 31 '12 at 16:25
0

As @Franck Wolff explained, for the technical reason of how values are stored in memory, you get into all kinds of troubles when using large numbers - not just when transferring between Flex and BlazeDS, but with numeric values in general.

Since it seems you're not using these numbers for any calculations, I presume the correct sequence is more important than the value here.

So you should do yourself a favor: Convert the IDs to String, transfer, then use Integer.valueOf( String ) to convert back to numeric values. It's the only way you really know for sure what you're getting on the other side - unless, of course, you're going to write your own serialization classes.

weltraumpirat
  • 22,544
  • 5
  • 40
  • 54
  • Converting numeric values to String is a workaround, better than losing part of the value, but still a workaround. Beside, it can force you to use intermediate DTOs, which is at least cumbersome... – Franck Wolff Sep 01 '12 at 14:13
  • Again, I would suggest to use GraniteDS and its extensive and reliable Java numeric type support: http://www.graniteds.org/public/docs/2.3.2/docs/reference/en-US/html/graniteds.bignumbers.html. But the migration from BlazeDS to GraniteDS may be of course a bit complicated, depending on the current status of the project (see http://granitedataservices.com/migrating-from-blazeds-to-graniteds/). – Franck Wolff Sep 01 '12 at 14:18
  • That really depends on the project. If the amount work that has already been done is in any way significant, I would definitely not rewrite, but just move the conversion to the lowest possible layer (presumably the data access layer, unless using VARCHAR ids in the database is an option) and work with Strings throughout the rest of the program. Also, I can only say this from my own experience: enterprise customers are usually more open to using the Adobe product, even if it is technically inferior. – weltraumpirat Sep 01 '12 at 20:34
  • Yes, you're right, it depends on the project. However, about enterprise customers using Adobe products, one could notice that Flex (and possibly BlazeDS in a near future) isn't anymore an Adobe project and opting for a Flex solution backed by Adobe doesn't seem to be particularly reassuring. – Franck Wolff Sep 04 '12 at 12:29
  • And then, still, Apache is the more well-known address. ;) BTW I can't wait for BlazeDS to change owners - the damn thing needs updates badly, and they haven't worked on it for more than a year, it seems. – weltraumpirat Sep 04 '12 at 15:19
  • Well, I bet you will have to wait quite a bit (http://forums.adobe.com/message/4387107): with about 3 people willing to contribute, it's going to be a long-long-long process before the next Apache BlazeDS release ;) – Franck Wolff Sep 04 '12 at 15:42
  • Well, I count at least 6, myself not included ;) But I wouldn't be surprised if there were more volunteers, once the official announcements are made. – weltraumpirat Sep 04 '12 at 17:52