I am surprised that dart does not have a built in object-to-json and json-to-object mapper.
I read that we have to hand code the mapping ourselves, which is not pleasant.
Anyways, although I have not thoroughly tested it for my use case, I found dart-exportable to be very helpful for half of my requirement.
Any suggested package for json to object decoding?
Your best option is to 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:
abstract class Serializable {
static fromJson(Type t, Map json) {
var typeMirror = reflectType(t);
T obj = typeMirror.newInstance(new Symbol(""), const[]).reflectee;
json.forEach((k, v) {
if (v is Map) {
var d = smoke.getDeclaration(t, smoke.nameToSymbol(k));
smoke.write(obj, smoke.nameToSymbol(k), Serializable.fromJson(d.type, v));
} else {
smoke.write(obj, smoke.nameToSymbol(k), v);
}
});
return obj;
}
Map toJson() {
var options = new smoke.QueryOptions(includeProperties: false);
var res = smoke.query(runtimeType, options);
var map = {};
res.forEach((r) => map[smoke.symbolToName(r.name)] = smoke.read(this, r.name));
return map;
}
}
Currently, there is no support to get generic type information (eg. to support List) in Smoke; however I've raised a case about this here:
https://code.google.com/p/dart/issues/detail?id=20584
Until this issue is implemented, a "good" implementation of what you want is not really feasible; but I'm hopeful it'll be implemented soon; because doing something as basic as JSON serialisation kinda hinges on it!
I haven't had the time to complete it yet but dartson is currently working using mirrors. However a better solution would be using a transformer when compiling to JavaScript. https://pub.dartlang.org/packages/dartson
Related
I'm trying to convert one of my functions that takes something from Firebase and converts it into a list of models. I noticed I keep using this logic so maybe the best way to refactor it was to use generics.
My original code:
Future<List<Guideline>> getList ({DatabaseReference query}) async {
DataSnapshot snap = await query.once();
Map<dynamic, dynamic> map = snap.value;
_myList = new List<MyModel>();
map.forEach((key, value) {
_myList.add(MyModel.fromJson(key: key, snapshot: value));
});
return _myList;
}
I tried to use this similar logic to create a generic version of it but I got an error while trying to make it work and I couldn't find a similar problem while searching here so I decided to ask out.
Future<List<T>> getList<T>({DatabaseReference query}) async {
DataSnapshot snap = await query.once();
//dynamic generates an error: The name 'dynamic' isn't a type so it can't be used as a type argument.
Map<dynamic, dynamic> json = snap.value;
return list;
}
If I hadn't gotten the error above I would continue my code as how I did with my first function except that fromJson would be a callback function so I could pass its implementation.
I want to get a current user location to update nearby stores based on latitude/longitude inside the url.
but I can't figure out how to interact data between two different class.
I want to make it work something like 'AppConfig.latitude = _position.latitude;'. I tried with several methods including inherited widget that I found on stackoverflow and youtube, but still don't work. It's definitely that I'm missing something.
when I use a bloc, I have no clue how to update data inside 'class AppConfig' with bloc. Can it be done simply using SetState? I spent the whole day yesterday Googling for this problem. please guide me to right approach
class _CurrentLocationState extends State<CurrentLocation> {
Position _position;
Future<void> _initPlatformState() async {
Position position;
try {
final Geolocator geolocator = Geolocator()
...
setState(() {
_position = position;
// print(${_position.latitude})
// 35.9341...
// print(${_position.longitude})
// -117.0912...
<*I want to make it work something like this*>
AppConfig.latitude = _position.latitude;
AppConfig.longitude = _position.longitude;
<*this is how I tried with bloc*>
latLongBloc.getUserLocation(LatLng(position.latitude, position.longitude));
});
<* latitude/longitude need to be updated with a current user location *>
abstract class AppConfig {
static const double latitude = 0;
static const double longitude = 0;
static const List<String> storeName = ['starbucks'];
}
<* I need to use AppConfig.latitude for url in Repository class*>
class Repository {
...
Future<List<Business>> getBusinesses() async {
String webAddress =
"https://api.yelp.com/v3/businesses/search?latitude=${AppConfig.latitude}&longitude=${AppConfig.longitude}&term=${AppConfig.storeName}";
...
}
this is my bloc.dart file
class LatLongBloc {
StreamController _getUserLocationStreamController = StreamController<LatLng>();
Stream get getUserLocationStream => _getUserLocationStreamController.stream;
dispose(){
_getUserLocationStreamController.close();
}
getUserLocation(LatLng userLatLong) {
_getUserLocationStreamController.sink.add(userLatLong);
}
}
final latLongBloc = LatLongBloc();
You want to share state between classes/widgets, right? There are also other state management patterns like ScopedModel or Redux. Each pattern has its pros and cons, but you don't have to use BLoC if you don't understand it.
I would recommend to use ScopedModel because it's quite easy to understand in my opinion. Your data/state is in a central place and can be accessed by using ScopedModel. If you don't like to use this approach then try Redux or other patterns :)
Hope it helped you :D
Yours Glup3
Currently trying to understand 'analyzer' package, because I need to analyze and edit .dart file from another file (maybe it's a terrible idea).
I think I understand how to go deep into the childEntities tree.
But can't understand how to search in it.
I mean, theoretically I can write a recursive search that will find me a class named "FindABetterSolution". But is there a built in method for that?
What I'm trying to do:
var file = parseDartFile("test.dart");
file.childEntities.forEach((SyntacticEntity entity) {
if(entity is AstNode) {
//then it has its own child nodes which can be AstNode-s or Tokens.
} else if(entity is Token) {
Token token = entity;
print("${token.lexeme} ${token.type} ${token.runtimeType} ${token.keyword}");
//this will output "class KEYWORD KeywordToken CLASS" for "class" in "class MyClass {"
}
});
//I need a way to find certain functions/classes/variables/methods e.t.c.
var myClassNode = file.searchClass("MyClass", abstract: false);
var myMethod = myClassNode.searchMethod("myMethod", static: true);
var globalFunction = file.searchFunction("myFunc", returns: "bool");
UPD: Ok, I think I found a way to search and replace nodes. But how to insert new node after/before another?
You can call file.accept() or file.visitChildren() with a RecursiveAstVisitor that implements visitClassDeclaration, visitMethodDeclaration, or visitFunctionDeclaration.
Trying to read simple Parquet file into my Google DataFlow Pipeline
using the following code
Read.Bounded<KV<Void, GenericData>> results = HadoopFileSource.readFrom("/home/avi/tmp/db_demo/simple.parquet", AvroParquetInputFormat.class, Void.class, GenericData.class);
trigger always the following exception when running the pipeline
IllegalStateException: Cannot find coder for class org.apache.avro.generic.GenericData
seems like this method inside HadoopFileSource can't handle this type of class as for coder
private <T> Coder<T> getDefaultCoder(Class<T> c) {
if (Writable.class.isAssignableFrom(c)) {
Class<? extends Writable> writableClass = (Class<? extends Writable>) c;
return (Coder<T>) WritableCoder.of(writableClass);
} else if (Void.class.equals(c)) {
return (Coder<T>) VoidCoder.of();
}
// TODO: how to use registered coders here?
throw new IllegalStateException("Cannot find coder for " + c);
}
any help will be appreciated
Avi
This is a problem with the design of HadoopFileSource. I would suggest moving to apache-beam or (scio) which is the apache "version" (and the "future") of dataflow sdk. Once you are on the beam, you can:
This is gonna be scala (but you can easily translate to java):
HDFSFileSource.from(
input,
classOf[AvroParquetInputFormat[AvroSchemaClass]],
AvroCoder.of(classOf[AvroSchemaClass]),
new SerializableFunction[KV[Void, AvroSchemaClass], AvroSchemaClass]() {
override def apply(e: KV[Void, AvroSchemaClass]): AvroSchemaClass =
CoderUtils.clone(AvroCoder.of(classOf[AvroSchemaClass]), e.getValue)
}
)
which is a alternative version of from that accepts coder.
I like the await for construct in Dart.
How can I implement something similar with a regular for loop?
Something like
// beware! fictional code.
var element = stream.next();
for(; stream.isEndReached(); element = stream.next()) {
// use element here
}
// or probably it will be like this, right?
var element = await stream.next();
for(; await stream.isEndReached(); element = await stream.next()) {
// use element here
}
But I can't figure out what functions to use instead of next() and isEndReached() here. If you could give me a full example that acts exactly like async for, that would be great.
Edit: Here is the actual reason that I asked for this: I want to do something like this:
if (!stream.isEndReached()) {
var a = await stream.next();
// use a
}
if (!stream.isEndReached()) {
var b = await stream.next();
// use b
}
// have an arbitrary number of these
I need to consume items one by one like this. This is why I'm asking what my made up .next() and .isEndReached() methods map to which actual methods in the stream class.
The async package contains a StreamQueue class that might do what you want.
See also this great article http://news.dartlang.org/2016/04/unboxing-packages-async-part-3.html
StreamQueue provides a pull-based API for streams.
A code snipped from the article mentioned above
void main() async {
var queue = new StreamQueue(new Stream.fromIterable([1, 2, 3]));
var first = queue.next;
var second = queue.next;
var third = queue.next;
print(await Future.wait([first, second, third])); // => [1, 2, 3]
}
update
WebStorm (uses a feature of the dartanalyzer) doesn't provide quick fixes for imports when nothing was yet imported from that package. It doesn't read packages if they are not refered to in your source code. As mentioned in my answer StreamQueue is from the async package. import 'package:async/async.dart'; is usually enough (it's a convention to name the main entrypoint file (async.dart) of a package the same as the package) and all exported identifiers become available in your library. Otherwise you can search the source of your project and WebStorm will also search dependencies and show what library contains the StreamQueue class. Then you can import this file.