When I try to use JsonUtility to parse the JSON from a REST call returning an array of elements, it fails saying that top level must be an object. C'mon guys. That's ridiculous.
OK, moving on to figuring out how to use Newtonsoft.json because it works well everywhere else.
Tried using JSON .NET for Unity out of the asset store. Seemed like it would work fine and did in the editor, but didn't work (calls to it failed with exceptions) when I tried to use it in a Mac local build on my dev macbook pro. So if it doesn't work on my dev machine and for mac builds, then it's a no go. https://assetstore.unity.com/packages/tools/input-management/json-net-for-unity-11347
Tried using jilleJr's version from here: https://github.com/jilleJr/Newtonsoft.Json-for-Unity but the installation instructions caused the package manager to not be able to open. I get a null reference exception when following the directions to add the package directly into my manifest.json
So what's the secret to making JSON work in Unity 2019/2020 right now? Seems like a huge problem for a platform to have.
Open *YourUnityProject*/Packages/manifest.json and add the following line to the dependencies object.
"com.unity.nuget.newtonsoft-json": "2.0.0",
To serialize and deserialize data use these functions:
using Newtonsoft.Json;
public class Data
{
int[] numbers;
}
string json = JsonConvert.SerializeObject(new Data());
Data data = JsonConvert.DeserializeObject<Data>(json);
I wouldn't say it's a problem with Unity, back when I was trying to read data in from serialised JSON. JsonUtility worked a treat when serialising/deserialising to/from a class. I also preferred it to Newtonsoft.json, mainly because it was part of UnityEngine
For example:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class JSONRW : MonoBehaviour
{
PersonData data;
string jsonPath = "Assets/TestJSON.json";
private void Start()
{
//Read in JSON file
string jsonString = File.ReadAllText(jsonPath);
data = JsonUtility.FromJson<PersonData>(jsonString);
Debug.Log(data.client[0].name); //Outputs A
//Write to JSON file
data.client[0].name = "Luc"; //Changes the name of the entry named A
File.WriteAllText(jsonPath, JsonUtility.ToJson(data)); //Writes updata back to file
}
}
[System.Serializable]
public class Person
{
public string name;
public int age;
public Person(string _name, int _age)
{
name = _name;
age = _age;
}
}
[System.Serializable]
public class PersonData
{
public List<Person> client;
}
JSON file:
{
"client": [
{
"name": "A",
"age": 10
},
{
"name": "B",
"age": 20
},
{
"name": "C",
"age": 30
},
{
"name": "D",
"age": 40
}
]
}
Related
I have an appsettings.json file with the following values
{
"MailOptions":
{
"Username": "ruskin",
"Password": "password"
}
}
When I read it via the ConfigurationBuilder I can only access the values via configuration["MailSettings:Username"]. I want to grab the entire MailOptions string, is there anyway to do that? I don't want to use Json to parse the file etc...I want to stick to configuration builder.
I would expect configuration.GetSection("MailOptions") to work? It simply returns null.
What I have tried
SomeSection aSection = new SomeSection();
ServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.Configure<SomeSection>(options => configuration.GetSection("SomeSection").Bind(aSection));
var someSection = serviceCollection.BuildServiceProvider().GetService<IOptions<SomeSection>>();
// aSection is instantiated but no values in it
// someSection is null
My appsettings.json
{
"SomeSection": {
"UserName": "ruskin",
"Password": "dantra"
}
}
And my POCO class
public class SomeSection
{
public string UserName { get; set; }
public string Password { get; set; }
}
The configuration framework is an abstraction over the underlying source types. So MailOptions:Username could come from JSON, an environment variables or even INI files - and the configuration system can even be configured with multiple sources. If need a JSON string to configure your mail library and want to use the configuration abstraction, I suggest creating a class to hold the settings and serialize it to a JSON string again.
EDIT:
Using configuration.GetSection("SomeSection").Get<SomeSection>() I can successfully get the POCO from the app. see sample application.
Motivated by this: Google JSON Style Guide, I want to insert a bit of custom serialization logic to my rest API. I'm using the WebAPI 2 and JSON.NET. My goal is to wrap the 'payload' of my response in the 'data' field of the main JSON response, as described in the style guide, include an apiVersion field in every response, and that sort of thing. Of course the controller actions just return straight POCO's, and I want to modify the container that they're sent inside of, not the POCOs themselves, so:
{
"id": "111",
"apiVersion": "1.0",
"data": {
"kind": "monkey",
"name": "manny",
"age": "3"
},
"error": null
}
...that type of thing. So I envision inserting little bits of standard data into every response before it goes over the wire. What's the best way to accomplish this?
TIA.
I believe you can use an ActionFilterAttribute to achieve this kind of behaviour. You would first need to create a class to represent your wrapped response (all the properties are string, adjust as you need):
public class WrappedJsonResponse
{
public string Id {get;set;}
public string ApiVersion {get;set;}
public object Data {get;set;}
public string Error {get;set;}
}
The ActionFilterAttribute allow you to do some processing after the execution of an action via the virtual OnActionExecuted method:
public class WrappedJsonAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext context)
{
// A POCO response will normally be wrapped in an ObjectContent
var content = context.Response.Content as ObjectContent
if(content != null)
{
// Create the WrappedJsonResponse object appropriately and
// put the original result in the Data property
content.Value = new WrappedJsonResponse { Data = content.Value };
content.ObjectType = typeof(WrappedJsonResponse);
}
}
}
With the attribute, you can then choose to apply it where you want (whole controller, action only or as a default filter).
Note: I do not have access to a development environment at the moment and have not tested the filter. If this is not complete, it should at least give you an idea on how it can be done.
I've got a strange mapping Issue with Jackson on Android.
I've got a "Content" Class which should be used by the Jackson Mapper.
It looks like this:
public class content {
private String header;
private String subheader;
private String bodytext;
#JsonProperty("singleimage")
private String image;
#JsonProperty("uid")
private String id;
#JsonProperty("link")
private String article;
#JsonProperty("CType")
private String cType;
// Eclipse auto generated getters & setters
...
}
The corresponding JSON Object looks like this:
{
"header": "xyz",
"subheader": "abc",
"bodytext": "abc",
"singleimage": "abc",
"images": "abc.jpg",
"teaser_elements": "",
"uid": "13",
"link": "xyz.htm",
"CType": "row_header"
}
Now when I use the Jackson Maper to create instances of Content from a provided JSON all fields of the content class get populated correctly - all except "cType".
I already tried to move the #JsonProperty("CType") annotation to the setCType Method but still no effect.
I don't get any Exceptions while mapping the class or anything else and as it seems to me that all mappings pretty much do the same (mapping to String) im kinda buffled why it doesn't work wit the "CType".
Any suggestions what the problem might be are highly appreciated.
I'm getting a pretty strange error when marshalling my object to json. My object is annotated like this.
My class:
#XmlRootElement(name = "myobject")
public class MyObject {
private List<String> contactPersonsForMyObject;
#javax.xml.bind.annotation.XmlElement()
public List<String> getContactPersonsForMyObject() {
return contactPersonsForMyObject;
}
public void setContactPersonsForMyObject(List<String> contactPersonsForMyObject) {
this.contactPersonsForMyObject = contactPersonsForMyObject;
}
}
Everything works fine except for that if the List contactPersonsForMyObject contains only one value it get's marshalled to a string which ofcourse creates problems since the application consuming this expects a list.
The marshalled object:
[
{
"myobject": {
"somethingcool": "amazing",
"contactPersonsForMyObject": [
"test.test#gmail.com",
"test#test.se"
],
"myObjectId": "c85e48730501bfae41e67714c6131b7d"
}
},
{
"myobject": {
"somethingcool": "cool",
"contactPersonsForMyObject":"test#test2.se",
"myObjectId": "c85e48730501bfae41e67714cqwerty"
}
}
]
Why does this happen and how do I force it to create a list with one value?
Try using Jackson to handle processing your objects into JSON, it solved the same array problem for me in the past. If you are using RESTEasy (version 1.2 GA) with Maven, this link should help you get things setup to use Jackson to serialize objects to JSON.
This article also has some useful information for integrating Jackson with RESTEasy. Hope this helps!
I can't seem to find anything in the OpenRasta docs or tutorials that shows how to use arbitrary JSON objects (i.e. objects not predefined using C# classes) for both receiving from and responding back to the client.
One way to do it would be to use JsonValue and write a custom codec that would just use the (de)serialization features provided by JsonValue. That should be pretty straightforward and less than 50 lines of code, but I wondered if there isn't anything built into OpenRasta?
(One downside of JsonValue is that MS has not yet released it, so you can't yet deploy it to customers (see 1. "Additional Use Rights"). But in cases where that matters, any other Json library, like Json.NET can be used.)
I have written, like most people, a very simple codec that supports dynamics as inputs and outputs to handlers using json.net. You can also register that codec with an anonymous type and it works brilliantly. You end up with this:
public object Post(dynamic myCustomer) {
return new { response = myCustomer.Id };
}
I just implemented a JSON codec using JsonFx. It goes like this:
using System.IO;
using System.Text;
using JsonFx.Json;
namespace Example
{
[global::OpenRasta.Codecs.MediaType("application/json")]
public class JsonFXCodec : global::OpenRasta.Codecs.IMediaTypeWriter, global::OpenRasta.Codecs.IMediaTypeReader
{
public void WriteTo(object entity, global::OpenRasta.Web.IHttpEntity response, string[] codecParameters)
{
JsonWriter json = new JsonWriter();
using (TextWriter w = new StreamWriter(response.Stream, Encoding.UTF8))
{
json.Write(entity, w);
}
}
public object ReadFrom(global::OpenRasta.Web.IHttpEntity request, global::OpenRasta.TypeSystem.IType destinationType, string destinationName)
{
JsonReader json = new JsonReader();
using (TextReader r = new StreamReader(request.Stream, Encoding.UTF8))
{
return json.Read(r, destinationType.StaticType);
}
}
public object Configuration { get; set; }
}
}
If it is registered for "object" then it seems to work for any class:
ResourceSpace.Has.ResourcesOfType<object>()
.WithoutUri
.TranscodedBy<JsonFXCodec>();