JsonUtility in Unity is not working anymore. Why? - c#

I'm trying to get a integer value from a Json that I GET from a server. I used JsonUtility from Unity libreries and It was working fine. And suddenly it is not parsing anymore.
All values returned are Null.
//SAMPLE CODE
SpinResult res = JsonUtility.FromJson<SpinResult>(download.downloadHandler.text);
spinValue = res.result;
//spinValue is always 0. It was working fine
//CLASS
[System.Serializable]
public class SpinResult
{
public int result;
}
//JSON
{
"data": {
"type": "",
"id": "",
"attributes": {
"server_seed": "",
"client_seed": "",
"result": 31,
},
"next_spin": {
"hashed_server_seed": "",
"client_seed": ""
}
}
}
I just need the integer "RESULT", in this case it should be 31 but the actual output is always 0. I check the Json everytime and its working perfectly fine.

I have not tested this, but try making your class look like this:
[System.Serializable]
public class SpinResult
{
public string type;
public string id;
public Attributes attributes;
}
[System.Serializable]
public class Attributes
{
public string server_seed;
public string client_seed;
public int result;
}
Then to get the value of result you would use:
int spinValue = res.attributes.result;

Related

How do I get info from an object with an array of objects in a json for Unity?

I have a JSON file setup as such
{
"cards": [
{
"id": "sand_bags",
"type": "Structure",
"name": "Sand Bags",
"values": [
{
"civilian": 1,
"fiend": -1
}
],
"effectTexts": [
{
"civilian": "Add +1 to your BUNKER.",
"fiend": "Send any CIVILIAN'S +1 STRUCTURE to the SCRAPYARD."
}
],
"flavorTexts": [
{
"civilian": "They're just heavy bags with sand. Not much else to say, but they'll slow down an attack from a fiend. Good luck, you'll need it!",
"fiend": "You've spotted a pretty bad STRUCTURE in this BUNKER. Time to do some damage."
}
],
"staysOnField": [
{
"civilian": true,
"fiend": false
}
],
"amountInDeck": 5
}
]
}
I also have a Cards script
[Serializable]
public class Cards
{
public Card[] cards;
}
[Serializable]
public class Card
{
public string id;
public string type;
public string name;
public int amountInDeck;
}
public class Values
{
public int civilian;
public int fiend;
}
I then have a CardEffects script that I'm using for my functions.
public class CardEffects : MonoBehaviour
{
public TextAsset jsonFile;
public Values values;
void Start()
{
Cards cardsInJson = JsonUtility.FromJson<Cards>(jsonFile.text);
foreach (Card card in cardsInJson.cards)
{
Debug.Log("Card name: " + card.name + " with " + values.civilian + " in the deck.");
}
}
}
I have searched all over trying to figure out how to even get the array of objects of "values". I got this far and the value printed is always 0 regardless of the information in "values" in the JSON. If I make the class Serializable, I'm able to change the values and it works but I want the values to be whatever they were declared as in the JSON. Is there a better way to do this?
Please keep in mind I'm new to C# and Unity. I usually code in JS in which using JSON files are no big deal for me and thought it was the best way to go.
Your json and your classes doesn't match. Not only that your json isn't even valid Json. Below I will give you your correct json and class.
{
"cards": [
{
"id": "sand_bags",
"type": "Structure",
"name": "Sand Bags",
"values": [
{
"civilian": 1,
"fiend": -1
}
],
"effectTexts": [
{
"civilian": "Add +1 to your BUNKER.",
"fiend": "Send any CIVILIAN'S +1 STRUCTURE to the SCRAPYARD."
}
],
"flavorTexts": [
{
"civilian": "They're just heavy bags with sand. Not much else to say, but they'll slow down an attack from a fiend. Good luck, you'll need it!",
"fiend": "You've spotted a pretty bad STRUCTURE in this BUNKER. Time to do some damage."
}
],
"staysOnField": [
{
"civilian": true,
"fiend": false
}
],
"amountInDeck": 5
}
] // <---- This was missing
}
For that Json this is how your card class will have to look like:
public Card
{
public string id { get; set; }
public string type { get; set; }
public string name { get; set; }
public Values[] values { get; set; }
public Values[] effectTexts { get; set; }
public Values[] staysOnField { get; set; }
public int amountInDeck { get; set; }
}
And your Values class have to look like this:
public class Values
{
public object civilian;
public object fiend;
}
I suggest MiniJson.
You can just copy paste the script to your project and you are ready to go.
The then can call Json.Deserialize(string json) passing your string in. For the case of an array you can do for example:
IList myJsonElements = (IList)Json.Deserialize(string json);
Find working snippet:
using System;
using Newtonsoft.Json;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args) {
string myJson = "{\"cards\": [{\"id\": \"sand_bags\",\"type\": \"Structure\",\"name\": \"Sand Bags\",\"values\": [{\"civilian\": 1,\"fiend\": -1}],\"effectTexts\": [{\"civilian\": \"Add +1 to your BUNKER.\",\"fiend\": \"Send any CIVILIAN'S +1 STRUCTURE to the SCRAPYARD.\"}],\"flavorTexts\": [{\"civilian\": \"They're just heavy bags with sand. Not much else to say, but they'll slow down an attack from a fiend. Good luck, you'll need it!\",\"fiend\":\"You've spotted a pretty bad STRUCTURE in this BUNKER. Time to do some damage.\"}],\"staysOnField\": [{\"civilian\": true,\"fiend\": false}],\"amountInDeck\": 5}]}";
var myJsonElements = MiniJSON.Json.Deserialize(myJson);
Console.WriteLine(myJsonElements.ToString());
string json = JsonConvert.SerializeObject(myJsonElements, Formatting.Indented);
Console.WriteLine(json);
Console.ReadLine();
}
}
}

Deserialize nested objects with JsonUtility

I would like to deserialize my json files holding information about levels. Given this example .json file called 1.json
{
"name": "Level One",
"map": [
[{
"groundTexture": "grass",
"cellType": "empty",
"masterField": null,
"worldObjects": [{
"worldObjectType": "player",
"rotation": 90
}]
},{
"groundTexture": "grass",
"cellType": "obstacle",
"masterField": null,
"worldObjects": [{
"worldObjectType": "tree",
"rotation": 0
}]
}],[{
"groundTexture": "grass",
"cellType": "campFire",
"masterField": null,
"worldObjects": [{
"worldObjectType": "campfire",
"rotation": 270
}]
},{
"groundTexture": "grass",
"cellType": "related",
"masterField": {
"x": 1,
"y": 0
},
"worldObjects": []
}]
]
}
I would like to convert the data from that file to a class object holding all the data needed to create a level during runtime. I created a reader which only reads the file content
public class LevelReader : MonoBehaviour
{
private string levelBasePath;
private void Awake()
{
levelBasePath = $"{Application.dataPath}/ExternalFiles/Levels";
}
public string GetFileContent(string levelName)
{
string file = $"{levelName}.json";
string filePath = Path.Combine(levelBasePath, file);
return File.ReadAllText(filePath);
}
}
and a mapper which maps the json string to a LevelInfo object.
public class LevelMapper : MonoBehaviour
{
private void Start()
{
// DEBUGGING TEST
LevelReader levelReader = GetComponent<LevelReader>();
string levelContent = levelReader.GetFileContent("1");
LevelInfo levelInfo = MapFileContentToLevelInfo(levelContent);
Debug.Log(levelInfo.cells);
}
public LevelInfo MapFileContentToLevelInfo(string fileContent)
{
return JsonUtility.FromJson<LevelInfo>(fileContent);
}
}
The following structs just help to create an object containg all the level data:
[Serializable]
public struct LevelInfo
{
public string name;
public LevelCell[][] cells;
}
[Serializable]
public struct LevelCell
{
public string groundTexture;
public string cellType;
public Vector2? masterField;
public LevelWorldObject[] worldObjects;
}
[Serializable]
public struct LevelWorldObject
{
public string worldObjectType;
public int rotation;
}
When starting the application the mapper runs and loops through the data object. Unfortunately the cells are null. How can I deserialize the file correctly?
In LevelInfo structure you have field "cells" but in Json - "map". They must be the same.
JsonUtility can't serialize/deserialize multidimensional arrays.
https://answers.unity.com/questions/1322769/parsing-nested-arrays-with-jsonutility.html
https://docs.unity3d.com/Manual/script-Serialization.html
I believe you can change your data structures or use another serializer.

Unexpected character encountered while parsing value: [

My JSON is as follows
{
"#odata.context":"https://graph.microsoft.com/V1.0/$metadata#users",
"value":[
{
"businessPhones":[
],
"displayName":"dee",
"givenName":null,
"jobTitle":null,
"mail":"79#gmail.com",
"mobilePhone":null,
"officeLocation":null,
"preferredLanguage":null,
"surname":null,
"userPrincipalName":"79_gmail.com#EXT##web.onmicrosoft.com",
"id":"08fab3-6f-4dc9-9ffb-6568d172"
},
{
"businessPhones":[
"973"
],
"displayName":"Technologies LLP",
"givenName":"SHA",
"jobTitle":null,
"mail":null,
"mobilePhone":"8762",
"officeLocation":null,
"preferredLanguage":"en-U",
"surname":"SHAI",
"userPrincipalName":"admin#web.onmicrosoft.com",
"id":"2adf-94cd-45-83ef-d0dbf1e36"
},
{
"businessPhones":[
],
"displayName":"admin of smartogle",
"givenName":null,
"jobTitle":null,
"mail":null,
"mobilePhone":null,
"officeLocation":null,
"preferredLanguage":"en-US",
"surname":null,
"userPrincipalName":"admin#smartogle.com",
"id":"1754-d6-40-9ae2-d816063e"
},
{
"businessPhones":[
],
"displayName":"av",
"givenName":null,
"jobTitle":null,
"mail":null,
"mobilePhone":null,
"officeLocation":null,
"preferredLanguage":"en-US",
"surname":null,
"userPrincipalName":"av#smartogle.com",
"id":"6837-08-449-a6ab-78b"
}
]
}
I am using the following code to convert the json to the object list
MyObject obj = JsonConvert.DeserializeObject<MyObject>(members);
MyObject Class is as follows
public class MyError
{
public List<values> value;
}
public class values
{
public string id;
public string userPrincipalName;
public string surname;
public string preferredLanguage;
public string officeLocation;
public string mobilePhone;
public string mail;
public string jobTitle;
public string givenName;
public string displayName;
public string businessPhones;
}
While converting I am getting the following error
Unexpected character encountered while parsing value: [. Path 'value[0].businessPhones', line 1, position 97.
When I delete the public string businessPhones; from the class the rest of the data are parsed to the object list. But actually I need the businessPhones also
as several folks pointed about you should declare businessPhones as array:
public string[] businessPhones;

Unable to handle Collection Deserealization Error

I'm trying to handle deresealize an object that does not comply with some of my classes. I wold like the code to execute and fail only on the invalid attributes but the deserealization method is returning a null Object.
I am using this method in a generic utility class that deserealizes some string to any given type.
From the test code, the error handler works correctly on invalid dates and other invalid types and returns the object with the default .NET initialization values.
If I change (or comment) the Items collection in the sub object, the code works.
string json = "{\"Id\":8,\"CreatedByUserId\":0,\"CreatedOnDate\":\"2019X-Y02Z-W06T18:A51:05.783\",\"LastModifiedByUserId\":1,\"LastModifiedOnDate\":\"2019-03-12T17:00:34.82\",\"OperationData\":{\"IsActive\":true,\"Items\":[{\"_Id\":1,\"Id_Value\":0,\"Id\":1},{\"_Id\":2,\"Id\":2},{\"Id\":1,\"IsDeleted\":false,\"Content\":{}}]}}";
TestType test = DeserealizeContent(json);
/*The convertion utility*/
private static TestType DeserealizeContent(string data)
{
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore,
Error = HandleDeserializationError
};
var r = JsonConvert.DeserializeObject<TestType>(data, settings);
return r;
}
public static void HandleDeserializationError(object sender, ErrorEventArgs errorArgs)
{
errorArgs.ErrorContext.Handled = true;
}
/*Supporting types*/
public class TestType {
public int Id { get; set; }
public DateTime CreatedOnDate { get; set; }
public int CreatedByUserId { get; set; }
public string Instructions { get; set; }
public OperationDataType OperationData {get;set;}
}
public class OperationDataType {
public bool IsActive { get; set; }
public List<int> Items { get; set; }
}
I was expecting the error handler to catch handle the exception and continue with the process but instead the deserealization just returns null in the end.
If I change List Items to List Items the result is correctly parsed.
My expected result wold be:
{
"Id": 8,
"CreatedByUserId": 0,
"CreatedOnDate": null,
"LastModifiedByUserId": 1,
"LastModifiedOnDate": "2019-03-12T17:00:34.82",
"OperationData": {
"IsActive": true,
"Items": null
}
}
EDIT - workaround
The suggestion from Yair (bellow) works.
Changing from List to List works as expected and the exception get handle correctly.
The items in your json is not an array of int so how you want it to be List?
Items is array of objects look at the json formated:
{
"Id": 8,
"CreatedByUserId": 0,
"CreatedOnDate": "2019X-Y02Z-W06T18:A51:05.783",
"LastModifiedByUserId": 1,
"LastModifiedOnDate": "2019-03-12T17:00:34.82",
"OperationData": {
"IsActive": true,
"Items": [{
"_Id": 1,
"Id_Value": 0,
"Id": 1
}, {
"_Id": 2,
"Id": 2
}, {
"Id": 1,
"IsDeleted": false,
"Content": {}
}
]
}
}
You can do one of three things:
handle the json content as string or map it so the items will be int array [1,2,3].
create item class for the items that include all the fields you need then extract the int that you want.
get it as object like you do now and use reflection () for getting the int you want.
you can use this function for reflection:
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
and then use it like this:
GetPropValue(test.OperationData.items[0], "Id")
EDIT
you can use this to deserialize the json in generic way:
Newtonsoft.Json.Linq.JObject jsonDeserialized = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject<object>(json);
and then
you can map it manually or with automapper to the new TestType test that you want without the items in it.
you can get the values like this:
test.Id = jsonDeserialized["Id"];
test.CreatedByUserId = jsonDeserialized["CreatedByUserId"];
and so on
according to your last comment i find that if i changed the List<int> Items to List<long> Items it works as you wanted. it is something with primitive types and the parsing that deserialize do.

Serialize and deserialize part of JSON object as string with WCF

I have a WCF REST service which has a resource which contains several typed fields, and then a field which can be an array of objects. I want the field on our service to serialize this field as if it were a string. Example:
[DataContract]
public class User
{
[DataMember]
public long ID;
[DataMember]
public string Logon;
[DataMember]
public string Features;
}
When users of our API POST a new User object, I'd like them to be able to do use something like this as the body:
{
"ID" : 123434,
"Logon" : "MyLogon",
"Features" : [
{ "type": "bigFeature", "size": 234, "display":true },
{ "type": "smFeature", "windowCount": 234, "enableTallness": true}
]
}
instead of
{
"ID" : 123434,
"Logon" : "MyLogon",
"Features" : "[
{ \"type\": \"bigFeature\", \"size\": 234, \"display\":true },
{ \"type\": \"smFeature\", \"windowCount\": 234, \"enableTallness\": true}
]"
}
On the service side, I'm going to be saving the "Features" array as JSON text blog in the database, and when I return the Object on GET calls, I'd like it to round trip properly.
If you were willing to switch to Json.NET, you could serialize your Features string as a private JToken proxy property:
[DataContract]
public class User
{
[DataMember]
public long ID;
[DataMember]
public string Logon;
string _features = null;
[IgnoreDataMember]
public string Features
{
get
{
return _features;
}
set
{
if (value == null)
_features = null;
else
{
JToken.Parse(value); // Throws an exception on invalid JSON.
_features = value;
}
}
}
[DataMember(Name="Features")]
JToken FeaturesJson
{
get
{
if (Features == null)
return null;
return JToken.Parse(Features);
}
set
{
if (value == null)
Features = null;
else
Features = value.ToString(Formatting.Indented); // Or Formatting.None, if you prefer.
}
}
}
Note that, in order to serialize the Features string without escaping, it must be valid JSON, otherwise your outer JSON will be corrupt. I enforce this in the setter. You could use JArray instead of JToken to enforce the requirement that the string represent a JSON array, if you prefer.
Note that the string formatting isn't preserved during serialization.

Categories

Resources