New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to deserialize collections without type information #438
Comments
OK, I figured out the main problem. My generated serializers collection did not include the following: ..addBuilderFactory(const FullType(BuiltList, const [const FullType(UserDto)]), () => new ListBuilder<UserDto>()) I guess this is because my DTOs don't actually contain I also need to figure out how to dynamically determine a |
Even though it's not as clean a design for my APIs, I'm leaning heavily towards using |
What about
? |
I seem to be going around in circles with this. In the end, this is the best I've been able to come up with that seemingly solves the problem: /// Serializes [object] to JSON.
String serialize(Object object, FullType fullType) {
// TODO: it might be that we *do* want to allow this, but I have no use case as yet.
assert(object != null, "Unable to serialize null.");
assert(fullType != null);
return json.encode(serializers.serialize(object, specifiedType: fullType));
}
/// Deserializes [json] into a [T].
T deserialize<T>(String json, FullType fullType) {
assert(json != null);
assert(fullType != null);
final result = serializers.deserialize(convert.json.decode(json), specifiedType: fullType);
if (result is T) {
return result;
} else {
final error = "Result of deserialization is of type ${result?.runtimeType}, not the expected type $T.";
throw new Exception(error);
}
} I had really hoped that the Are there any suggestions on how this could be improved? |
I think this is the whole purpose why |
Yeah, that's the same conclusion I came to - guess I just hoped maybe I was wrong. Oh well, I think passing in I will leave this open for a couple of days in case there is any further feedback. Thanks! |
Sure, @davidmorgan will be able to provide more fundamental feedback for sure |
Hmm, in your code snippet here what class are the Generally, Dart has limited support for runtime manipulation of types, unless you're in the VM. This is so that dart2js/flutter can throw away most of the type information; it forces you to use codegen to do some things. |
@davidmorgan yeah, sorry - I forgot some context. I'm writing a mixin that I can use from any class that wants to integrate with back-end APIs (I'm using a vertical architecture so the API integration for each feature sits in a file within each feature's folder). So the full code is: /// A mixin that provides JSON (de)serialization support.
abstract class SerializationMixin {
/// Serializes [object] to JSON.
///
/// [fullType] must fully describe the type being serialized. Due to limitations in Dart's
/// type system, it cannot be inferred from a generic type parameter `T`.
///
/// More information at https://github.com/google/built_value.dart/issues/438.
String serialize(Object object, FullType fullType) {
// TODO: it might be that we *do* want to allow this, but I have no use case as yet.
assert(object != null, "Unable to serialize null.");
assert(fullType != null);
return json.encode(serializers.serialize(object, specifiedType: fullType));
}
/// Deserializes [json] into a [T].
///
/// [fullType] must fully describe the type being serialized. Due to limitations in Dart's
/// type system, it cannot be inferred from the generic type parameter [T].
///
/// More information at https://github.com/google/built_value.dart/issues/438.
T deserialize<T>(String json, FullType fullType) {
assert(json != null);
assert(fullType != null);
final result = serializers.deserialize(convert.json.decode(json), specifiedType: fullType);
if (result is T) {
return result;
} else {
final error = "Result of deserialization is of type ${result?.runtimeType}, not the expected type $T.";
throw new Exception(error);
}
}
} Then a particular API integration would look something like: class Login extends TheApiInterface with SerializationMixin, HttpMixin {
@override
Future<UserDto> authenticate(String name, String password) async {
final body = (new AuthenticateRequestDtoBuilder()
..name = name
..password = password)
.build();
final response = await postAndVerifySuccess("/authenticate", body: body);
return deserialize<UserDto>(response.body, const FullType(UserDto));
}
} I was hoping that final invocation could be simplified to: return deserialize<UserDto>(response.body); But I just couldn't find a way to make it work without "doubling up" on the type information. |
I see. There is one feature that may help you, You would write e.g.
this works by taking both |
@dave26199 thanks, but per this comment above I wasn't able to figure out how to use serializers in scenarios where I wanted to deserialize a T deserialize<T>(String json) {
assert(json != null);
// how would I do this?
final serializer = ???;
return serializers.deserializeWith(serializer, json) as T;
} Or are you suggesting to do away with the generic helper altogether? |
Hmm, you're right, that doesn't quite work right now. I was thinking you might be able to create a ...which would effectively provide a way to bundle the type literal What we actually need is a new class,
then we can use this variable to do what you want: we can pass it in and both 1) extract T, 2) get the FullType so we can find the serializer. It should be possible to try creating such a class in your code; you'd then have a library of constants and pick the right one when you need it. Then you would have
How does that sound? |
I'm using
built_value
for JSON serialization in the context of integrating with an API. I'm struggling a bit becausebuilt_value
seems to require type information in the incoming JSON stream, which it won't get from the API. I think I've solved this for cases where I'm deserializing a DTO, but I've hit a snag with respect to APIs that returns collections.For example, the API might return this JSON:
And I need to parse that into a
BuiltList<UserDto>
(whereUserDto
is just a built value withid
andname
).Now I thought the following would suffice to parse this:
However, this gives me:
What am I doing wrong here?
The text was updated successfully, but these errors were encountered: