Even with externalizers, there is still a problem with classes that do not declare a default constructor: how do we instanciate those classes with meaningful parameters? Granite DS externalizers may be used without anything else when you are using the Sun JVM: if no default constructor is found, Granite DS externalizer will try to use the sun.reflect.ReflectionFactory class that allows instanciation of such classes. Then, fields deserialization will follow the above process (with the lexical order rule).
For example, one could use this granite-config.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE granite-config PUBLIC "-//Granite Data Services//DTD granite-config internal//EN" "http://www.graniteds.org/public/dtd/1.0.0/granite-config.dtd"> <granite-config> <externalizers> <externalizer type="org.granite.messaging.amf.io.util.DefaultExternalizer"> <include type="java.util.Locale"/> </externalizer> </externalizers> </granite-config>
and this ActionScript 3 implementation:
package test.util { import flash.utils.IExternalizable; import flash.utils.IDataInput; import flash.utils.IDataOutput; [RemoteClass(alias="java.util.Locale")] public class Locale implements IExternalizable { private var _country:String; private var _language:String; private var _variant:String; public function get country():String { return _country; } public function get language():String { return _language; } public function get variant():String { return _variant; } public function readExternal(input:IDataInput):void { _country = input.readObject() as String; _language = input.readObject() as String; _variant = input.readObject() as String; } public function writeExternal(output:IDataOutput):void { output.writeObject(_country); output.writeObject(_language); output.writeObject(_variant); } } }
If you do not use a Sun JVM (or if you dislike this kind of hack), you may use a specialized instanciator. An instanciator must extend the org.granite.messaging.amf.io.util.instanciator.AbstractInstanciator class and implement two methods:
package org.granite.messaging.amf.io.util.instanciator; ... public abstract class AbstractInstanciator<T> extends HashMap<String, Object> { ... public abstract T newInstance(); public abstract List<String> getOrderedFieldNames(); ... }
There is already a standard implementation for java.util.Locale in Granite DS:
package org.granite.messaging.amf.io.util.instanciator; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; public class LocaleInstanciator extends AbstractInstanciator<Locale> { private static final long serialVersionUID = 1L; private static final List<String> orderedFields; static { List<String> of = new ArrayList<String>(3); of.add("country"); of.add("language"); of.add("variant"); orderedFields = Collections.unmodifiableList(of); } public LocaleInstanciator() { super(); } @Override public Locale newInstance() { String language = noNull((String)get("language")); String country = noNull((String)get("country")); String variant = noNull((String)get("variant")); return new Locale(language, country, variant); } @Override public List<String> getOrderedFieldNames() { return orderedFields; } private static String noNull(String s) { return s != null ? s : ""; } }
The getOrderedFieldNames method returns a list of field names that will be used by the DefaultExternalizer in order to (de)serialize java.util.Locale fields in a predictable order ("country", "language", "variant"). The lexical order in this example is purely accidental: ActionScript 3 implementation must only follow the rule defined here. When Granite DS AMF3 deserializer will need to instanciate this class, it will call the newIntance method of the instanciator (after reading all field values). Since AbstractInstanciator extends HashMap, field values may be retrieved by a Map.get method.
You should finally modify the granite-config.xml file as follow in order to use this instanciator:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE granite-config PUBLIC "-//Granite Data Services//DTD granite-config internal//EN" "http://www.graniteds.org/public/dtd/1.0.0/granite-config.dtd"> <granite-config> <instanciators> <instanciator type="java.util.Locale"> org.granite.messaging.amf.io.util.LocaleInstanciator </instanciator> </instanciators> <externalizers> <externalizer type="org.granite.messaging.amf.io.util.DefaultExternalizer"> <include type="java.util.Locale"/> </externalizer> </externalizers> </granite-config>
|
Browse Space |
Explore Confluence |
Your Account |
Add Content |
|
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.6.0 Build:#913 Sep 27, 2007) |
|
|
|