How to Parse this JSON with LibGDX - json

"components":[
{
"class":"AssetReference",
"asset":{
"class":"TextureRegionAsset",
"relativePath":"gfx/opengraph.png"
}
},
{
"class":"Layer"
},
{
"class":"ProtoVisSprite",
"width":5,
"height":5
},
{
"class":"Transform",
"x":0.13817275,
"y":2.8430145,
"scaleX":0.2,
"scaleY":0.2
},
{
"class":"Origin"
},
{
"class":"Tint"
},
{
"class":"Renderable",
"zIndex":2
},
{
"class":"VisID",
"id":"scratch"
}
]
Im having some issues in parsing the nested asset with LibGDX. Does anyone know how to assign asset to AssetReference with the relativePath from TextureRegionAsset?
I know I could strip out the "class" handling and simple parse the JSON but I need to be able to handle this with LibGDX.
Ideally Im looking to parse the data and create a sprite from the JSON.
Thanks.

You can use JsonReader and get JsonValue for that.
JsonReader json = new JsonReader();
JsonValue base = json.parse(Gdx.files.internal("file.json"));
//print json to console
System.out.println(base);
//get the component values
JsonValue component = base.get("components");
//print class value to console
System.out.println(component.getString("class"));
//array objects in json if you would have more components
for (JsonValue component : base.get("components"))
{
System.out.println(component.getString("class"));
System.out.println(component.get("asset").getString("class");
System.out.println(component.get("asset").getString("relativePath");
}

There is actually a useful libgdx wiki page for this:
https://libgdx.com/wiki/utils/reading-and-writing-json
Apparently it seems to work fine with nested classes on its own already.
The wiki page has this example:
Json json = new Json();
Person person = json.fromJson(Person.class, text);
Using the following as text:
{
class: com.example.Person,
numbers: [
{
class: com.example.PhoneNumber,
number: "206-555-1234",
name: Home
},
{
class: com.example.PhoneNumber,
number: "425-555-4321",
name: Work
}
],
name: Nate,
age: 31
}
This is using an example class "Person" with the following properties:
ArrayList numbers
String name
int age
The String text is the result of json.toJson(person). Your resulting serialized string seems the same format, which makes me assume you're already using the Json serializer, but not the unserializer.

Related

How to iterate through nested dynamic JSON file in Flutter

So I have two JSON files with different fields.
{
"password": { "length": 5, "reset": true},
}
"dataSettings": {
"enabled": true,
"algorithm": { "djikstra": true },
"country": { "states": {"USA": true, "Romania": false}}
}
I want to be able to use the same code to be able to print out all the nested fields and its values in the JSON.
I tried using a [JSON to Dart converter package](https://javiercbk.github.io/json_to_dart/.
However, it seems like using this would make it so I would have to hardcode all the values, since I would retrieve it by doing
item.dataSettings.country.states.USA
which is a hardcoded method of doing it. Instead I want a way to loop through all the nested values and print it out without having to write it out myself.
You can use ´dart:convert´ to convert the JSON string into an object of type Map<String, dynamic>:
import 'dart:convert';
final jsonData = "{'someKey' : 'someValue'}";
final parsedJson = jsonDecode(jsonData);
You can then iterate over this dict like any other:
parsedJson.forEach((key, value) {
// ... Do something with the key and value
));
For your use case of listing all keys and values, a recursive implementation might be most easy to implement:
void printMapContent(Map<String, dynamic> map) {
parsedJson.forEach((key, value) {
print("Key: $key");
if (value is String) {
print("Value: $value");
} else if (value is Map<String, dynamic>) {
// Recursive call
printMapContent(value);
}
));
}
But be aware that this type of recursive JSON parsing is generally not recommendable, because it is very unstructured and prone to errors. You should know what your data structure coming from the backend looks like and parse this data into well-structured objects.
There you can also perform input validation and verify the data is reasonable.
You can read up on the topic of "JSON parsing in dart", e.g. in this blog article.

How to Import JSON data to typescript Map<K, V> type?

I am trying to import json data that might include present or absent mappings within one of the properties, and figured the correct data type to represent this was Map<string, number>, but I'm getting an error when I try to do this.
My JSON file, data.json, looks like this:
{
"datas": [
{
"name":"test1",
"config":"origin",
"entries": {
"red":1,
"green":2
}
}
,
{
"name":"test2",
"config":"remote",
"entries": {
"red":1,
"blue":3
}
}
,
{
"name":"test3",
"entries": {
"red":1,
"blue":3,
"purple":3
}
}
]
}
My typescript code, Data.ts, which attempts to read it looks like this:
import data from './data.json';
export class Data {
public name:string;
public config:string;
public entries:Map<string, number>;
constructor(
name:string,
entries:Map<string, number>,
config?:string
) {
this.name = name;
this.entries = entries;
this.config = config ?? "origin";
}
}
export class DataManager {
public datas:Data[] = data.datas;
}
But that last line, public datas:Data[] = data.datas;, is throwing an error.
Is there a proper way to import data like this?
The goal, ultimately, is to achieve three things:
Any time entries is present, it should receive some validation that it only contains properties of type number; what those properties are is unknown to the programmer, but will be relevant to the end-user.
If config is absent in the JSON file, the construction of Data objects should supply a default value (here, it's "origin")
This assignment of the data should occur with as little boilerplate code as possible. If, down the line Data is updated to have a new property (and Data.json might or might not receive updates to its data to correspond), I don't want to have to change how DataManager.data receives the values
Is this possible, and if so, what's the correct way to write code that will do this?
The lightest weight approach to this would not be to create or use classes for your data. You can instead use plain JavaScript objects, and just describe their types strongly enough for your use cases. So instead of a Data class, you can have an interface, and instead of using instances of the Map class with string-valued keys, you can just use a plain object with a string index signature to represent the type of data you already have:
interface Data {
name: string;
config: string;
entries: { [k: string]: number }
}
To make a valid Data, you don't need to use new anywhere; just make an object literal with name, config, and entries properties of the right types. The entries property is { [k: string]: number }, which means that you don't know or care what the keys are (other than the fact that they are strings as opposed to symbols), but the property values at those keys should be numbers.
Armed with that definition, let's convert data.datas to Data[] in a way that meets your three criteria:
const datas: Data[] = data.datas.map(d => ({
config: "origin", // any default values you want
...d, // the object
entries: onlyNumberValues(d.entries ?? {}) // filter out non-numeric entries
}));
function onlyNumberValues(x: { [k: string]: unknown }): { [k: string]: number } {
return Object.fromEntries(
Object.entries(x).filter(
(kv): kv is [string, number] => typeof kv[1] === "number"
)
);
}
The above sets the entries property to be a filtered version of the entries property in the incoming data, if it exists. (If entries does not exist, we use an empty object {}). The filter function is onlyNumberValues(), which breaks the object into its entries via the Object.entries() method, filters these entries with a user-defined type guard function, and packages them back into an object via the Object.fromEntries() method. The details of this function's implementation can be changed, but the idea is that you perform whatever validation/transformation you need here.
Any required property that may be absent in the JSON file should be given a default value. We do this by creating an object literal that starts with these default properties, after which we spread in the properties from the JSON object. We do this with the config property above. If the JSON object has a config property, it will overwrite the default when spread in. (At the very end we add in the entries property explicitly, to overwrite the value in the object with the filtered version).
Because we've spread the JSON object in, any properties added to the JSON object will automatically be added. Just remember to specify any defaults for these new properties, if they are required.
Let's make sure this works as desired:
console.log(datas)
/* [{
"config": "origin",
"name": "test1",
"entries": {
"red": 1,
"green": 2
}
}, {
"config": "remote",
"name": "test2",
"entries": {
"red": 1,
"blue": 3
}
}, {
"config": "origin",
"name": "test3",
"entries": {
"red": 1,
"blue": 3,
"purple": 3
}
}] */
Looks good.
Playground link to code

reading json file using jackson library in scala language

I am newto the scala language to i am trying to read the json file in my scala file using jackson library
my son file is like this
{
"Rice":[
{
"name":"Basmati",
"price":40
},
{
"name":"jeera",
"price":30
},
{
"name":"Indrayani",
"price":40
}
],
"Pulses":[
{
"name":"peas",
"price":60
},
{
"name":"ground nut",
"price":60
},
{
"name":"dal",
"price":80
}
],
"Wheats":[
{
"name":"atta",
"price":40
},
{
"name":"bread",
"price":45
},
{
"name":"bun",
"price":50
}
]
}
I tried with the case classes to store and print the data
code sample like this
case class Inventory(var name:String,var price:String)
object InventoryDataManagement {
def main(args: Array[String]): Unit = {
val mapper = JsonMapper.builder()
.addModule(DefaultScalaModule)
.build()
val src = new File("src/main/json/inventary.json")
val myMap = mapper.readValue(src,classOf[Inventory])
println(myMap.name)
}
}
but I am getting error like below
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Rice" (class Inventory), not marked as ignorable (2 known properties: "price",
"name"])
please help to understand this
thanks in advance!!!
Unrecognized field "Rice" (class Inventory)
This error should make you notice that Jackson is looking for a field Rice on the Inventory class, which doesn't make sense.
Why so?
Because you are telling Jackson to read your JSON file as a single Inventory instance.
This is not what your JSON file contains, it contains something that can be represented as a Map[String, Seq[Inventory]].
You should try something like this instead:
mapper.readValue(src,classOf[Map[String, Seq[Inventory]]])

Json manipulation TypeScript Angular 2

I come from a Python Background and recently started programming using TypeScript and Angular2. I want to know how to obtain keys from a JSON object using TypeScript.
I have a response like so:
response.text()
I pass this object to a function
removeMetaData (my_data: string){
//(Various manipulation)...etc
}
i have read that I can call a json() method instead of text(). If I do that, what is the type I should use for my_data?
Then,
If my JSON looks like this:
{
"count": 100,
"next_page": "http://www.test.com/users/?page=2",
"prev_page": "http://www.test.com/users/?page=3",
"results":[
{
"username": "johnny"
},
Etc....
]
How do I parse that?
I've read I might have to use an interface but I don't understand how.
In python it's just response["next_page"] to get the key of a dictionary, then I can assign that value to a variable within the class. That is exactly what I'm trying to achieve within a component.
Thank you.
ADDITION
list() {
this.requestService.get(this.api_path)
.subscribe(
response => this.populate(response.json()),
error => this.response = error.text()
)
}
populate(payload: object) {
this.count = payload.count;
this.next = payload.next;
this.previous = payload.previous;
*payload.results => this.users = payload.results;******
}
Declare an interface which will be used as value object.
export interface IPage
{
count:number;
next_page:string;
prev_page:string;
results:Array<any>;
...
...
}
var my_data:IPage;
Now assign parsed json value to my_data and access all the properties with '.' operator i.e. my_data.count, my_data.results.
Feel free to throw any question.
If I do that, what is the type I should use for my_data?
Its just a javascript object.
As an example if you json looks like:
{
"foo": {
"bar": "bas"
}
}
Then in the parsed json (in variable someObj) the value someObj.foo.bar would be bas 🌹

Marshal dynamic JSON field tags in Go

I'm trying to generate JSON for a Terraform file. Because I (think I) want to use marshalling instead of rolling my own JSON, I'm using Terraforms JSON format instead of the 'native' TF format.
{
"resource": [
{
"aws_instance": {
"web1": {
"some": "data"
}
}]
}
resource and aws_instance are static identifiers while web1 in this case is the random name. Also it wouldn't be unthinkable to also have web2 and web3.
type Resource struct {
AwsResource AwsResource `json:"aws_instance,omitempty"`
}
type AwsResource struct {
AwsWebInstance AwsWebInstance `json:"web1,omitempty"`
}
The problem however; how do do I generate random/variable JSON keys with Go's field tags?
I have a feeling the answer is "You don't". What other alternatives do I have then?
In most cases where there are names not known at compile time, a map can be used:
type Resource struct {
AWSInstance map[string]AWSInstance `json:"aws_instance"`
}
type AWSInstance struct {
AMI string `json:"ami"`
Count int `json:"count"`
SourceDestCheck bool `json:"source_dest_check"`
// ... and so on
}
Here's an example showing how to construct the value for marshalling:
r := Resource{
AWSInstance: map[string]AWSInstance{
"web1": AWSInstance{
AMI: "qdx",
Count: 2,
},
},
}
playground example