Turn QString to JSON - json

I have the following:
QString notebookid = ui->notebookid->toPlainText();
QString tagid = ui->tagid->toPlainText();
QString userid = ui->userid->toPlainText();
QString subject = ui->subject->toPlainText();
QString comment = ui->comment->toPlainText();
I need to turn them into JSON, where the key is the notebookid, tagid, etc and the value is in the ui->notebookid, etc.
What's the best way to go about doing this?
Thanks.

I'll answer this based on the fact that you were using Qt 4.8 and would not have the QJsonObject available from Qt5.
I use QJSON for exactly this. It's an easy-to-use library using QVariants to parse and serialize the data.
This would be how you'd turn your data into json using QJSON:
QVariantMap jsonMap;
jsonMap.insert("notebookid", notebookid);
jsonMap.insert("tagid", tagid);
jsonMap.insert("userid", userid );
jsonMap.insert("subject", subject );
jsonMap.insert("comment", comment);
QJson::Serializer serializer;
bool ok;
QByteArray json = serializer.serialize(jsonMap, &ok);
assert (ok);

In Qt 5, you can use QJsonObject. One way is to explicitly select the controls to serialize:
QJsonObject MyDialog::serialize() const {
QJsonObject json;
json.insert("notebookid", ui->notebookid->toPlainText());
...
return json;
}
Another way is to have a generic serializer that uses the Qt's metadata. Each named control's user property is then serialized:
QJsonObject serializeDialog(const QWidget * dialog) {
QJsonObject json;
foreach (QWidget * widget, dialog->findChildren<QWidget*>()) {
if (widget->objectName().isEmpty()) continue;
QMetaProperty prop = widget->metaObject()->userProperty();
if (! prop.isValid()) continue;
QJsonValue val(QJsonValue::fromVariant(prop.read(widget)));
if (val.isUndefined()) continue;
json.insert(widget->objectName(), val);
}
return json;
}
You can convert QJsonDocument to text as follows:
QJsonDocument doc(serializeDialog(myDialog));
QString jsonText = QString::fromUtf8(doc.toJson());
Unfortunately, Qt 5's json code requires a bunch of changes to compile under Qt 4.

Related

Why does UserAuthExtensions.PopulateFromMap(session, jwtPayload) does not deserialize json values with escape correctly in ServiceStack.Auth?

We want to get the UserName from the ServiceStack session, but we find that the backslashes in the UserName are not deserialized as expected. The UserName has this format 'domainname\username' and serialized in a jwt token this looks like:
{
"typ": "JWT",
"alg": "HS256"
}.{
"iss": "ssjwt",
"iat": 1635952233,
"exp": 1635955833,
"name": "Robin Doe",
"preferred_username": "domainname\\robindoe"
}.[Signature]
After calling:
var sessionFromJwt = JwtAuthProviderReader.CreateSessionFromJwt(req);
userName = sessionFromJwt.UserName;
The userName variable contains the value 'domainname\\robindoe' instead of 'domainname\robindoe'.
After digging in the ServiceStack code, we pin this down to the PopulateFromMap() method in https://github.com/ServiceStack/ServiceStack/blob/36df74a8b1ba7bf06f85262c1155e1425c082906/src/ServiceStack/Auth/UserAuth.cs#L388.
To demonstrate this problem we have written a small program to prove the point:
class Program
{
static void Main(string[] args)
{
var jwtPayload = JsonObject.Parse(#"{
""iss"": ""ssjwt"",
""iat"": 1635952233,
""exp"": 1635955833,
""name"": ""John Doe"",
""preferred_username"": ""domainname\\username""
}");
var session = new AuthUserSession();
// The PopulateFromMap implementation does not deserialize the json values according to json standards
UserAuthExtensions.PopulateFromMap(session, jwtPayload);
// Notice that the session.UserName still has the escape character 'domainname\\username' instead of the expected 'domainname\username'
Console.WriteLine(session.UserName);
// The PopulateFromMap should deserialize also the values, like in test Can_dynamically_parse_JSON_with_escape_chars()
Can_dynamically_parse_JSON_with_escape_chars();
}
private const string JsonCentroid = #"{""place"":{ ""woeid"":12345, ""placeTypeName"":""St\\a\/te"" } }";
// Source: https://github.com/ServiceStack/ServiceStack.Text/blob/master/tests/ServiceStack.Text.Tests/JsonObjectTests.cs
public static void Can_dynamically_parse_JSON_with_escape_chars()
{
var placeTypeName = JsonObject.Parse(JsonCentroid).Object("place").Get("placeTypeName");
if (placeTypeName != "St\\a/te")
throw new InvalidCastException(placeTypeName + " != St\\a/te");
placeTypeName = JsonObject.Parse(JsonCentroid).Object("place").Get<string>("placeTypeName");
if (placeTypeName != "St\\a/te")
throw new InvalidCastException(placeTypeName + " != St\\a/te");
}
}
Why does UserAuthExtensions.PopulateFromMap(session, jwtPayload) does not deserialize json values with escape correctly in ServiceStack.Auth?
The issue is due to enumerating a JsonObject didn't return the same escaped string value as indexing it which has been resolved from this commit.
This change is available from v5.12.1+ that's now available on MyGet.

Deserialize Json Object list with id as root with jackson

I have this json structure from firebase where it's a list of objects but the root of each object is the ID
How can I serialize this to a list of object with the id/root as a member variable. This is for Spring boot so I would prefer if it were a Jackson2 solution.
This may be the same question as Jackson JSON key as value in Java but my answer is better because it doesn't require an extra/useless class
val reader = ObjectMapper().reader()
val tree = reader.readTree(testJson)
val eventList = mutableListOf<Event>()
tree.fields().iterator().forEach {
val event = Event(
it.key,
it.value.get("name").asText(),
it.value.get("description").asText(),
it.value.get("startDate").asText(),
it.value.get("startTime").asText(),
it.value.get("endDate").asText(),
it.value.get("endTime").asText(),
it.value.get("imageUrl").asText()
)
eventList.add(event)
}
I have found a solution using jackson in kotlin, it's not the prettiest but it works. the fields method returns a map of children. So, I am iterating through the map and adding the key as the object id member and then grabbing the rest of the data from the nested map.
Sorry, I am not a pro in Jackson. But there is a simple way to transform your object in JavaScript -- and perhaps this will lay the foundation for something that can be ported to Jackson (java?)
This is the convertData function that does the transform:
var convertData = function (d) {
var arr = [];
for(var prop in data)
{
var el = { "id": prop };
var otherprops = data[prop];
for(var otherprop in otherprops)
{
el[otherprop] = otherprops[otherprop];
}
arr.push(el);
}
return arr;
}
Tnis is what my sample data looks like after the conversion (slightly different values than yours):
[{"id":"-L8eoUd5mqJGnXDVSmb0","description":"With a great description","endDate":"12/31/2018","endTime":"03:00","imageUrl":"/favicon.ico","name":"Here's a Good Event","startDate":"12/01/2018","startTime":"12:00"},{"id":"-L8jO6Zhz976hvoLUiga","description":"Another item","endDate":"12/30/2018","endTime":"03:05","imageUrl":"/favicon2.ico","name":"Event #2","startDate":"12/11/2018","startTime":"12:03"}]
Link to JSFiddle: https://jsfiddle.net/2t1s2are/13/
Hope this helps!!

Use Jackson To Stream Parse an Array of Json Objects

I have a file that contains a json array of objects:
[
{
"test1": "abc"
},
{
"test2": [1, 2, 3]
}
]
I wish to use use Jackson's JsonParser to take an inputstream from this file, and at every call to .next(), I want it to return an object from the array until it runs out of objects or fails.
Is this possible?
Use case:
I have a large file with a json array filled with a large number of objects with varying schemas. I want to get one object at a time to avoid loading everything into memory.
EDIT:
I completely forgot to mention. My input is a string that is added to over time. It slowly accumulates json over time. I was hoping to be able to parse it object by object removing the parsed object from the string.
But I suppose that doesn't matter! I can do this manually so long as the jsonParser will return the index into the string.
Yes, you can achieve this sort of part-streaming-part-tree-model processing style using an ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
JsonParser parser = mapper.getFactory().createParser(new File(...));
if(parser.nextToken() != JsonToken.START_ARRAY) {
throw new IllegalStateException("Expected an array");
}
while(parser.nextToken() == JsonToken.START_OBJECT) {
// read everything from this START_OBJECT to the matching END_OBJECT
// and return it as a tree model ObjectNode
ObjectNode node = mapper.readTree(parser);
// do whatever you need to do with this object
}
parser.close();
What you are looking for is called Jackson Streaming API. Here is a code snippet using Jackson Streaming API that could help you to achieve what you need.
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createJsonParser(new File(yourPathToFile));
JsonToken token = parser.nextToken();
if (token == null) {
// return or throw exception
}
// the first token is supposed to be the start of array '['
if (!JsonToken.START_ARRAY.equals(token)) {
// return or throw exception
}
// iterate through the content of the array
while (true) {
token = parser.nextToken();
if (!JsonToken.START_OBJECT.equals(token)) {
break;
}
if (token == null) {
break;
}
// parse your objects by means of parser.getXxxValue() and/or other parser's methods
}
This example reads custom objects directly from a stream:
source is a java.io.File
ObjectMapper mapper = new ObjectMapper();
JsonParser parser = mapper.getFactory().createParser( source );
if ( parser.nextToken() != JsonToken.START_ARRAY ) {
throw new Exception( "no array" );
}
while ( parser.nextToken() == JsonToken.START_OBJECT ) {
CustomObj custom = mapper.readValue( parser, CustomObj.class );
System.out.println( "" + custom );
}
This is a late answer that builds on Ian Roberts' answer. You can also use a JsonPointer to find the start position if it is nested into a document. This avoids custom coding the slightly cumbersome streaming token approach to get to the start point. In this case, the basePath is "/", but it can be any path that JsonPointer understands.
Path sourceFile = Paths.get("/path/to/my/file.json");
// Point the basePath to a starting point in the file
JsonPointer basePath = JsonPointer.compile("/");
ObjectMapper mapper = new ObjectMapper();
try (InputStream inputSource = Files.newInputStream(sourceFile);
JsonParser baseParser = mapper.getFactory().createParser(inputSource);
JsonParser filteredParser = new FilteringParserDelegate(baseParser,
new JsonPointerBasedFilter(basePath), false, false);) {
// Call nextToken once to initialize the filteredParser
JsonToken basePathToken = filteredParser.nextToken();
if (basePathToken != JsonToken.START_ARRAY) {
throw new IllegalStateException("Base path did not point to an array: found "
+ basePathToken);
}
while (filteredParser.nextToken() == JsonToken.START_OBJECT) {
// Parse each object inside of the array into a separate tree model
// to keep a fixed memory footprint when parsing files
// larger than the available memory
JsonNode nextNode = mapper.readTree(filteredParser);
// Consume/process the node for example:
JsonPointer fieldRelativePath = JsonPointer.compile("/test1");
JsonNode valueNode = nextNode.at(fieldRelativePath);
if (!valueNode.isValueNode()) {
throw new IllegalStateException("Did not find value at "
+ fieldRelativePath.toString()
+ " after setting base to " + basePath.toString());
}
System.out.println(valueNode.asText());
}
}

Antlr4 StringTemplate not compatible with Json.net dynamic items

I would like to read a dynamic object from a json file and then use this in a stringTemplate.
The following code works.
dynamic data = new { bcName = "Lixam B.V", periodName = "July 2013" };
var engine = new Template("<m.bcName> <m.periodName>");
engine.Add("m", data);
engine.Render().Should().Be("Lixam B.V July 2013");
The following code fails
var json = "{bcName : 'Lixam B.V', periodName : 'July 2013'}";
dynamic data = JsonConvert.DeserializeObject(json);
string name = (data.bcName);
name.Should().Be("Lixam B.V"); // this passes
var engine = new Template("<m.bcName> <m.periodName>");
engine.Add("m", data);
engine.Render().Should().Be("Lixam B.V July 2013"); //fails
Is there another way to configure JsonConverter to be compatible with StringTemplate
You need to create an IModelAdaptor for whatever the compiled type representing dynamic is, and register it using TemplateGroup.RegisterModelAdaptor.
Inspired on Mr. Harwell's answer, I've implemented an IModelAdaptor that enable the usage of Newtonsoft.Json parsed objects.
Here it goes:
internal class JTokenModelAdaptor : Antlr4.StringTemplate.IModelAdaptor
{
public object GetProperty(
Antlr4.StringTemplate.Interpreter interpreter,
Antlr4.StringTemplate.TemplateFrame frame,
object obj,
object property,
string propertyName)
{
var token = (obj as JToken)?.SelectToken(propertyName);
if (token == null)
return null;
if (token is JValue)
{
var jval = token as JValue;
return jval.Value;
}
return token;
}
}
You just need to register the adaptor in your template group, like this:
template.Group.RegisterModelAdaptor(typeof(JToken), new JTokenModelAdaptor());

How can I JSON.stringify a Collection in Dart

How can I made a JSON string out of a collection in dart, as I can do it with Maps. The docs say I can pass a map or a an array into the JSON.stringify() method. But there are no Array data type in Dart and passing a collection gives me an exception.
I've a naive workaround, but I wonder if there will be a better way to do this:
String s = '[';
bool first=true;
_set.forEach(function(item){
if (first) {
first = false;
} else {
s+=',';
}
s += JSON.stringify(item);
});
s +=']';
print(s);
return s;
In Dart, you can get a JSON String out of an Object using the JsonEncoder's convert method. Here is an example:
import 'dart:convert';
void main() {
final jsonEncoder = JsonEncoder();
final collection1 = List.from([1, 2, 3]);
print(jsonEncoder.convert(collection1)); // prints [1,2,3]
final collection2 = List.from(['foo', 'bar', 'dart']);
print(jsonEncoder.convert(collection2)); // prints ["foo","bar","dart"]
final object = {'a': 1, 'b': 2};
print(jsonEncoder.convert(object)); // prints {"a":1,"b":2}
}
Passing a list works for me:
in the Dart VM importing dart-sdk/lib/frog/server/dart_json.dart
in Dartium importing json:dart
using this code:
void main() {
var list = new List.from(["a","b","c"]);
print(JSON.stringify(list));
}
prints this JSON snippet:
["a","b","c"]
Doesn't work for new Set.from(...) which is expected, given that JSON only deals in maps and lists.