How to make Json.stringify ignore certain class memebers? - json

I'm using the latest Haxe and HaxeFlixel to make a simple game prototype.
I have the following class...
class GameData
{
public var playerHealth: Int;
public var playerScore: Int;
public var levelName: String;
public function new(playerHealth: Int = 0, playerScore: Int = 0, levelName: String = "")
{
this.playerHealth = playerHealth;
this.playerScore = playerScore;
this.levelName = levelName;
}
}
I convert it to JSON as follows...
Json.stringify(new GameData(64, 512, "Level 1"));
Is there's a way I can make it so the stringify ignores certain members?

haxe.Json has no mechanism to exclude fields, so I would recommend using a third-party library such as json2object that does. Here you can simply annotate fields that should be ignored with #:jignored:
#:jignored
public var levelName:String;
var data = new GameData(100, 10, "Level 1");
var json = new json2object.JsonWriter<GameData>().write(data);
trace(json); // {"playerHealth": 100,"playerScore": 10}
There are some possible workarounds that don't involve adding a library to your project, but they don't seem very nice:
Don't serialize the object directly, but a structure that only includes the desired fields:
var data = new GameData(100, 10, "Level 1");
var json = Json.stringify({
playerHealth: data.playerHealth,
playerScore: data.playerScore
});
trace(json); // {"playerHealth":100,"playerScore":10}
Remove the unwanted fields after serialization - this seems rather hacky as it involves a lot of unnecessary overhead due to an additional Json.parse() and Json.stringify() call:
var json = Json.stringify(new GameData(100, 10, "Level 1"));
var data:haxe.DynamicAccess<String> = Json.parse(json);
data.remove("levelName");
json = Json.stringify(data);
trace(json); // {"playerHealth":100,"playerScore":10}

Depending on your exact situation, it can be desirable to make a slightly modified version of standard library's JsonPrinter - for example, in GMEdit I allow JSON objects to have an hxOrder: Array<String> field, which, if provided, determines the field order for printing, and is initialized to a static array. You can make a similar scheme for field inclusion/exclusion.

Related

Adding Fields to JSON in better way Javascript

I'm using Node-Red and the data is passed using JSON objects.
All of the data is in msg.payload. I want to add a new property, the TimeStamp, to the object without all of this unnecessary code...It works but I know this is sloppy.
Is there a better way?
var TimeStamp = new Date();
var newMsg = [ ];
newMsg.push({payload:
{ TimeStamp:TimeStamp ,
Humidity: msg.payload.Humidity,
Temperature: msg.payload.Temperature,
CO2: msg.payload.CO2,
Light: msg.payload.Light
}
});
return newMsg;
You can add the new property to the existing msg object and pass it on.
msg.payload.TimeStamp = new Date();
return msg;
This is the better approach as it leaves all other message properties untouched.

Google Realtime circular JSON error when indexReference stored in collaborative map only when contained in an object

Trying to store indexReferences per user, I've found that when I store one (or more) directly in a map, it works fine. However, when stored in an object (or a custom realtime object), the realtime API generates Circular JSON errors.
This works fine:
function doRegisterTypes() {
gapi.drive.realtime.custom.registerType(MyCustomType, "MyCustomType");
MyCustomType.prototype.startPoints = gapi.drive.realtime.custom.collaborativeField('startPoints');
MyCustomType.prototype.endPoints = gapi.drive.realtime.custom.collaborativeField('endPoints');
MyCustomType.prototype.elements = gapi.drive.realtime.custom.collaborativeField('elements');
gapi.drive.realtime.custom.setInitializer(MyCustomType, initializeMyCustomType);
}
function initializeMyCustomType() {
var model = gapi.drive.realtime.custom.getModel(this);
this.startPoints = model.createMap();
this.endPoints = model.createMap();
this.elements = model.createList();
}
function initializeModel(model) {
var o = model.create("MyCustomType");
o.elements.pushAll(["foo", "bar"]);
var startIndex = o.elements.registerReference(0, false);
var endIndex = o.elements.registerReference(0, false);
o.startPoints.set(UserId, startIndex);
o.endPoints.set(UserId, endIndex);
model.getRoot().set("MyCustomObject", o);
}
But this doesn't, failing with circular JSON errors when storing the range object in the map:
function doRegisterTypes() {
gapi.drive.realtime.custom.registerType(MyCustomType, "MyCustomType");
MyCustomType.prototype.ranges = gapi.drive.realtime.custom.collaborativeField('ranges');
MyCustomType.prototype.elements = gapi.drive.realtime.custom.collaborativeField('elements');
gapi.drive.realtime.custom.setInitializer(MyCustomType, initializeMyCustomType);
}
function initializeMyCustomType() {
var model = gapi.drive.realtime.custom.getModel(this);
this.ranges = model.createMap();
this.elements = model.createList();
}
function initializeModel(model) {
var o = model.create("MyCustomType");
o.elements.pushAll(["foo", "bar"]);
var startIndex = o.elements.registerReference(0, false);
var endIndex = o.elements.registerReference(0, false);
// FAILS:
o.ranges.set(UserId, {start:startIndex, end:endIndex});
model.getRoot().set("MyCustomObject", o);
}
I should stress the error appears for a single indexReference, and whether the object is a specific custom type or not, and also WHENEVER the value is set into the map: while initializing the model or later. It's as if the indexReferences cannot be stored at anything but a "top level", though that makes little sense.
Feature? Bug? User stoopidity?
You can't store CollaborativeObjects within arbitrary json within a CollaborativeObject. CollaborativeObjects (including IndexReferences) must be stored directly in other CollaborativeObjects.
(There are a few reasons for this, mostly having to do with how the collaboration works.. json objects are treated as arbitrary blobs whose contents are ignored.)
In this case, you could create a Range custom object type that has a start and end CollaborativeField. (Or a CollaborativeList with 2 elements..)

new constructor with a string

Instead of many if conditionals, I want to call a constructor according to a string value
var valueString:String = "myNewClassB";
var value:Class = valueString as Class;
new value() // new value() == new myNewClassB()
I know it's gonna fail, I need help. Thanks.
var ClassReference:Class = getDefinitionByName("myNewClassB");
var instance = new ClassReference();
That's the basics, bud.
If you want to do that, there are two ways, either assign classes to a list of classes made for an example in a object:
var list:Object = {
classA: FirstClass,
classB: SecondClass,
classC: ThirdClass
}
and than call them by a string:
var desiredObject:* = new (list["classA"] as Class)();
or you could also use getDefinitionBtName but than if you want to get a class you need to provide a full name (with the package)
var desiredClass = getDefinitionByName( "com.somedomain.SomeClass" );
If you are laoding an SWF content and than want to get a class from it you should use that loader loaderInfo.applicationDomain.getDefinition( "....class" );
you can also check if a class is defined by:
loaderInfo.applicationDomain.hasDefinition( "....class" );
link: ApplicationDomain.getDefinition
link: ApplicationDomain.hasDefinition
link: LoaderInfo

How to send array through HTTPservice in Adobe Flex 3

How to send array in Httpservice in Adobe Flex3
I am not quite sure what you mean by sending an array to a httpservice. If you mean to send an array to a httpservice with the same field name, you can pass an array as field value.
var service:HTTPService = new HTTPService();
service.useProxy = true;
service.destination = "myservicet";
service.resultFormat = HTTPService.RESULT_FORMAT_XML;
var fields:Array = ["categories", "organisation"];
var params:Object = new Object();
params.q = "stackoverflow";
params.rows = 0;
params.facet = "true";
params["facet.field"] = fields;
service.send(params);
The HTTPService will convert this to the url parameters:
facet=true&q=stackoverflow&facet%2Efield=categories&facet%2Efield=organisation&rows=0
Hope this helps!
Added for more clarity. When there is only 1 argument in the array, do not pass the fields as an array. For some reason, flex will not send this to the http service
It really depends what is the back end technology you're using. If you're sending it to PHP you could try:
var fields:Array = ["categories", "organisation"];
var params:Object = {};
params.q = "stackoverflow";
params.rows = 0;
params.facet = "true";
params["facet.field[]"] = fields;
service.send(params);
PHP will generate an array for you.
AFAIR this works fine in Rails as well.
if it is a simple string array, you can join it with a well know separator char, and on the other site, split the string with the same separator back to an array.
If it is a simple array, you could send it as a comma separated string.
httpService.request = new Object;
httpService.request.csv = array.toString();

Difference between json.js and json2.js

Can someone tell me what the difference is between the 2 JSON parsers?
https://github.com/douglascrockford/JSON-js/blob/master/json.js
https://github.com/douglascrockford/JSON-js/blob/master/json2.js
I have a JSON file from 2007-04-13 (It has methods such as parseJSON). I don't see these methods in any of the new versions.
From their code:
// Augment the basic prototypes if they have not already been augmented.
// These forms are obsolete. It is recommended that JSON.stringify and
// JSON.parse be used instead.
if (!Object.prototype.toJSONString) {
Object.prototype.toJSONString = function (filter) {
return JSON.stringify(this, filter);
};
Object.prototype.parseJSON = function (filter) {
return JSON.parse(this, filter);
};
}
I guess parseJSON is obsolete, therefore the new version (json2) doesn't even use it anymore. However if your code uses parseJSON a lot you could just add this piece of code somewhere to make it work again:
Object.prototype.parseJSON = function (filter) {
return JSON.parse(this, filter);
};
Quoting here:
"JSON2.js - Late last year Crockford quietly released a new version of his JSON API that replaced his existing API. The important difference was that it used a single base object."
I also noticed that json2 stringified arrays differently than json2007.
In json2007:
var array = [];
array[1] = "apple";
array[2] = "orange";
alert(array.toJSONString()); // Output: ["apple", "orange"].
In json2:
var array = [];
array[1] = "apple";
array[2] = "orange";
alert(JSON.stringify(array)); // Output: [null, "apple", "orange"].