Dynamic tag in JSON - json

I am generating one JSON file and I have a variable of the below type in TypeScript:
export interface Rules{
name: string,
condition: string,
}
I want to parse the 'Rule' type in JSON in the below format:
"dataRetentionRules": {
"RULE_1": {
"name": "test123",
"condition": "RetentionStartDate"
},
"RULE_2": {
"name": "test456",
"condition": "RetentionEndDate"
}
}
How can I make this rule tag dynamic? I mean how do I parse this "RULE_1", "RULE_2" tag? Since tags are supposed to be constant I believe. How can I achieve the above format?

You can make use of the typescript Record built-in type. Behind the scenes you are using the principles of index types and mapped types.
But all that you really need to know it this: Record<string, Rules> defines an object whose keys are strings and whose values are instances of Rules.
Your JSON object can be described by
interface HasRetentionRules {
dataRetentionRules: Record<string, Rules>
}
Note that this is asserting that any string key corresponds to a Rules object and it does not check for invalid keys, so you need to check for invalid keys yourself. Alternatively, you can use Partial<Record<string, Rules>> which states that any string key has a value which is of type Rules or undefined.
Typescript Playground Link

Related

JSON schema conditional check in JSON object within array

Here is the desired schema and json for illustration purpose. Please see the link below.
JSON Schema and JSON
{
"id": "123" ,
"ts": "1234567890",
"complex_rules":
[
{
"type":"admin",
"rule":{
"rights":"all",
"remarks": "some admin remarks"
}
},
{
"type":"guest",
"rights": "limited"
},
{
"type":"anonymous",
"rights": "blocked"
}
]
}
The 'complex_rules' is an array of json object:
With type either be a : "admin", "guest", "anonymous" and the 'type' attribute is MANDATORY.
Each object in array can have its own structure, but the type can be either of: "admin", "guest", "anonymous" only. No other type attribute is acceptable.
The conditions to evaluate:
The type of object in the array cannot re-occur in the array. (I know this seems to be not possible, so we can ignore this)
If attribute "rights" in the {type=admin object} with any value, then we cannot have "rights": "limited" or any value in {type=guest object}. The JSON Schema validation must complain about this.
Another twist, either object {type":"guest"}or {type":"anonymous"} can exist. Both types cannot coexist along with other types.
----Update
The above link is the solution this question.
In regards to 1 and 2:
You need to use a combination of if, then, and not keywords to construct the logic you require with the correct level of applicability.
In regards to 3:
The type of object in the array cannot re-occur in the array. (I know
this seems to be not possible, so we can ignore this)
Right, that's correct, it's not possible as of draft-7 JSON Schema.

Assign proper types to data read from JSON

I have a struct such as this one:
type Data struct {
Id string
Value string
Custom customtype1
Special customtype2
TimeStamp Time
}
var model Data
I am reading data from a JSON object. Because the JSON is structured very differently, I can't just directly unmarshall the JSON into the struct. So I am trying to "match" the fields from the JSON objects to those of the struct one by one. I don't actually need to properly unmarshall the JSON data into the struct, all I really need is to be able to assign, for each field, the proper type to its value.
So I unmarshall the JSON to a generic interface, then convert it to a map[string]interface{} and iterate over that. For each field, I try to find a match among the field names in the model variable which I get using reflect.
Now this all works fine, but the problem arises when I try to get the right type for the values.
I can get the Type for a certain field from the model using reflect, but then I can't use that to cast the type of the value I get from the JSON because that is not a type. I can't use a switch statement either, because this is a simplified version of the situation and in reality I'm dealing with 1000+ different possible types. How can I convert the values I have for each field into their proper type ?
The only I can think of solving this would be to recreate a json string that matches the format of the struct and then unmarshall that into its proper struct, but that seems way to convoluted. Surely there must be a simpler way?
Here's a sample JSON (I can not change this structure, unless I rework it within my Go program):
{
"requestId": 101901,
"userName": "test",
"options": [1, 4],
"request": {
"timeStamp": {
"Value1": "11/02/2018",
"Value2": "11/03/2018"
},
"id": {
"Value1": "123abcd",
"Value2": "0987acd",
"Value3": "a9c003"
},
"custom": {
"Value1": "customtype1_value",
"Value2": "customtype1_value"
}
}
}
I'd advise against your current approach. You haven't provided enough context to tell us why you're choosing to unmarshall things one by one, but Go's support for JSON is good enough that I'd guess it is capable of doing what you want.
Are you aware of Marshall's support for struct tags? Those might serve the purpose you're looking for. Your struct would then look something more like:
type Data struct {
Id string `json:"id"`
Value string `json:"value"`
Custom customtype1 `json:"custom_type"`
Special customtype2 `json:"special_type"`
TimeStamp Time `json:"timestamp"`
}
If your problem is that the custom types don't know how to be unmarshalled, you can define custom unmarshalling functions for them.
This would then enable you to unmarshall an object like the following:
{
"id": "foo",
"value": "bar",
"custom_type": "2342-5234-4b24-b23a",
"special_type": "af23-af2f-rb32-ba23",
"timestamp": "2018-05-01 12:03:41"
}

TJSONUnMarshal: how to track what is actually unmarshalled

Is there another way to track what is unmarshalled than write own reverter for each field?
I'm updating my local data based on json message and my problem is (simplified):
I'm expecting json like
{ "items": [ { "id":1, "name":"foobar", "price":"12.34" } ] }
which is then unmarshaled to class TItems by
UnMarshaller.TryCreateObject( TItems, TJsonObject( OneJsonElement ), TargetItem )
My problem is that I can't make difference between
{ "items": [ { "id":1, "name":"", "price":"12.34" } ] }
and
{ "items": [ { "id":1, "price":"12.34" } ] }
In both cases name is blank and i'd like to update only those fields that are passed on json message. Of course I could create a reverted for each field, but there are plenty of fields and messages so it's quite huge.
I tried to look REST.Jsonreflect.pas source, but couldn't make sense.
I'm using delphi 10.
In Rest.Json unit there is a TJson class defined that offers several convenience methods like converting objects to JSON and vice versa. Specifically, it has a class function JsonToObject where you can specify options like for example ignore empty strings or ignore empty arrays. I think the TJson class can serve you. For unmarshalling complex business objects you have to write custom converters though.
Actually, my problem was finally simple to solve.
Instead of using TJSONUnMarshal.tryCreateObject I use now TJSONUnMarshal.CreateObject. First one has object parameters declared with out modifier, but CreateObject has Object parameter var modifier, so I was able to
create object, initalize it from database and pass it to CreateObject which only modifies fields in json message.

Can you flatten a nested JSON structure into a single autobean?

Assuming the following JSON structure:
{
\"is_something\": false,
\"name\": \"Some Name\",
\"subtype\": {
\"total\": 0.0
}
}
Instead of creating two autobean interfaces (one for the whole structure and one for the subtype), I would like to have one which contains all the properties.
public interface ExampleAutoBean {
#PropertyName("is_something")
boolean isSomething();
String getName();
#PropertyName("subtype.total")
double getTotal();
}
So, the getTotal() method is expected to contain the total property of the nested subtype in the JSON structure. I can't find any documentation in the source code or online which states whether or not this is possible.
Thanks in advance!
Nope: AutoBeans are designed to be a mapping from the JSON structure to Java interfaces, plus or minus collections like List, Set, and Map and String encodings of a long or a Date. Additionally, it is legal to have json like the following:
{
"some.property.with.dots" : "abcd",
"name" : "wxyz"
}
If the . character could only be used for traversing into sub-objects, there would be no way to have a getter for the first property.

about the validity of the json message

I am wondering why the following is not a valid json
{ test : event}
but
{ "test" : "event" }
is a valid one?
Because in JSON, fields are declared in quotes (so it's "test" and not test), and the only data types a field can store are: number, string, boolean, array, object (that is, another JSON object), or null. event isn't any of those things, but "event" is a string, which is a valid value type. Those are just the rules of JSON.
You should read up on JSON.