Hi,
When I serialize to AMF3 a BigDecimal which it's value is null, on the client Flex app side I recieve 0 instead of null or NaN.
What I would like is that when a java variable pointed to null is serialized, on the client Flex app I recieve null or NaN(if it's a Number on the client side).
Also when I serialize NaN from flex client I would like it to be deserialized to null on the Java side.
Is there any way to customize that specific object serialization?
I have read in some places that mentioned the use of a custom bean proxy. But I couldn't find how to implement or configure such a thing.
I'm using BalzeDS AMF3 serialization classes.
thanks in advance,
Polaco.
Hi,
You can find more info in that bug : https://bugs.adobe.com/jira/browse/BLZ-305
Basically, making a custom BeanProxy consist of making a subclass of BeanProxy.
To then use it, you need at he initialization of your application to do something like this :
PropertyProxyRegistry.getRegistry().register(rootClass, new MyBeanProxy());
rootClass being the class, comon superclass or interface of the object for which the BeanProxy has been implemented.
Hope this help,
Nicolas.
Hi Nicolas,
I have read your post on https://bugs.adobe.com/jira/browse/BLZ-305 and really liked your solution. I wondered if you could post some code example about how to create and the steps to registrate the custom marshaller you are talking about. I'm quite lost about how to do this.
Thanks a lot for your time.
Polaco.
Hi Polaco,
First,for the BeanProxy, registering against Object class isn't really a great idea and can have some side effects, as I found out recently. If it's possible it's better to use a marker interface, an empty interface that the object you want to serialize with the customization will implement and register the BeanProxy against that interface.
For the marshaller, I found the idea in the BlazeDS dev guide, here http://forums.adobe.com/thread/535610?tstart=0 .
In the channel definition inside the services-config.xml file, you can specify a <serialization> tag with several options including type-marshaller.
That's where you have to configure to use your own implementation of the TypeMarshaller interface.
The class implementing it in BlazeDS is ASTranslator, and I think there is also a subclass specific for Java 1.5, can't find the name right now, but I know it's there. So the easiest way to make your own is to have a look at this class, subclass it and adapt with what you wanna do.
Hope this help,
Nicolas.
Hi Nicolas,
Thanks a lot for your help.
My first question is: Do I have to implement the Marshaller, the BeanProxy or both?
I really don't get how could I create a marker interface for Java Number subclasses maybe I could set the beanproxy for java.lang.Number?
I've been reading the Blaze Dev Guide section "Using custom serialization between ActionScript and Java". Which has been useful. However the thing I did not mention is that I was not using Blaze, just it's AMF serialization deserialization features so it doesn't seem to be possible to configure a marshaller in my case.
The motive why I'm not using it is that I wanted to implement a Flex UI with a JSR168 Portlet as a backend and Blaze channels and all that stuff wasn't suitable for that task.
So what I did is that the Flex layer sends (via HTTPService) an AMF serialized objects in a URL request parameter, the portlet backend take this parameter, deserializes it and answers the request with other AMF serialized response.
Due to this I see no way to configure the custom marshaller from Blaze config. But instead I have seen that maybe would be possible to create a new implementation of flex.messaging.io.amf.AmfOutput and flex.messaging.io.amf.AmfInput that seems to be the classes used for serializing and deserializing in this case. (I have added and repackage this classes inside my project to be able to extend them)
Since there is no documentation on how to use AMF3 serialization without Blaze I'm not pretty sure this is the right direction or not.
Also I want to leave clear I could use this way of sending messages AMF serilized data between Flex and Portlets with success just this issue of the Number is a bit bothering.
What do you think about this?
thanks again for your time,
Polaco.
ps:
I have attached 2 files in case you wanna take a look and this "abomination" ![]()
AMFWebTest.zip:contains a simple webapp I did to test to check if was possible to translate this to a portlet architecture, updated with the changes I mentioned before.
AMFClientTest.zip: contains a simple user interface I did to send messages to the java webapp.
Hi Polaco,
I'm not sure adding and repackaging those classes is really authorized. Adding the jar to your project and making sub-classes is probably a better way of doing it.
Anyway, you will face an issue : when you want to send null from java to flex, AmfOutput is already too late to make a conversion to NaN.
The reason is that hte only thing you have is null, not the actual type of the variable. So you have no way to change it to NaN when it is number related.
That's why I had to use the BeanProxy, at that point, you can find out the type of each properties of a bean, so you can convert to NaN when the type is BigDecimal or other Number kind and the value is null.
Well at least that's the conclusion I've reached so far.
For the typeMarshaller, t's used somewhere in the input process, but I can't find out where tonight, I'll have a look tomorrow.
Regards,
Nicolas.
Hi Nicolas,
I see the legal issue you mention, but there is no way to extend that classes without repackaging them, except adding my own class inside the original packages and rebuilding the jars because they access to several protected methods and properties.
Anyway lets suppouse we go with the BeanProxy solution. Do I have to implement the Marshaller and the BeanProxy or just a BeanProxy and register it as you mentioned before?
Maybe instead of a marker interface I could use for Java Number subclasses the java.lang.Number class?
Something like:
PropertyProxyRegistry.getRegistry().register(java.lang.Number, new MyNumberBeanProxy());
Can I registrate the bean proxy in that way?
thanks again,
best regards,
Polaco.
Hi Nicolas,
Setting the BeanProxy as you said:
PropertyProxyRegistry.getRegistry().register(java.lang.Object.class, new MyNumberProxy());
And creating the following MyNumberProxy (taking your BeanProxy as example):
import java.math.BigDecimal;
import java.math.BigInteger;
import flex.messaging.io.BeanProxy;
/**
* Uses Bean introspection to collect the properties for a given instance.
*
* @author Peter Farland
*/
public class MyNumberProxy extends BeanProxy
{
/** {@inheritDoc} */
public Object getValue(Object instance, String propertyName){
Class propertyType = getBeanProperty(instance, propertyName).getType();
Object result = super.getValue(instance,propertyName);
if (result == null
&& (BigDecimal.class == propertyType
|| BigInteger.class == propertyType
|| Integer.class == propertyType
|| Long.class == propertyType
|| Double.class == propertyType
)
)
{
return new Double(Double.NaN);
}
return result;
}
public void setValue(Object object, String propName, Object value){
if(value.getClass().equals(Double.class) && Double.isNaN(((Double)value).doubleValue())){
super.setValue(object, propName, null);
}else{
super.setValue(object, propName, value);
}
}
}
I could send NaN values from flex layer and transform them to null values on the Java side, also could send null Java values as NaN to flex.
This seems to be what I was looking for. I wonder why you dislike this solution or find it inapropiate?
Also, even I have achieved what I was looking for I am not very sure about how all this process takes place and i find this a bit dangerous since I can recommend or implement something I do not understand how is it happening coz I wouldn't be able to foresee possible problems with it.
So would be great to understand deeper this serlialization/deserialization process. How the execution order of Marshallers, BeanProxys and any other thing that intervenes takes place and when.
Unhappily I didn't find the Blaze dev guide or AMF3 APIs doc too extense in this topics. For instance the word "BeanProxy" is never mentioned in Blaze dev guide.
Could you recommend me some readings about this process?
thanks a lot for your helping hand and advices,
greetings,
Polaco.
Hi Polaco,
Normally you can access the protected method from subclasses even in another package.
The type marshaller has the advantage of dealing not only withbeans but also with parameters you pass to a method call. I guess in your case it doesn't really matter.
Regarding the registration against the Object class, the issue is in the way BlazeDS works. BlazeDS is making messages, and those messages are of course subclasses of Object. And those messages including Ack are serialized the same way your objects are. That's where the side-effect can and, more than likely, will occurs.
The problem is that you're not only customizing your own objetcs but also the one used by BlazeDS.
The best way to understand how all of this works is to launch your sever in debug mode, put breakpoints and launch something.
Here is how I understood it is working :
When BlazeDS serialize or deserialize something, if it's not a simple type, he will look for a BeanProxy registered to the class of the object. First against the actual class, then against the implemented interfaces, then it goes up in the class hierachy. If it doesn't find any, it will create one based on the default BeanProxy.
Then, it will use this BeanProxy to have the list of properties of the class, and will getValue or setVlaue when he's reading or writting something on an object.
There is also a method that handle the creation of the actual object.
If I understand well the idea behind that, the goal is to have blazeDs use the proxy instead of the actual objects and classes so it can uses caches instead of actually using reflexion all the time.
This article is about implementing a beanProxy to add some anotation features to BlazeDS http://www.flexpasta.com/index.php/2008/05/19/blazeds-with-annotations -for-remote-objects/
And this one is using this mechanism to propose a way of handling enum serialization http://flexblog.faratasystems.com/2007/09/16/adding-enum-support-to-fl ex-amf-protocol
Hope this help,
Nicolas.
Hi Nicolas,
I have been debugging the code quite a while but couldn't find a place were to set by code a custom marshaller. What I could do is to extend the AMF3Input and AMF3Output classes to obtain the same serialization I was getting with the custom beanproxy. ( You were rigth about the 'protected' observation you made me, I don't know what I was doing
)
Since I am using AMF3 without Blaze it almost seems the same (for me) to use the BeanProxy registered to Object or the custom AMF3 classes.
just to let you know,
kind regards,
Polaco.
Hi Polaco,
In BlazeDS the typeMarshaller is set directly on the EndPoint, the code is in the AbstractEndpoint class, so I think this part doesn't apply to your case.
It's also used in the BeanProxy class in the setValue method where it's retreived from TypeMarshallingContext. I don't know where it's set there in blazeDS, but there is a static method setTypeMarshaller there.
The other place where it's used in BlazeDS and that make the TypeMarsaller more interesting that the BeanProxy in my case is the MethodMatcher class, where the convertParams method also use the typeMarshaller coming from the TypeMarshallingContext.
I didn't tried serializing without BlazeDS yet, so I can't really make alot of comment, but if you don't use BlazeDS, you shouldn't have the message issue.
For AMF3Input and Ouput, yes you could, as long as you can find a way to decide if a null from Java need to be sent as is or converted to NaN.
Regards,
Nicolas.
North America
Europe, Middle East and Africa
Asia Pacific