I search google and stackoverflow but did not find some auto converting lib like in C#
I need something in dart-flutter alternative to this code in C#
string jsonTokenData = "{my token json data}";
TokenModel getTokenModel = Newtonsoft.Json.JsonConvert.DeserializeObject<GetTokenModel>(jsonTokenData);
Update
I read the Documentation and I know how to map models with json
this question to who know how Newtonsoft lib work on C#
if you do not know Newtonsoft: the Idea is to convert json data to a model automatically without writing map for each model. Also I know there is a tool to create that map with json for each model automatically but still make code ridiculous.
Update2: as I get a suggestion from community for a similar question that not answer my question. so this is a another explanation:
I have a lot of models these models are updated by time as clients requested or adding new features to some models.
so when an update happen I just need to add the extra properties that has been added to these models, I do not need to warry every time about mapping, spell mistaken or using some tools again to regenerate these codes.
so I'm asking for a function that take two parameters
first one is the type of the model
second one the json string that hold the data
[then in return is an object instance of the passed type]
for simple example if I have this class:
class Car {
String name;
String type;
}
Then I could keep it clean this way without getting it dart with other methods:
Car({
this.name,
this.type,
});
factory Car.fromJson(Map<String, dynamic> json) => Car(
name: json["name"],
type: json["type"],
);
Map<String, dynamic> toJson() => {
"name": name,
"type": type,
};
by the way lib in C# is also take care about arrays, lists and nested classes
I hope this time it explained well
I've added a new Dart package to Jsonize custom classes within any data structure.
This is how your Car example would look like:
import 'package:jsonize/jsonize.dart';
class Car implements Jsonizable<Car> {
final String name;
final String type;
Car({required this.name, required this.type});
// Jsonizable implementation
factory Car.empty() => Car(name: "", type: "");
#override
String get jsonClassCode => "car";
#override
Map<String, dynamic> toJson() => {"name": name, "type": type};
#override
Car? fromJson(value) => Car(name: value["name"], type: value["type"]);
}
void main() {
// Register classes
Jsonize.registerClass(Car.empty());
// Now you can jsonize it wherever
Map<String, dynamic> myMap = {
"my_car": Car(name: "Jessie", type: "Tesla"),
"purchase_dt": DateTime.now(),
};
var jsonRep = Jsonize.toJson(myMap);
var hereIsMyMap = Jsonize.fromJson(jsonRep);
print(hereIsMyMap);
List<dynamic> myList = [
Car(name: "Jessie", type: "Tesla"),
Car(name: "Bob", type: "Ford"),
];
jsonRep = Jsonize.toJson(myList);
var hereIsMyList = Jsonize.fromJson(jsonRep);
print(hereIsMyList);
}
just import dart:convert library like this :
import 'dart:convert';
Then use this code :
json.decode(json)
Take a look at this link : dart:convert library
Doing some research would allow you to not ask here on SO.
JSON decoding is well documented on the flutter site. It points to using the jsonDecode function, which parses the String and returns the resulting JSON object.
String jsonTokenData = "{my token json data}";
dynamic json = jsonDecode(jsonTokenData);
You can pass the decoded object to a custom constructor of your object like .fromJson, which accepts a Map/List depending on your JSON data.
If for some reason creating a constructor to accept JSON data would be too much work/typing or if you're having trouble doing it yourself, you can use a JSON to Dart service like this.
Related
I have created a weather model class with its parameters and I'm going to get data from the API.
But I'm a bit curious If I want to get data from 2 APIs with different parameters how do I use the same model classes?
Example: API 1 -> returns 'temp' and API 2 -> returns 'temperature' and I want to use the same model class.
Is this even possible? If so how should I do it?
Include all parameters from both api response and make params which are different in both Apis nullable.
use different fromJson in your model class:
for example in one of them do this:
static Weather fromJsonOne(Map<String, Object> json) {
return Weather(
temp: json["temp"] as String
);
}
and in the other do this:
static Weather fromJsonTwo(Map<String, Object> json) {
return Weather(
temp: json["temperature"] as String
);
}
I have a #freezed class defined like below and I need to be able to use its artistId in order to make an API call and get an Artist object. Since that object will be used across multiple screens and filtering functions, I don't want to make requests every single time.
Since the freezed library doesn't allow mutable state in annotated classes, what would be the best workaround?
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../abstract/repository/artist/artist_repository.dart';
import '../artist/artist.dart';
import '../fair/fair.dart';
import '../provenance/provenance.dart';
part 'photo.g.dart';
part 'photo.freezed.dart';
enum OwnershipType { user, artist, collector }
#freezed
class Photo with _$Photo {
factory Photo({
required int id,
required int artistId,
required String title,
required String year,
double? height,
double? length,
double? depth,
required String photo,
required String approved,
required String creationDate,
#JsonKey(name: 'show') Fair? fair,
// required List<Fair> exhibited,
required String description,
required List<Provenance> provenance,
required String submittedDate,
String? submitterName,
bool? pendingUpdate,
String? dimensionUnits,
#Default(<String>[]) List<String> galleryNames,
String? thumb,
}) = _Photo;
factory Photo.fromJson(Map<String, dynamic> json) => _$PhotoFromJson(json);
Photo._();
String get firebasePhoto {
return 'https://storage.googleapis.com/download/storage/v1/b/blob-venture.appspot.com/o/${photo.replaceAll('/', '%2F')}?alt=media';
}
//following is not allowed sadly
// Artist? artist;
// Future<void> fetchArtist(ArtistRepository artistRepository) async {
// artist = await artistRepository.getArtist(id: artistId);
// }
}
I've thought about making another model that will hold the Photo object along with its corresponding Artist object after fetching it, but if there's a better way to go about it, I'd love to know.
Maybe there's another library that allows for such cases? This library was selected by the previous dev of the project but it's not been a great tool for me so far.
You could make a service that handle the API requests.
You could have a state management solution (e.g. flutter_bloc) that handles calling the service. The state management solution could be constructed to provide all the information down a specific widget tree, or the entire app.
Convert the result from your API to a "freezed-model-classes".
freezed is amazing and imo is a great choice by your colleagues. Just make sure to realize that package shouldn't handle everything in your app. In other words, if you are making API calls from your model classes, you could improve the architecture of your app.
To expand further, you could put Artist? as a part of your Photo class by putting it with the rest of your parameters. And you can use the copyWith method to "add" (actually copy with added data as name suggests) new information to an existing Photo object.
Using the source_gen stack to make a code generator, how can I make a generator that generates code that would be the input of another generator (more specifically json_serializable)?
For example, consider:
class Example extends Generator {
#override
String generate(LibraryReader library, BuildStep buildStep) {
return '''
#JsonSerializable(nullable: false)
class Person {
final String firstName;
final String lastName;
final DateTime dateOfBirth;
Person({this.firstName, this.lastName, this.dateOfBirth});
factory Person.fromJson(Map<String, dynamic> json) => _PersonFromJson(json);
Map<String, dynamic> toJson() => _PersonToJson(this);
}
''';
}
}
This is an example of a code-generator that output code which then needs to be sent to json_serializable
What can I do so that json_serializable correctly generates here?
Check the build.yaml config file documentation for more info, but I think you should use the applies_builders param that allows to execute another build after the defined one.
The example shows a builder that generates .tar.gz files and then executes another build that takes the .tar.gz files as input
builders:
# The regular builder config, creates .tar.gz files.
regular_builder:
import: "package:my_package/builder.dart"
builder_factories: ["myBuilder"]
build_extensions: {".dart": [".tar.gz"]}
auto_apply: dependents
apply_builders: [":archive_extract_builder"]
post_process_builders:
# The post process builder config, extracts .tar.gz files.
extract_archive_builder:
import: "package:my_package/extract_archive_builder.dart"
builder_factory: "myExtractArchiveBuilder"
input_extensions: [".tar.gz"]
so with source_gen you should implement for your build
applies_builders: ["source_gen|combining_builder", "json_serializable"]
and configure the other builder
json_serializable:
import: "package:json_serializable/builder.dart"
builder_factories: ["jsonSerializable"]
build_extensions: {".dart": ["json_serializable.g.part"]}
auto_apply: dependents
build_to: cache
applies_builders: ["source_gen|combining_builder"]
It's not possible just with annotation because there maybe two packages that both have the #JsonSerializable annotation
There are two situtations :
You know what other generators should run after your generator.
https://stackoverflow.com/a/59605830/6877472 is one of the solutions
you can use the other generator's code in your own generator and call their generator's.generate function. example code:
class Example extends Generator {
#override
String generate(LibraryReader library, BuildStep buildStep) {
return JsonSerializable().generate('''
#JsonSerializable(nullable: false)
class Person {
final String firstName;
final String lastName;
final DateTime dateOfBirth;
Person({this.firstName, this.lastName, this.dateOfBirth});
factory Person.fromJson(Map<String, dynamic> json) => _PersonFromJson(json);
Map<String, dynamic> toJson() => _PersonToJson(this);
}
''');
}
}
You don't know what other generators should run after your generator.
Unfortunately currently there is no way to tell the source_gen that your generator may produce a code that needs code generation.
I created an issue here https://github.com/dart-lang/source_gen/issues/442 if you want to subscribe
You can decode the JSON by calling the jsonDecode() function, with the JSON string as the method argument.
Map<String, dynamic> user = jsonDecode(jsonString);
print('Howdy, ${user['name']}!');
print('We sent the verification link to ${user['email']}.');
Now, Use the User.fromJson() constructor, for constructing a new User instance from a map structure and a toJson() method, which converts a User instance into a map.
employee.dart
class Employee {
final String name;
final String id;
Employee(this.name, this.id);
Employee.fromJson(Map<String, dynamic> json)
: name = json['name'],
id = json['id'];
Map<String, dynamic> toJson() =>
{
'name': name,
'id': id,
};
}
json_serializable is an automated source code generator that generates the JSON serialization boilerplate for you.
You need one regular dependency, and two dev dependencies to include json_serializable in your project.
dependencies:
json_annotation: ^0.2.3
dev_dependencies:
build_runner: ^0.8.0
json_serializable: ^0.5.0
For more details on JSON serialization you can refer here
you can also use the Smoke library.
It's a subset of the Mirrors functionality but has both a Mirrors-based and a Codegen-based implementation. It's written by the PolymerDart team, so it's as close to "Official" as we're going to get.
While developing, it'll use the Mirrors-based encoding/decoding; but for publishing you can create a small transformer that will generate code.
Seth Ladd created a code sample here, which I extended slightly to support child-objects:
Been doing some research on Flutter Dependency Injection,and I kinda settled on Inject.dart
However, I am having some trouble using inject.
Is there any way to simplify instantitation of a injected class?
I have this MyClass, which I need to instantiate passing a HomeStore, however, how can I instatiate it without calling global acessors? (such as the ones made on the Injector file).
It seems I could just use the Get_It package otherwise, which would get me the same results, and without code generation, but I don't quite like the whole global access thing.
My sample:
// current code
class MyClass(){
store = HomeStore(AppInjector().globalHudStore, AppInjector().globalErrorStore);
}
// desired code
class MyClass(){
#instance ?
store = HomeStore();
store = HomeStore.instanciate?();
}
class HomeStore {
#provide
HomeStore(this._globalHudStore, this._globalErrorStore);
final GlobalHudStore _globalHudStore;
final ErrorStore _globalErrorStore;
}
If you are willing to work with json, you might want to consider this package json_serializable. Just search for it at pub.dev.
I can give a little example. Let's say you have a User class/model.
part 'user.g.dart';
#JsonSerializable()
class User {
int id;
#JsonKey(name: 'user_type_id')
int userTypeId;
String email;
#JsonKey(name: 'user_detail')
UserDetail userDetail;
#JsonKey(name: 'user_type')
UserType userType;
#JsonKey(name: 'user_location')
UserLocation userLocation;
User();
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
and you fetched a User data via API, and want to create a User variable and fill it with data without having to do that manually.
You can actually do that with just this line of code
User user = User.fromJson(jsonUser);
These even automatically json serializes classes in your User class, as long as those classes are also json serializable, which is defined with #JsonSerializable()
So even with just that single line of code, if the jsonUser which came from the API also has values for UserDetail, UserType, and UserLocation, you can also access them.
Looking for help for assigning List values to a class. Here is my class.
class Specialties {
int id;
String name;
String details;
const Specialties(this.id, this.name, this.details);
}
I have a List created from JSON and I have confirmed it has values, but can not get the values assigned to instantiate the class. I know the class works as when I hardcode values it gets created just fine.
This is how I am trying to do it and can not find why it does not work.
Specialties getSpec(int index) {
return new Specialties(mylist[index].id, mylist[index].name, mylist[index].details);
}
I am sure I am missing something easy, but once I saw hardcoded values working, can not figure it out.
Any help would be great.
It seems like you may be coming from a JavaScript background where object.property
object['property'] are equivalent. In Dart, they are not.
If you parsed a JSON object it will turn into a Dart Map with String keys. Modify your getSpec function to use operator[] instead of dot syntax to read the entries of the Map.
Specialties getSpec(int index) {
return new Specialties(mylist[index]['id'], mylist[index]['name'], mylist[index]['details']);
}
You may want to consider giving Specialties an additional fromMap constructor rather than constructing it in an external function. You should also make the fields of Specialties be final since its constructor is const.
class Specialties {
final int id;
final String name;
final String details;
const Specialties(this.id, this.name, this.details);
factory Specialties.fromMap(Map data) => new Specialties(data['id'], data['name'], data['details']);
}
Then you can say
new Specialties.fromMap(mylist[index])
Finally, there are some other JSON deserialization libraries that you might want to consider to reduce the amount of boilerplate deserialization code: Jaguar, built_value.
If you have a JSON string in the form of '[{"id": 1, "name": "ab", "details": "blabla"},{...}]' you can convert it like this:
List<Specialties> specialties(String jsonstring) {
List parsedList = JSON.decode(jsonstring);
return parsedList.map((i) => new Specialties(
i["id"], i["name"], i["details"]));
}
You will have to import dart:convert to get the method JSON.decode