Casting an object in Flutter/Dart returns _HashSet - flutter

I am having some problem in Flutter with casting a dynamic to a custom object. I receive JSON as response from a web service, which I store as an instance of my object in a class as dynamic together with some other meta information. When I try to cast that object to my desired class (e.g. LoginReply) I keep getting the following error message: Expected a value of type 'LoginReply', but got one of type '_HashSet<LoginReply>'
Here is my response class that stores the reply object:
class DioResponse {
String? error;
dynamic object;
DioResponse(this.error, this.object);
bool get isSuccessful => error == null || error!.isEmpty;
T get<T extends dynamic>() {
print("Object: $object");
return object.cast<T>();
}
}
I serialize the JSON response like this:
LoginReply _serializeResponse(Map<String, dynamic> json) {
LoginReply reply = LoginReply.fromJson(json);
if (!reply.header!.successful) {
errorMessage.value = "${reply.header!.errorCode}: ${reply.header!.errorMessage}";
return LoginReply();
}
AppConfig.persistString("token", reply.token!);
return reply;
}
And here is how I try to access the DioReponse.object / LoginReply:
DioResponse response = await handler.post(Globals.nodeAddress, ......);
if (response.isSuccessful) {
//LoginReply reply = response.get<LoginReply>();
print("Object: ${response.object}");
LoginReply reply = response.object as LoginReply;
The print output on the second last line prints: Object: {Instance of 'LoginReply'} which makes the whole error even harder to understand for me.

The problem was in the closure that was passed as parameter to the post function. So it really returned a Set. I pass a function to the DioHandler class that is called there and then it just works the way it should.

Related

Single value in ionic http post param

Hi I'm new to ionic/angular and I'm reading someone else code and came across the function below in the Service
makePostRequest(100)
public makePostRequest(param) {
return this.http.post('/sample/api', param);
}
Does this mean param is sent as json body or just a value, online documentation just shows json body as the argument not a single value. Can someone help me with this
Thanks in advance.
The post body is sent as serialized parameters as explained here.
In the example you have provided, they are calling the makePostRequest() function and providing an argument of 100. When the makePostRequest() function runs, it takes that value from the argument and sets it as a parameter which is then used to populate the body in the POST request.
You can still send single values as you would multiple values with something similar to this:
sendData() {
const data = {
number: 100
};
return this.http.post('myurl.com', data);
}
Or for multiple:
sendData() {
const data = {
number: 100,
fruit: 'banana'
};
return this.http.post('myurl.com', data);
}
You can of course pass multiple arguments if you have parameters set up to accept them:
sendData(body: { score: number, fruit: string }) {
return this.http.post('myurl.com', body);
}

type 'Response<dynamic>' is not a subtype of type 'String

I tried to decode JSON Data using JsonDecode(). when I try to access each member through [] indexing and try to print them, the above error is printed onto my terminal. I am trying to build an expense tracker app that uses a pie chart to display the different expenses of the user.
Here is a small snippet of the code. I can provide more if needed.
var expense = Expense(
_dateController.text, categories.toString(), money);
token.storage.read(key: "jwt").then((value) {
AuthService().getExpense(value).then((val) => {
print(val), // this prints the json data
mv = jsonDecode(val), // i tried to decode it
item = mv[0], //acessing each member
print(item['category']),
});
});
Once again the error I get is:
[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'Response' is not a subtype of type 'String'
it is giviing error because return type of api call is of type Response and print function can print string only try to conver that value into string using .toString method. also if you are making an api call you should accces its body to print.
for example :
token.storage.read(key: "jwt").then((value) {
AuthService().getExpense(value).then((val) => {
print(val.body.toString), // change here
});
});

Parse Server SDK - Include Object method doesn't work for fetching the whole object in flutter

I was using parse server sdk in my app for database.
I have three class in my Back4App Dashboard which are "_User", "Office", "Office_Members".
In Office_Members class it has following columns,
user_id (Pointer to _User)
office_id (Pointer to Office)
count
To fetch the data including Pointer to _User as well from Office_Members, I am using following code,
QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject("Office_Members"))
..whereEqualTo("office_id", ParseResponse_OfficeObject)
..includeObject(["user_id "]);
ParseResponse apiResponse = await parseQuery.query();
Output :
Payload : [{"className":"Office_Members","objectId":"twpDY51PUK","createdAt":"2020-08-14T09:58:59.775Z","updatedAt":"2020-08-14T09:58:59.775Z","office_id":{"__type":"Pointer","className":"Office","objectId":"4dkfSMrwBI"},"user_id":{"__type":"Pointer","className":"_User","objectId":"Hx5xJ5ABxG"},"count":1}]
In my payload response i am not getting whole user_id pointer response.
So can anybody help me that what i might be doing wrong?
Thanks.
The data should be included.
The logging function simply does not print the data of pointers.
The data should be included. The print function not print the data of pointers.
You can print it out directly for testing purposes, E.g.
response.results[0].get('user_id').get('name')
Evaluation Expression E.g.
In your model u can access at same way, E.g
Call Model
if(response.success){
return response.results.map((p) => Example.fromParse(p)).toList();
} else {
throw ParseErrors.getDescription(response.error.code);
}
Model
import 'package:parse_server_sdk/parse_server_sdk.dart';
class Example {
Example({this.id, this.name});
Example.fromParse(ParseObject parseObject) :
id = parseObject.objectId,
name = parseObject.get('user_id').get('name');
final String id;
final String name ;
#override
String toString() {
return 'Example{id: $id, name: $name}';
}
}
Why not simply use cloud code ? I'm not to familiar with flutter but I can suggest you this alternative solution.
Write a function like this.
Parse.Cloud.define("fetchMemberAndUser", async (request) => {
//Pass in ParseResponse_OfficeObject ID as parameter
var objectId = request.params.id;
//Now do a simple get query
var query = new Parse.Query(Parse.Object.extend("Office_Members"));
//Using .includes to get the user profile object
query.include("user_id");
//This will return Office_Memebers Object along with user profile
return query.get(objectId,{useMasterKey:true});
}

Bad Request on simple POST Request

I have broke it down to a minimum and still don't know why this happens.
I have the following method in my controller:
#RequestMapping(method = RequestMethod.POST, value = "/myGreatCall")
public String getDynamicData(#RequestBody DataRequest dr) {
return dr.toString();
}
Using the following simple class:
public class DataRequest {
private String type;
//Getters and setters here
}
Now if I try to call this, I get an error 400 as the response.
let url = window.location.protocol+"//"+window.location.host+"/myGreatCall";
let request = new XMLHttpRequest();
request.open("POST", url, true);
request.onload = function () {
console.log(request.response); //Here I read the reponse and get the error 404
};
// This is the data I send as the body
let data = JSON.stringify(
{
type: "myType"
}
);
request.setRequestHeader("Content-Type", "application/json");
request.send(data);
Now from the error I suspect that for some reason it cant map my json object into the java object, but I have no idea why.
I tested the following:
do the request without the Method Parameter, that worked
different data types in the java class
handing over a hardcoded string '{\"type\":\"myType\"}' to the #send()
Any Ideas what I might be doing wrong?
It may be down to JSON serialization. Try this:
let data = JSON.stringify(
{
"type": "myType"
}
);
Ok seems to be something weird. I dont know what caused it, but after a PC restart it worked fine.

How to parse an object variable in eventChannel callback method?

I am programming a flutter app, in which I have a callback from the native system containing some nfc information. I register the callback via the following line of code:
eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
The callback looks like this:
void _onEvent(Object event) {
//Receive Event
print("NFC Event received");
//Get the Payload
event['Payload']; //This does not work, it gives an error
}
But how can I parse out the data? I know it contains a field by the name Payload however, I cannot access it via event['Payload'].
I am very confused, I tried to cast it to another type like this: Map<String, String> eventMap = Map<String, String>.from(event); but that didnt work. Could someone please point out what I am doing wrong and how I can correctly extract the data?
Without too much information of native part, I suggest
you can reference this package or fork this https://github.com/akeblom/flutter-nfc-reader
directly
this repo fix some issue of pub.dev and work well in real device
the dart code you need reside in
https://github.com/akeblom/flutter-nfc-reader/blob/master/lib/flutter_nfc_reader.dart
void _onEvent(dynamic data) {
print("Event");
print(data);
}
Edit add more detail
akeblom has add Write NFC capability to IOS, so IOS part should work. please ue this fork https://github.com/akeblom/flutter-nfc-reader
For IOS MissingPluginException issue, I do not have IOS, I suggest you can ask akeblom
The data part you mentioned in comments if I do not misunderstand is line 77, please see describe below
In Android part.
https://github.com/akeblom/flutter-nfc-reader/blob/master/android/src/main/kotlin/it/matteocrippa/flutternfcreader/FlutterNfcReaderPlugin.kt
line 174, use kotlin mapOf returns a new read-only map with the specified contents and eventSink.success result to Dart
if (message != null) {
val data = mapOf(kId to id, kContent to message, kError to "", kStatus to "read")
eventSink?.success(data)
}
In https://github.com/akeblom/flutter-nfc-reader/blob/master/lib/flutter_nfc_reader.dart
line 22, with named constructor
factory NfcData.fromMap(Map data) {
NfcData result = NfcData(
id: data['nfcId'],
content: data['nfcContent'],
error: data['nfcError'],
statusMapper: data['nfcStatus'],
);
In line 77, NFC read start and _onEvent(dynamic data) get the data.
stream use this named constructor, and parse data, here with map((result)) transfer to NfcData
static Stream<NfcData> get read {
final resultStream = _channel
.invokeMethod('NfcRead')
.asStream()
.asyncExpand((_) => stream
.receiveBroadcastStream()
.map((result) => NfcData.fromMap(result)));
return resultStream;
In https://github.com/akeblom/flutter-nfc-reader/blob/master/example/lib/main.dart
line 33, response has transfered to NfCData, so example just use _nfcData = response;
FlutterNfcReader.read.listen((response) {
setState(() {
_nfcData = response;
});
});
The simplest way I found to parse an event to a Map is the following:
I encoded the variable to a String (but I use json.encode(event)instead of event.toString()as encode(event)returns a valid string.
Then I use this string to construct a map via json.decode. All of this is achieved with the flutter native library dart:convert. The complete code looks like this:
import 'dart:convert';
...
void _onEvent(dynamic event) {
//Receive Event
print("NFC Event received");
String str = json.encode(event);
Map eventMap = json.decode(str);
}
Have you tried event.toString()? It might return a string containing the field you are trying to get, from which you can easily parse the value.
You may also want to try:
Class<?> clazz = event.getClass();
Field payload= clazz.getField("Payload"); //Note, this can throw an exception if the field doesn't exist.
String fieldValue = payload.toString();
If it isn't returning what you want, you may need to make an interface for the object type, with a get method, or override the toString method to get return the Payload value.