Dart - Call class constructor by class name - dart

I have the following code:-
switch (code) {
case "BleDisconnectedException":
throw BleDisconnectedException(msg, details);
case "BleGattException":
throw BleGattException(msg, details);
case "BleGattCallbackTimeoutException":
throw BleGattCallbackTimeoutException(msg, details);
case "BleCharacteristicNotFoundException":
throw BleCharacteristicNotFoundException(msg, details);
case "BleGattCannotStartException":
throw BleGattCannotStartException(msg, details);
default:
throw e;
}
How do I make dart automatically do the switch-case, i.e. call the class constructor by its name, provided as a String?

As I know in current Dart is not possible, but you can do something like this:
var factories = Map<String, Object Function()>{'Foo', () => new Foo(), 'Bar', () => new Bar()};
Object instance = factories['Foo']();

Related

Why is there no spy functionality in Mockito Dart?

The following code is a simplified example from my code. I have class A which is dependent on class B. I want to test class A, so I mock class B. Then I'm writing a test for a method of class A and inside of that test I write a stub for whenever a method from my mocked class B is called:
fetchData() async {
try {
await b.getData();
} on DioError catch (e) {
switch (e.response!.statusCode) {
case 401:
logout();
throw UnauthorizedException();
default:
throw UnspecifiedDioException(error: e);
}
}
Test written for fetchData() method:
test('check if fetchData calls logout when 401 is returned', () {
when(mockB.getData())
.thenAnswer((_) async =>
throw DioError(
requestOptions: RequestOptions(path: ""),
response: Response(requestOptions: RequestOptions(path: ""), statusCode: 401)));
verify(a.logout()); // doesn't work because A isn't mocked
});
I've read that you can do this very easily with spies but to my surprise spies are available for every language which uses mockito except for dart. It's apparently deprecated but then again how can something be deprecated if there isn't even a newer version to replace it with.
I'd really appreciate it if someone could tell me if there is a convenient workaround for what I'm trying to achieve. Thanks in advance.
Edit: I've changed the question because the former one wasn't making much sense. I just wanna know if there is something like spies in dart or not.
Using mocktail..
You should stub your logout invocation's dependency as well.
class A {
A({required this.api, required this.auth});
// to be mocked
final Api api;
final Auth auth;
Future<void> fetchData() async {
try {
await api.getData();
} catch (e) {
auth.logout();
}
}
}
class Auth {
Future<void> logout() => Future(() {});
}
class Api {
Future<void> getData() => Future(() {});
}
And your test
class MockApi extends Mock implements Api {}
class MockAuth extends Mock implements Auth {}
void main() {
// create mock objects
final mockApi = MockApi();
final mockAuth = MockAuth();
test('when [Api.getData] throws, [Auth.logout] is called', () async {
// create an instance of "A" and use your mock objects
final a = A(api: mockApi, auth: mockAuth);
// use "thenThrow" to throw
when(() => mockApi.getData()).thenThrow('anything');
// use "thenAnswer" for future-returning methods
when(() => mockAuth.logout()).thenAnswer((_) => Future.value(null));
// call the method to "start" the test
await a.fetchData();
// verify logout was called
verify(mockAuth.logout).called(1); // passes
});
}

how to use setMethodCallHandler [duplicate]

I am writing a native plugin that, in some cases, has to call functions in the Flutter portion of the app, written in Dart.
How it's achieved, is explained here:
https://flutter.io/platform-channels/
Furthermore, an example of invoking a method from the native/platform part towards the Dart/non-native is here:
https://github.com/flutter/plugins/tree/master/packages/quick_actions
Now, this example is really nice in case the platform only needs to invoke a method, i.e. that call returns nothing/void, but in case it needs to invoke a function, i.e. needs a return value from the non-native/Dart part, I could not have found an example or documentation on the internet. I believe it can be implemented though, because in the native Java part, there is a method:
public void invokeMethod(String method, Object arguments, MethodChannel.Result callback)
So, there is a callback object that could have a return value from the non-native part - or, I am mistaken here, and there is currently no way of returning a value from the non-native Dart portion of the app?
The signature is void setMethodCallHandler(Future<dynamic> handler(MethodCall call)), so we need to provide a function at the Dart end that returns Future<dynamic>, for example _channel.setMethodCallHandler(myUtilsHandler);
Then implement the handler. This one handles two methods foo and bar returning respectively String and double.
Future<dynamic> myUtilsHandler(MethodCall methodCall) async {
switch (methodCall.method) {
case 'foo':
return 'some string';
case 'bar':
return 123.0;
default:
throw MissingPluginException('notImplemented');
}
}
At the Java end the return value is passed to the success method of the Result callback.
channel.invokeMethod("foo", arguments, new Result() {
#Override
public void success(Object o) {
// this will be called with o = "some string"
}
#Override
public void error(String s, String s1, Object o) {}
#Override
public void notImplemented() {}
});
In Swift, the return value is an Any? passed to the result closure. (Not implemented is signaled by the any parameter being the const NSObject value FlutterMethodNotImplemented.)
channel.invokeMethod("foo", arguments: args, result: {(r:Any?) -> () in
// this will be called with r = "some string" (or FlutterMethodNotImplemented)
})

flutter: Need either specifiedType or discriminator field

everyone,i'm confuse on this problem few days,any one can help me?
when i using flutter redux,i got this problems.
Deserializing '[data, {accounts: [], version: 5.4}, null, null]' to 'LoginResponse' failed due to: Invalid
argument(s): Unknown type on deserialization. Need either specifiedType or discriminator field.
here is LoginResponse Deserialize method:
LoginResponse deserialize(Serializers serializers, Iterable serialized,
{FullType specifiedType: FullType.unspecified}) {
final result = new LoginResponseBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'data':
result.data.replace(serializers.deserialize(value, specifiedType: const FullType(LoginResponseData)) as LoginResponseData);
break;
case 'error':
result.error.replace(serializers.deserialize(value,
specifiedType: const FullType(ErrorMessage)) as ErrorMessage);
break;
}
}
return result.build();
}
abstract class LoginResponseData implements Built<LoginResponseData, LoginResponseDataBuilder> {
factory LoginResponseData([void updates(LoginResponseDataBuilder b)]) = _$LoginResponseData;
LoginResponseData._();
BuiltList<CompanyEntity> get accounts;
String get version;
static Serializer<LoginResponseData> get serializer => _$loginResponseDataSerializer;
}
What really hurts me is that the debugging mode of android studio seems some problem? some variable always shows "Collecting data... it's hard to me to fix this problem cause i can't got some key variable's value.just like:specifiedType.
There is some screenshot when debuging.
i'm great appreciate if any one could give me some tips or answers!!! thanks!!!!

Switching on class type in Dart

I'm looking to write a function in a Dart superclass that takes different actions depending on which subclass is actually using it. Something like this:
class Foo {
Foo getAnother(Foo foo) {
var fooType = //some code here to extract fooType from foo;
switch (fooType) {
case //something about bar here:
return new Bar();
case //something about baz here:
return new Baz();
}
}
}
class Bar extends Foo {}
class Baz extends Foo {}
where the idea is that I have some object and want to get a new object of the same (sub)class.
The main question is what type should fooType be? My first thought was Symbol, which leads to easy case statements like case #Bar:, but I don't know how I would populate fooType with a Symbol. The only options I can think of are to do something like Symbol fooType = new Symbol(foo.runtimeType.toString()); but my understanding is that runtimeType.toString() won't work when converted to javascript. You could get around that by using Mirrors, but this is meant to be a lightweight library, so those aren't on the table. Object.runtimeType returns something of the Type class, but I have no idea how to create instances of Type I could use for the case statements. Maybe I'm missing some other piece of the Dart library that is better suited for this?
You can use the runtimeType in switch :
class Foo {
Foo getAnother(Foo foo) {
switch (foo.runtimeType) {
case Bar:
return new Bar();
case Baz:
return new Baz();
}
return null;
}
}
In the case statements the class name is used directly (AKA class literal). This gives a Type object corresponding to the class mentioned. Thus foo.runtimeType can be compared with the specified type.
Note that you can not use generics for now in class literals. Thus, case List<int>: is not allowed.

Serializing Templated Container Types

I've been struggling with this for a few hours. I'm hoping someone could assist me in understanding where the problem is.
Spray-JSON has a test case here
https://github.com/spray/spray-json/blob/master/src/test/scala/spray/json/AdditionalFormatsSpec.scala
case class Container[A](inner: Option[A])
object ReaderProtocol extends DefaultJsonProtocol {
implicit def containerReader[T :JsonFormat] =
new JsonReader[Container[T]] {
def read(value: JsValue) = value match {
case JsObject(fields) if fields.contains("content") =>
Container(Some(jsonReader[T].read(fields("content"))))
case _ => deserializationError("Unexpected format: " + value.toString)
}
}
}
}
that shows how you can serialize a container type. I've attempted to adapt this to my situaiton.
case class ListResponseObject[A](url : String, data : Seq[A])
object ListResponseWriterProtocol extends DefaultJsonProtocol {
implicit def containerWriter[T: JsonFormat] = lift {
new JsonWriter[ListResponseObject[T]] {
def write(obj: ListResponseObject[T]) = JsObject(
"object" -> JsString("object"),
"url" -> JsString(obj.url),
"count" -> JsNumber(obj.data.length),
"data" -> obj.data.toJson
)
}
}
}
Unfortunately, when I attempt to use this here
{ ctx : RequestContext =>
ask(cardTokenActor, ListMessage(account))
.mapTo[ListResponse]
.onComplete {
case Success(ListResponse(list: ListResponseObject[CardToken])) =>
ctx.complete(list)
case Success(_) => ctx.complete(NotFound)
case Failure(e: Throwable ) => logAndFail(ctx, e)
}
}
I run into this error
161: could not find implicit value for evidence parameter of type
spray.httpx.marshalling.Marshaller[com.smoothpay.services.ListResponseObject
[com.smoothpay.services.cardtoken.entity.CardToken]]
[error] case Success(ListResponse(list: ListResponseObject[CardToken])) =>
ctx.complete(list)
I've also got all the right imports in place.
import spray.httpx.SprayJsonSupport._
import spray.httpx.marshalling._
import spray.http._
import spray.json._
I'm curious where the problem could be. Appreciate the help in advance.
You can make it a bit easier, i think that should help:
case class ListResponseObject[A](url : String, data : Seq[A])
object ListResponseWriterProtocol extends DefaultJsonProtocol {
implicit def containerWriter[A: JsonFormat] = jsonFormat2(ListResponseObject.apply[A])
}

Resources