It is quite simple to do it, you write the object down to file, then you read it:
http://corlan.org/2008/09/02/storing-data-locally-in-air/
http://cookbooks.adobe.com/post_Storing_ActionScript_Objects_in_the_Encrypted_Loca-10563.html
My questions are
why when we put [RemoteClass(alias="foo.Bar")] into VO, it can be
cast automatically (otherwise the type of the deserialized object is
Generic Object with correct properties data inside it)?
Is there another way to achieve it without RemoteClass tag? (Using metadata tag is preference)
Thanks
The answer is in the page you linked to:
Note that the alias is a key that is stored with the class instance
and links the class definition with the specific object that is stored
in the ByteArray when an instance of that object is serialized. This
key can be any unique string identifying this class, but convention is
to use the fully normalized package and class name.
That's why you get a generic object if you omit the alias - the deserialization method does not know what to do with the data, unless you specify to which class the values should be mapped.
Yes, there is: registerClassAlias() does the same thing. But the metadata tag is much prettier to read ;)
Related
I've been working with JSON.net for a while. I have written both custom converters and custom contract resolvers (generally from modifying examples on S.O. and the Newtonsoft website), and they work fine.
The challenge is, other than examples, I see little explanation as to when I should use one or the other (or both) for processing. Through my own experience, I've basically determined that contract resolvers are simpler, so if I can do what I need with them, I go that way; otherwise, I use custom JsonConverters. But, I further know both are sometimes used together, so the concepts get further opaque.
Questions:
Is there a source that distinguishes when to user one vs. the other? I find the Newtonsoft documentation unclear as to how the two are differentiated or when to use one or the other.
What is the pipeline of ordering between the two?
Great question. I haven't seen a clear piece of documentation that says when you should prefer to write a custom ContractResolver or a custom JsonConverter to solve a particular type of problem. They really do different things, but there is some overlap between what kinds of problems can be solved by each. I've written a fair number of each while answering questions on StackOverflow, so the picture has become a little more clear to me over time. Below is my take on it.
ContractResolver
A contract resolver is always used by Json.Net, and governs serialization / deserialization behavior at a broad level. If there is not a custom resolver provided in the settings, then the DefaultContractResolver is used. The resolver is responsible for determining:
what contract each type has (i.e. is it a primitive, array/list, dictionary, dynamic, JObject, plain old object, etc.);
what properties are on the type (if any) and what are their names, types and accessibility;
what attributes have been applied (e.g. [JsonProperty], [JsonIgnore], [JsonConverter], etc.), and
how those attributes should affect the (de)serialization of each property (or class).
Generally speaking, if you want to customize some aspect of serialization or deserialization across a wide range of classes, you will probably need to use a ContractResolver to do it. Here are some examples of things you can customize using a ContractResolver:
Change the contract used for a type
Serialize all Dictionaries as an Array of Key/Value Pairs
Serialize ListItems as a regular object instead of string
Change the casing of property names when serializing
Use camel case for all property names
Camel case all property names except dictionaries
Programmatically apply attributes to properties without having to modify the classes (particularly useful if you don't control the source of said classes)
Globally use a JsonConverter on a class without the attribute
Remap properties to different names defined at runtime
Allow deserializing to public properties with non-public setters
Programmatically unapply (ignore) attributes that are applied to certain classes
Optionally turn off the JsonIgnore attribute at runtime
Make properties which are marked as required (for SOAP) not required for JSON
Conditionally serialize properties
Ignore read-only properties across all classes
Skip serializing properties that throw exceptions
Introduce custom attributes and apply some custom behavior based on those attributes
Encrypt specially marked string properties in any class
Selectively escape HTML in strings during deserialization
JsonConverter
In contrast to a ContractResolver, the focus of a JsonConverter is more narrow: it is really intended to handle serialization or deserialization for a single type or a small subset of related types. Also, it works at a lower level than a resolver does. When a converter is given responsibility for a type, it has complete control over how the JSON is read or written for that type: it directly uses JsonReader and JsonWriter classes to do its job. In other words, it can change the shape of the JSON for that type. At the same time, a converter is decoupled from the "big picture" and does not have access to contextual information such as the parent of the object being (de)serialized or the property attributes that were used with it. Here are some examples of problems you can solve with a JsonConverter:
Handle object instantiation issues on deserialization
Deserialize to an interface, using information in the JSON to decide which concrete class to instantiate
Deserialize JSON that is sometimes a single object and sometimes an array of objects
Deserialize JSON that can either be an array or a nested array
Skip unwanted items when deserializing from an array of mixed types
Deserialize to an object that lacks a default constructor
Change how values are formatted or interpretted
Serialize decimal values as localized strings
Convert decimal.MinValue to an empty string and back (for use with a legacy system)
Serialize dates with multiple different formats
Ignore UTC offsets when deserializing dates
Make Json.Net call ToString() when serializing a type
Translate between differing JSON and object structures
Deserialize a nested array of mixed values into a list of items
Deserialize an array of objects with varying names
Serialize/deserialize a custom dictionary with complex keys
Serialize a custom IEnumerable collection as a dictionary
Flatten a nested JSON structure into a simpler object structure
Expand a simple object structure into a more complicated JSON structure
Serialize a list of objects as a list of IDs only
Deserialize a JSON list of objects containing GUIDs to a list of GUIDs
Work around issues (de)serializing specific .NET types
Serializing System.Net.IPAddress throws an exception
Problems deserializing Microsoft.Xna.Framework.Rectangle
I am trying to make a replacement VB6 class for the Scripting.Dictionary class from SCRRUN.DLL. Scripting.Dictionary has (among other things) a "Keys" method that returns an array of keys, and a read/write "Item" property that returns the item associated with a key. I am confused about this, because both of them seem to be defaults for the class. That is:
For Each X In MyDict
Is equivalent to:
For Each X In MyDict.Keys
Which to me implies that "Keys" is the default operation for the class, but:
MyDict("MyKey") = "MyValue"
MsgBox MyDict("MyKey")
Is equivalent to:
MyDict.Item("MyKey") = "MyValue"
MsgBox MyDict.Item("MyKey")
Which to me implies that "Item" is the default operation for the class.
I've never before created a VB6 class that had a default operation, so upon realizing this, I thought perhaps I could define multiple default operations as long as they all have different signatures, which they do: Keys is nullary, the Item getter takes a Variant, and the Item setter takes two Variants. But this doesn't seem to be allowed: When I use "Tools/Procedure Attributes" to set the Keys function to be the default, and then I use it to set the Item property to be the default, the IDE complains that a default has already been set.
So I think I'm misunderstanding something fundamental here. What is going on in the Scripting.Dictionary object that makes it able to act as if "Keys" is the default in some contexts, but as if "Item" is the default in others? And whatever it is, can I accomplish the same thing in VB6?
OK, answering my own question: I haven't tried this yet, but I gather that "Item" should be made the default, and that I should add an entirely new function called "NewEnum" that looks something like the following (slightly modified from an example in Francesco Balena's "Programming Microsoft Visual Basic 6.0" book):
Public Function NewEnum() As IUnknown
Set NewEnum = m_Keys.[_NewEnum]
End Function
(where "m_Keys" is a Collection containing the keys), and then use Tools/Procedure Attributes to hide NewEnum and to set its ProcID to -4.
What you are observing is the difference between the default member and a collection enumerator. A COM object (including VB6 classes) can have both.
You can identify the default property of a class by looking in the Object Browser for the tiny blue globe or the words "default member of" in the description (see Contents of the Object Browser). The Object Browser will not identify an enumerator method, but if you look at the class's interface definition using OLE View or TypeLib Browser (free but registration required) it's DispId will be 0xfffffffc or -4.
In your own class, you can mark the default property by setting the Procedure ID to "(default)" in the Procedure Attributes dialog (see Making a Property or Method the Default). You already listed the steps for setting up the collection enumerator in your own answer, but you can find this listed as well in the Programmer's Guide topic Creating Your Own Collection Class: The House of Bricks.
Scripting.Dictionary has a dirty secret:
It does not handle enumeration at all, it returns big ugly Variant arrays and your For Each loops iterate over those.
This is one of the reasons why a Dictionary can actually be far less efficient than a standard VB6 Collection.
If any control (e.g. a DataGrid) is cast to UIComponent, how can you get its type at runtime?
Is this possible in Actionscript?
You can use getQualifiedClassName() to get class name by the value as a string. You can use describeType() to get the full information about class. And you can use constructor property to get class itself (to instantiate new instance by existing instance). Finally you can use is operator to compare to the limited set of classes. Less recommended usage of typeof operator which is rather obsolete.
To select the right way we need to know your particular problem.
Basically I want to make my script service only serialise properties that are not null on an array of object I am returning... So this..
{"k":"9wjH38dKw823","s":10,"f":null,"l":null,"j":null,"p":null,"z":null,"i":null,"c":null,"m":0,"t":-1,"u":2}
would be
{"k":"9wjH38dKw823","s":10,"m":0,"t":-1,"u":2}
Does anyone know if this is possible?
Basically the reason for this is because null values are for unchanged properties. A local copy is kept in the javascript that is just updated to reduce traffic to the server. Change values are then merged.
You can create a custom JavaScriptConverter class for the JSON serialization process to use to handle your object, and then put the necessary logic in the Serialize method of that class to exclude the properties that are null.
This article has a clear step-by-step discussion of the process involved in creating it.
You probably would not need to actually implement the Deserialize method (can throw a NotImplementedException) if you are not passing that type of object in as an input parameter to your web services.
what I meen is to get all objects and their properties, is it possible? How to do such thing?
Read the SharedObject. The documentation is a great start.
Loop through the properties. Depending on how you stored them if they are simple, a for...in loop should do it. If you are storing complex types (like an Object inside and Object, etc.), you need to first check if the object is simple or not. If it is not, you need to loop through its properties.
Luckily, since you've tagged this for flex as well, the ObjectUtils class will be handy for things like checking if an Object isSimple() or inspecting an Object's properties via getClassInfo().
e.g.
//assuming nestedObjectFromSO is a nested object read from a SharedObject
trace(ObjectUtil.getClassInfo(nestedObjectFromSO).properties);
Depending on your structure, you might need to write a recursive function that gets the data from nested objects within your SharedObject.
HTH,
George
You can use AIR Shared Object Editor to grab and edit .sol files.