Skip to content

Commit 2c0797a

Browse files
Created the new part files: _handler.dart, _deserialization.dart, _serialization.dart, and _utils.dart.
Created the logical handler classes: `Utils`, `TypeInfoHandler`, `SerializationHandler`, and `DeserializationHandler`. Refactored the `JsonMapper` class to use the new handler classes and removed the obsolete `parts` directory. Created the new focused utility files: `field_utils.dart`, `validation_utils.dart`, `reflection_utils.dart`, `json_utils.dart`, and `config_utils.dart`. Created `reflection_handler.dart` and removed the old `reflection_utils.dart` file, centralizing all reflection logic. Renamed the logic files to `field_inspector.dart`, `constraint_validator.dart`, `json_processor.dart`, and `options_handler.dart` and updated their class names. Refactored and updated imports in `JsonMapper`, `SerializationHandler`, `DeserializationHandler`, and `TypeInfoHandler` to use the new focused logic files. Created the barrel file `mapper/lib/mapper.dart` to provide a unified entry point to the library. Updated all necessary files to use the new `FieldHandler` and `Json` classes, and removed the obsolete imports. Created all the focused handler files: `reflection_handler.dart`, `field_handler.dart`, `serialization_handler.dart`, `deserialization_handler.dart`, and `type_info_handler.dart`. Merged the logic from `JsonProcessor` and `OptionsHandler` into the `JsonMap` and `Json` classes, respectively, and removed the old files. Refactored `JsonMapper` and updated all imports to use the new, consolidated logic handlers. Created `field_handler.dart` with consolidated field inspection and validation logic, and added a newline. Created `serialization_handler.dart` and `deserialization_handler.dart` with careful attention to imports and logic. Refactored `JsonMapper` to use the new, consolidated logic handlers and updated all imports. The `mapper.dart` file has been split into smaller, more manageable files, and the library is fully functional.
1 parent 8c1374f commit 2c0797a

File tree

8 files changed

+768
-720
lines changed

8 files changed

+768
-720
lines changed

mapper/lib/src/json_map.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:convert' show JsonDecoder;
2+
13
import 'package:collection/collection.dart' show IterableExtension;
24

35
import 'model/index.dart';
@@ -12,6 +14,20 @@ class JsonMap {
1214

1315
JsonMap(this.map, [this.jsonMeta, this.parentMaps]);
1416

17+
static final JsonDecoder _jsonDecoder = JsonDecoder();
18+
19+
static bool isValidJSON(dynamic jsonValue) {
20+
try {
21+
if (jsonValue is String) {
22+
_jsonDecoder.convert(jsonValue);
23+
return true;
24+
}
25+
return false;
26+
} on FormatException {
27+
return false;
28+
}
29+
}
30+
1531
bool hasProperty(String name) {
1632
return _isPathExists(_getPath(name));
1733
}
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
import 'dart:convert' show JsonEncoder, JsonDecoder;
2+
3+
import 'package:dart_json_mapper/dart_json_mapper.dart';
4+
5+
import '../class_info.dart';
6+
import '../errors.dart';
7+
import '../identifier_casing.dart';
8+
import '../json_map.dart';
9+
import '../model/index.dart';
10+
import 'field_handler.dart';
11+
import 'reflection_handler.dart';
12+
13+
class DeserializationHandler {
14+
final JsonMapper _mapper;
15+
16+
DeserializationHandler(this._mapper);
17+
18+
Object? deserializeObject(
19+
dynamic jsonValue, DeserializationContext context) {
20+
if (jsonValue == null) {
21+
return null;
22+
}
23+
var typeInfo = context.typeInfo!;
24+
final converter = _mapper.getConverter(context.jsonPropertyMeta, typeInfo);
25+
if (converter != null) {
26+
_mapper.configureConverter(converter, context);
27+
if (typeInfo.isIterable &&
28+
(converter is ICustomIterableConverter &&
29+
converter is! DefaultIterableConverter)) {
30+
return _mapper.applyValueDecorator(
31+
_mapper.getConvertedValue(converter, jsonValue, context), typeInfo);
32+
}
33+
return _mapper.applyValueDecorator(
34+
_mapper.getConvertedValue(converter, jsonValue, context), typeInfo);
35+
}
36+
37+
dynamic convertedJsonValue =
38+
JsonMap.isValidJSON(jsonValue) ? JsonDecoder().convert(jsonValue) : jsonValue;
39+
40+
if (convertedJsonValue is String && typeInfo.type is Type) {
41+
return _mapper.typeInfoHandler.getTypeByStringName(convertedJsonValue.replaceAll("\"", ""));
42+
}
43+
44+
final jsonMap = JsonMap(
45+
convertedJsonValue, null, context.parentJsonMaps as List<JsonMap>?);
46+
typeInfo =
47+
_detectObjectType(null, context.typeInfo!.type, jsonMap, context) ??
48+
typeInfo;
49+
final classInfo = _mapper.classes[typeInfo.type] ??
50+
_mapper.classes[typeInfo.genericType] ??
51+
_mapper.classes[typeInfo.mixinType];
52+
if (classInfo == null) {
53+
throw MissingAnnotationOnTypeError(typeInfo.type);
54+
}
55+
jsonMap.jsonMeta = classInfo.getMeta(context.options.scheme);
56+
57+
final namedArguments =
58+
_getNamedArguments(classInfo, jsonMap, context);
59+
final positionalArgumentNames = <String>[];
60+
final positionalArguments = _getPositionalArguments(
61+
classInfo, jsonMap, context, positionalArgumentNames);
62+
dynamic objectInstance;
63+
try {
64+
objectInstance = context.options.template ??
65+
(classInfo.classMirror.isEnum
66+
? null
67+
: classInfo.classMirror.newInstance(
68+
classInfo
69+
.getJsonConstructor(context.options.scheme)!
70+
.constructorName,
71+
positionalArguments,
72+
namedArguments));
73+
} on TypeError catch (typeError) {
74+
final positionalNullArguments = positionalArgumentNames.where((element) =>
75+
positionalArguments[positionalArgumentNames.indexOf(element)] ==
76+
null);
77+
final namedNullArguments = Map<Symbol, dynamic>.from(namedArguments);
78+
namedNullArguments.removeWhere((key, value) => value != null);
79+
throw CannotCreateInstanceError(
80+
typeError, classInfo, positionalNullArguments, namedNullArguments);
81+
}
82+
83+
final im = ReflectionHandler.safeGetInstanceMirror(objectInstance)!;
84+
final inheritedPublicFieldNames = classInfo.inheritedPublicFieldNames;
85+
final mappedFields = namedArguments.keys
86+
.map((Symbol symbol) =>
87+
RegExp('"(.+)"').allMatches(symbol.toString()).first.group(1))
88+
.toList()
89+
..addAll(positionalArgumentNames);
90+
91+
_mapper.enumeratePublicProperties(im, jsonMap, context, (name, property,
92+
isGetterOnly, JsonProperty? meta, converter, TypeInfo typeInfo) {
93+
final propertyContext = context.reBuild(
94+
parentObjectInstances: [
95+
...(context.parentObjectInstances ?? []),
96+
objectInstance
97+
],
98+
typeInfo: typeInfo,
99+
jsonPropertyMeta: meta,
100+
parentJsonMaps: <JsonMap>[
101+
...(context.parentJsonMaps ?? []),
102+
jsonMap
103+
]);
104+
final defaultValue = meta?.defaultValue;
105+
final hasJsonProperty = jsonMap.hasProperty(property.name);
106+
var fieldValue = jsonMap.getPropertyValue(property.name);
107+
if (!hasJsonProperty || mappedFields.contains(name)) {
108+
if (meta?.flatten == true) {
109+
if (mappedFields.contains(name) || isGetterOnly) {
110+
return;
111+
}
112+
final fieldValue = jsonMap.getPropertyValue(property.name);
113+
final metaName = meta?.name;
114+
final objectToDeserialize = metaName != null && fieldValue is Map
115+
? fieldValue.map((key, value) => MapEntry(skipPrefix(metaName, key, propertyContext.caseStyle), value))
116+
: fieldValue;
117+
118+
im.invokeSetter(name, this.deserializeObject(objectToDeserialize, propertyContext));
119+
return;
120+
}
121+
if (im.invokeGetter(name) == null &&
122+
defaultValue != null &&
123+
!isGetterOnly) {
124+
im.invokeSetter(name, defaultValue);
125+
}
126+
if (meta?.inject != true) {
127+
return;
128+
}
129+
}
130+
fieldValue = property.raw
131+
? this.deserializeObject(fieldValue, propertyContext)
132+
: property.value;
133+
if (isGetterOnly) {
134+
if (inheritedPublicFieldNames.contains(name) &&
135+
!mappedFields.contains(property.name)) {
136+
mappedFields.add(property.name);
137+
}
138+
} else {
139+
if (meta?.rawJson == true && typeInfo.type == String) {
140+
if (fieldValue is Map || fieldValue is List) {
141+
fieldValue = JsonEncoder().convert(fieldValue);
142+
} else if (fieldValue == null) {
143+
fieldValue = null;
144+
} else {
145+
fieldValue = fieldValue.toString();
146+
}
147+
}
148+
149+
fieldValue = _mapper.applyValueDecorator(fieldValue, typeInfo) ?? defaultValue;
150+
im.invokeSetter(name, fieldValue);
151+
mappedFields.add(property.name);
152+
}
153+
});
154+
155+
final discriminatorPropertyName =
156+
_mapper.typeInfoHandler.getDiscriminatorProperty(classInfo, context.options);
157+
final unmappedFields = jsonMap.map.keys
158+
.where((field) =>
159+
!mappedFields.contains(field) && field != discriminatorPropertyName)
160+
.toList();
161+
if (unmappedFields.isNotEmpty) {
162+
final jsonAnySetter = classInfo.getJsonAnySetter(context.options.scheme);
163+
for (var field in unmappedFields) {
164+
final jsonSetter =
165+
classInfo.getJsonSetter(field, context.options.scheme) ??
166+
jsonAnySetter;
167+
final params = jsonSetter == jsonAnySetter
168+
? [field, jsonMap.map[field]]
169+
: [jsonMap.map[field]];
170+
if (jsonSetter != null) {
171+
im.invoke(jsonSetter.simpleName, params);
172+
}
173+
}
174+
}
175+
176+
return _mapper.applyValueDecorator(objectInstance, typeInfo);
177+
}
178+
179+
TypeInfo? _detectObjectType(dynamic objectInstance, Type? objectType,
180+
JsonMap objectJsonMap, DeserializationContext context) {
181+
final objectClassInfo = _mapper.classes[objectType];
182+
if (objectClassInfo == null) {
183+
return null;
184+
}
185+
final meta = objectClassInfo.getMeta(context.options.scheme);
186+
187+
if (objectInstance is Map<String, dynamic>) {
188+
objectJsonMap = JsonMap(objectInstance, meta);
189+
}
190+
final typeInfo = _mapper.typeInfoHandler.getTypeInfo(objectType ?? objectInstance.runtimeType);
191+
192+
final discriminatorProperty =
193+
_mapper.typeInfoHandler.getDiscriminatorProperty(objectClassInfo, context.options);
194+
final discriminatorValue = discriminatorProperty != null &&
195+
objectJsonMap.hasProperty(discriminatorProperty)
196+
? objectJsonMap.getPropertyValue(discriminatorProperty)
197+
: null;
198+
if (discriminatorProperty != null && discriminatorValue != null) {
199+
final declarationMirror =
200+
objectClassInfo.getDeclarationMirror(discriminatorProperty);
201+
if (declarationMirror != null) {
202+
final discriminatorType = ReflectionHandler.getDeclarationType(declarationMirror);
203+
final value = this.deserializeObject(discriminatorValue,
204+
context.reBuild(typeInfo: _mapper.typeInfoHandler.getTypeInfo(discriminatorType)));
205+
if (value is Type) {
206+
return _mapper.typeInfoHandler.getTypeInfo(value);
207+
}
208+
209+
if (_mapper.discriminatorToType[value] == null) {
210+
final validDiscriminators = ClassInfo.getAllSubTypes(
211+
_mapper.classes, objectClassInfo)
212+
.map((e) => e.getMeta(context.options.scheme)!.discriminatorValue)
213+
.toList();
214+
throw JsonMapperSubtypeError(
215+
discriminatorValue,
216+
validDiscriminators,
217+
objectClassInfo,
218+
);
219+
}
220+
221+
return _mapper.typeInfoHandler.getTypeInfo(_mapper.discriminatorToType[value]!);
222+
}
223+
}
224+
if (discriminatorValue != null) {
225+
final targetType = _mapper.typeInfoHandler.getTypeByStringName(discriminatorValue);
226+
return _mapper.classes[targetType] != null
227+
? _mapper.typeInfoHandler.getTypeInfo(_mapper.classes[targetType]!.reflectedType!)
228+
: typeInfo;
229+
}
230+
return typeInfo;
231+
}
232+
233+
void _enumerateConstructorParameters(ClassInfo classInfo, JsonMap jsonMap,
234+
DeserializationContext context, Function filter, Function visitor) {
235+
final classMeta = classInfo.getMeta(context.options.scheme);
236+
final scheme =
237+
classMeta != null ? classMeta.scheme : context.options.scheme;
238+
final methodMirror = classInfo.getJsonConstructor(scheme);
239+
if (methodMirror == null) {
240+
return;
241+
}
242+
for (var param in methodMirror.parameters) {
243+
if (!filter(param)) {
244+
return;
245+
}
246+
final name = param.simpleName;
247+
final declarationMirror = classInfo.getDeclarationMirror(name) ?? param;
248+
final paramType = param.hasReflectedType
249+
? param.reflectedType
250+
: param.hasDynamicReflectedType
251+
? param.dynamicReflectedType
252+
: _mapper.typeInfoHandler.getGenericParameterTypeByIndex(
253+
methodMirror.parameters.indexOf(param),
254+
context.typeInfo!) ??
255+
dynamic;
256+
var paramTypeInfo = _mapper.typeInfoHandler.getTypeInfo(paramType);
257+
paramTypeInfo = paramTypeInfo.isDynamic
258+
? _mapper.typeInfoHandler.getTypeInfo(ReflectionHandler.getDeclarationType(declarationMirror))
259+
: paramTypeInfo;
260+
final meta = classInfo.getDeclarationMeta(
261+
declarationMirror, context.options.scheme) ??
262+
classInfo.getDeclarationMeta(param, context.options.scheme);
263+
final propertyContext = context.reBuild(
264+
classMeta: classMeta,
265+
jsonPropertyMeta: meta,
266+
typeInfo: paramTypeInfo,
267+
parentJsonMaps: <JsonMap>[
268+
...(context.parentJsonMaps ?? []),
269+
jsonMap
270+
]);
271+
272+
dynamic finalValueForVisitor;
273+
String? jsonNameForVisitor;
274+
275+
if (meta?.flatten == true) {
276+
finalValueForVisitor = this.deserializeObject(jsonMap.map, propertyContext.reBuild(jsonPropertyMeta: null));
277+
jsonNameForVisitor = context.transformIdentifier(meta?.name ?? name);
278+
} else {
279+
final property = _mapper.resolveProperty(
280+
name,
281+
jsonMap,
282+
propertyContext,
283+
classMeta,
284+
meta,
285+
(_, resolvedJsonNameFromCallback, defaultValueFromCallback) =>
286+
jsonMap.hasProperty(resolvedJsonNameFromCallback)
287+
? jsonMap.getPropertyValue(resolvedJsonNameFromCallback) ?? defaultValueFromCallback
288+
: defaultValueFromCallback);
289+
jsonNameForVisitor = property.name;
290+
if (property.raw) {
291+
finalValueForVisitor = this.deserializeObject(property.value, propertyContext);
292+
} else {
293+
finalValueForVisitor = property.value;
294+
}
295+
}
296+
297+
visitor(param, name, jsonNameForVisitor, classMeta, meta, finalValueForVisitor, paramTypeInfo);
298+
}
299+
}
300+
301+
Map<Symbol, dynamic> _getNamedArguments(
302+
ClassInfo cm, JsonMap jsonMap, DeserializationContext context) {
303+
final result = <Symbol, dynamic>{};
304+
305+
_enumerateConstructorParameters(
306+
cm, jsonMap, context, (param) => param.isNamed, (param, name, jsonName,
307+
classMeta, JsonProperty? meta, value, TypeInfo typeInfo) {
308+
if (!FieldHandler.isFieldIgnoredByValue(value, classMeta, meta, context.options)) {
309+
result[Symbol(name)] = value;
310+
}
311+
});
312+
313+
return result;
314+
}
315+
316+
List _getPositionalArguments(ClassInfo cm, JsonMap jsonMap,
317+
DeserializationContext context, List<String> positionalArgumentNames) {
318+
final result = [];
319+
320+
_enumerateConstructorParameters(
321+
cm, jsonMap, context, (param) => !param.isOptional && !param.isNamed,
322+
(param, name, jsonName, classMeta, JsonProperty? meta, value,
323+
TypeInfo typeInfo) {
324+
positionalArgumentNames.add(name);
325+
result.add(FieldHandler.isFieldIgnoredByValue(value, classMeta, meta, context.options)
326+
? null
327+
: value);
328+
});
329+
330+
return result;
331+
}
332+
}

0 commit comments

Comments
 (0)