How does Orika decide when to use converter - mapping

I am trying to understand when does Orika use converters to do the mapping versus direct casting.
I have the following mapping:
Class A {
Map<String, Object> props;
}
Class B {
String bStr;
int bInt;
}
My mapping is defined as props['aStr'] => bStr and props['aInt'] => bInt
When I look at the generated code, I see that for the String case, it uses a converter and calls its convert method for the transformation:
destination.setBStr("" + ((ma.glasnost.orika.Converter)usedConverters[0]).convert(
((java.lang.Object) ((java.util.Map) source.getProps().get("aStr"),
(ma.glasnost.orika.metadata.Type) usedTypes[0]))
But, for the integer case it directly casts it like this:
destination.setBInt((java.lang.Integer)(java.lang.Object) ((java.util.Map)
source.getProps().get("aInt")))
The above line of code ends up giving class cast exception.
For fixing this issue, I was thinking along the lines of using a custom converter but if the above line of code doesn't use the converter then that wont work.
Of course, I can always do this is in my custom mapper but just trying to understand how the code is generated for type conversion.
Thanks!!

In Orika there is two stages: config-time and runtime, as optimization Orika resolve all used converter in the config-time and cache them into each generated mapper so it will be accessible directly O(1) but in the config time it will try to find in a list O(n) of registered converters which one "canConvert" between two given types, canConvert is a method in Converter interface .
So this solution offer the best of the two worlds:
A very flexible way to register a converter with arbitrary conditions
An efficient resolution and conversion operation in the runtime.
Orika by default, leverage the existence of .toString in every object to offer implicit coercion to String for every Object. The problem here is that there is no Converter from Object to Integer.
Maybe this can be an issue of error reporting. Ideally Orika should report that an Object have to be converted to Integer and there is no appropriate converter registered.

Related

The argument type 'ListOf5' can't be assigned to the parameter type 'ListOf5'

I need to implement an abstract class function, which own a an specific data type. But I need inside my logic layer to make the attribute which is going to be passed as a dynamic data type. But when i Pass it to the function, i am sure that its data type will be as needed. So, i type (product.value.pickedImages) as ListOf5) . But it does an Exception.
The Abstract Class Code Is:
Future<Either<FireStoreServerFailures, List<String>>> uploadProductImages(
{required ListOf5<File> images});
The Implementation Code Is:
Future<Option<List<String>>> _uploadImagesToFirestorage() async {
return await productRepo
.uploadProductImages(
images: (product.value.pickedImages) as ListOf5<File>) // Exception
}
The Exception Is:
The argument type 'ListOf5 < dynamic>' can't be assigned to the
parameter type 'ListOf5 < File>'.
You are trying to cast the List from List<dynamic> to List<String>.
Instead, you should cast each item, using something like this:
void main() {
List<dynamic> a = ['qwerty'];
print(List<String>.from(a));
}
Not sure about the implementation of this ListOf5 though...
The cast (product.value.pickedImages) as ListOf5<File> fails.
It fails because product.value.pickedImages is-not-a ListOf5<File>, but instead of ListOf5<dynamic> (which may or may not currently contain only File objects, but that's not what's being checked).
Unlike a language like Java, Dart retains the type arguments at run-time(it doesn't do "erasure"), so a ListOf5<dynamic> which contains only File objects is really different from a ListOf5<File> at run-time.
You need to convert the ListOf5<dynamic> to a ListOf5<File>.
How to do that depends on the type ListOf5, which I don't know.
For a normal List, the two most common options are:
(product.value.pickedImages).cast<File>(). Wraps the existing list and checks on each read that you really do read a File. It throws if you ever read a non-File from the original list. Perfectly fine if you'll only read the list once.
List<File>.of(product.value.pickedImages). Creates a new List<File> containing the values of product.value.pickedImages, and throws if any of the values are not File objects. Requires more memory (because it copies the list), but fails early in case there is a problem, and for small lists, the overhead is unlikely to be significant. If you read the resulting list many times, it'll probably be more efficient overall.
If the ListOf5 class provides similar options, you can use those. If not, you might have to build a new ListOf5 manually, casting each element of the existing ListOf5<dynamic> yourself.
(If the ListOf5 class is your own, you can choose to add such functionality to the class).

Better way to assign a value with nullable field in dart

Is there a better way to do this?
Assignment(
dueAt: json['due_at'] == null ?
null :
DateTime.parse(json['due_at']).toLocal()
)
The attribute "dueAt" in Assignment class can be null and i need to parse the string of json['due_at'] to a DateTime, but json['due_at'] can be null too.
Is not really a problem right now but seems noisy and repetitive.
First and foremost, it looks like you're writing JSON serialization code by hand. Your life will be much easier and less bug-prone if you let a library do this instead. json_serializable is very simple and powerful and 100% worth looking into.
However, this pattern is still common outside of json code.
You could also consider writing an extension method for Object? that behaves like the Kotlin standard library's let function (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/let.html)
You can then use Dart's ?. syntax to handle the rest of the logic:
// extension on T rather than Object? to maintain type information
extension Example<T> on T {
R let<R>(R Function(T) function) => function(this);
}
This just applies a given function to this, which isn't incredibly useful on it's own, but allows the use of ?.:
final DateTime? dueAt = json['due_at']?.let(DateTime.parse);
If json['due_at'] evaluates to null, the ?. operator short-circuits, and dueAt is set to null. Otherwise, it evaluates to DateTime.parse(json['due_at']).
Or, you could just use package:kt_dart which ports much of the Kotlin standard library to Dart
In this particular case you may want to use tryParse instead of parse. If dueAt is of type DateTime? you can simply call:
Assignment( dueAt: DateTime.tryParse(json['due_at'])?.toLocal() );
Be aware though that tryParse will return null for any invalid date string (be it null or an improperly formatted string). This may or may not be desired behavior depending on your intended use.

Why is Dart's Datetime.parse not a factory constructor?

Dart's Datetime class has a number of named constructors, but DateTime.parse() is not one of them. Instead, DateTime.parse() is a static method which returns a DateTime. To me, it makes sense as a constructor (since you are generating a new DateTime object in a manner not too different from the Datetime.utc() constructor).
Theories I've come up with are to mirror the fact that int.parse is not a constructor or to allow easier chaining (you don't need to use the cascade operator with a static method). But maybe there is another reason that I'm not thinking of. Does anyone know why they didn't make it a named constructor?
More explanation for the same change for Uri.parse: http://permalink.gmane.org/gmane.comp.lang.dart.general/17081
"parse" is special. The question is: do you see parsing as an
operation that does something and ends up giving you the result, or do
you see the string as data to construct a new element. If you see it
as the earlier, then "parse" should be a static function. If you see
the string as the data, then it should be a named constructor.
And then, of course, there is consistency.

How do Grails dynamic finders handle types?

I'm a bit confused about what is happening when I give a Grails dynamic finder the wrong type.
For instance, if I have class Foo
class Foo {
//long id (implicit id is a long)
Long barValue
}
And I do, Foo.findByIdAndBarValue('1', '2'), I get a result, but I am confused about what is going on here with the string values.
Is it passing these string values directly to the db (potentially ignoring valuable indices due to type mismatch) or is Grails automatically converting the types?
When passing parameters to the dynamic finders on Grails domain classes the parameters are dynamically typed. This allows for automatic type conversion, by Groovy.
In your example, Groovy is seeing that the barValue is of type Long and is casting the String value to a Long.
JN3015-Types explains this behavior of Groovy a bit further with some examples.

IEnumerable not accepting my class as a type?

I'm trying to cast a dynamic set of values so that I can use a lambda expression to query them, but I keep getting errors when casting the collection as IEnumerable:
(IEnumerable<MyClass>ViewBag.MyClassList)
causes the errors
Using the generic type System.Collections.Generic.IEnumerable<T> requires 1 type arguments
and
MyClass is a 'type', which is not valid in the given context
This literally makes zero sense. IEnumerable wants a type, but using a type is not valid in the given context.
Halp?
Brackets should do the trick:
((IEnumerable<MyClass>) ViewBag.MyClassList)
Not much information there for context.
ViewBag.MyClassList as IEnumerable<MyClass>
Might be an extension method or two too
ViewBag.MyClassList.ConvertAll<MyClass>()
ViewBag.MyClassList.ToList<MyClass>()
but other than that, Jeroen has the "CAST" approach and parenthesis usage

Resources