Skip to content

Commit 7e3e920

Browse files
refactor: Extract converter and property logic to separate handlers
This commit extracts the converter and property-related logic from `JsonMapper` into new `ConverterHandler` and `PropertyHandler` classes. This improves the separation of concerns and makes the `JsonMapper` class smaller and more focused. The following changes were made: - Created a new `ConverterHandler` class in `mapper/lib/src/logic/converter_handler.dart`. - Moved `getConverter`, `getEnumDescriptor`, `getConvertedValue`, and `configureConverter` methods from `JsonMapper` to `ConverterHandler`. - Moved `converters` and `convertedValuesCache` state from `JsonMapper` to `ConverterHandler`. - Created a new `PropertyHandler` class in `mapper/lib/src/logic/property_handler.dart`. - Moved `enumeratePublicProperties` and `resolveProperty` methods from `JsonMapper` to `PropertyHandler`. - Updated all call sites to use the new handlers. - Removed unused imports from modified files.
1 parent 9d17d8e commit 7e3e920

File tree

5 files changed

+267
-231
lines changed

5 files changed

+267
-231
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import 'package:collection/collection.dart';
2+
import 'package:dart_json_mapper/src/model/index.dart';
3+
4+
import '../mapper.dart';
5+
6+
class ConverterHandler {
7+
final JsonMapper _mapper;
8+
9+
Map<Type, ICustomConverter> converters = {};
10+
final Map<
11+
ICustomConverter?,
12+
Map<ConversionDirection,
13+
Map<DeserializationContext?, Map<dynamic, dynamic>>>>
14+
convertedValuesCache = {};
15+
16+
ConverterHandler(this._mapper);
17+
18+
void clearCache() {
19+
convertedValuesCache.clear();
20+
}
21+
22+
ICustomConverter? getConverter(
23+
JsonProperty? jsonProperty, TypeInfo typeInfo) {
24+
final result = jsonProperty?.converter ??
25+
converters[typeInfo.type!] ??
26+
converters[typeInfo.genericType] ??
27+
(_mapper.enumValues[typeInfo.type!] != null
28+
? converters[Enum]
29+
: null) ??
30+
converters[converters.keys.firstWhereOrNull(
31+
(Type type) => type.toString() == typeInfo.typeName)];
32+
33+
if (result is ICustomEnumConverter) {
34+
(result as ICustomEnumConverter)
35+
.setEnumDescriptor(getEnumDescriptor(_mapper.enumValues[typeInfo.type!]));
36+
}
37+
return result;
38+
}
39+
40+
IEnumDescriptor? getEnumDescriptor(dynamic descriptor) {
41+
if (descriptor is Iterable) {
42+
return EnumDescriptor(values: descriptor);
43+
}
44+
if (descriptor is IEnumDescriptor) {
45+
return descriptor;
46+
}
47+
return null;
48+
}
49+
50+
dynamic getConvertedValue(
51+
ICustomConverter converter, dynamic value, DeserializationContext context) {
52+
final direction = context.direction;
53+
if (convertedValuesCache.containsKey(converter) &&
54+
convertedValuesCache[converter]!.containsKey(direction) &&
55+
convertedValuesCache[converter]![direction]!.containsKey(context) &&
56+
convertedValuesCache[converter]![direction]![context]!
57+
.containsKey(value)) {
58+
return convertedValuesCache[converter]![direction]![context]![value];
59+
}
60+
61+
final computedValue = direction == ConversionDirection.fromJson
62+
? converter.fromJSON(value, context)
63+
: converter.toJSON(value, context as SerializationContext);
64+
convertedValuesCache.putIfAbsent(
65+
converter,
66+
() => {
67+
direction: {
68+
context: {value: computedValue}
69+
}
70+
});
71+
convertedValuesCache[converter]!.putIfAbsent(
72+
direction,
73+
() => {
74+
context: {value: computedValue}
75+
});
76+
convertedValuesCache[converter]![direction]!
77+
.putIfAbsent(context, () => {value: computedValue});
78+
convertedValuesCache[converter]![direction]![context]!
79+
.putIfAbsent(value, () => computedValue);
80+
return computedValue;
81+
}
82+
83+
void configureConverter(
84+
ICustomConverter converter, DeserializationContext context,
85+
{dynamic value}) {
86+
if (converter is ICompositeConverter) {
87+
(converter as ICompositeConverter).setGetConverterFunction(getConverter);
88+
(converter as ICompositeConverter)
89+
.setGetConvertedValueFunction(getConvertedValue);
90+
}
91+
if (converter is ICustomIterableConverter) {
92+
(converter as ICustomIterableConverter).setIterableInstance(value);
93+
}
94+
if (converter is ICustomMapConverter) {
95+
final instance = value ?? (context.options.template);
96+
(converter as ICustomMapConverter).setMapInstance(instance);
97+
}
98+
if (converter is IRecursiveConverter) {
99+
(converter as IRecursiveConverter).setSerializeObjectFunction(
100+
(o, context) => _mapper.serializationHandler.serializeObject(o, context));
101+
(converter as IRecursiveConverter).setDeserializeObjectFunction((o,
102+
context, type) =>
103+
_mapper.deserializationHandler.deserializeObject(o, context.reBuild(typeInfo: _mapper.typeInfoHandler.getTypeInfo(type))));
104+
}
105+
}
106+
}

mapper/lib/src/logic/deserialization_handler.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@ class DeserializationHandler {
2121
return null;
2222
}
2323
var typeInfo = context.typeInfo!;
24-
final converter = _mapper.getConverter(context.jsonPropertyMeta, typeInfo);
24+
final converter = _mapper.converterHandler.getConverter(context.jsonPropertyMeta, typeInfo);
2525
if (converter != null) {
26-
_mapper.configureConverter(converter, context);
26+
_mapper.converterHandler.configureConverter(converter, context);
2727
if (typeInfo.isIterable &&
2828
(converter is ICustomIterableConverter &&
2929
converter is! DefaultIterableConverter)) {
3030
return _mapper.applyValueDecorator(
31-
_mapper.getConvertedValue(converter, jsonValue, context), typeInfo);
31+
_mapper.converterHandler.getConvertedValue(converter, jsonValue, context), typeInfo);
3232
}
3333
return _mapper.applyValueDecorator(
34-
_mapper.getConvertedValue(converter, jsonValue, context), typeInfo);
34+
_mapper.converterHandler.getConvertedValue(converter, jsonValue, context), typeInfo);
3535
}
3636

3737
dynamic convertedJsonValue =
@@ -88,7 +88,7 @@ class DeserializationHandler {
8888
.toList()
8989
..addAll(positionalArgumentNames);
9090

91-
_mapper.enumeratePublicProperties(im, jsonMap, context, (name, property,
91+
_mapper.propertyHandler.enumeratePublicProperties(im, jsonMap, context, (name, property,
9292
isGetterOnly, JsonProperty? meta, converter, TypeInfo typeInfo) {
9393
final propertyContext = context.reBuild(
9494
parentObjectInstances: [
@@ -276,7 +276,7 @@ class DeserializationHandler {
276276
finalValueForVisitor = this.deserializeObject(jsonMap.map, propertyContext.reBuild(jsonPropertyMeta: null));
277277
jsonNameForVisitor = context.transformIdentifier(meta?.name ?? name);
278278
} else {
279-
final property = _mapper.resolveProperty(
279+
final property = _mapper.propertyHandler.resolveProperty(
280280
name,
281281
jsonMap,
282282
propertyContext,
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import 'package:dart_json_mapper/src/model/index.dart';
2+
import 'package:reflectable/reflectable.dart' show InstanceMirror, MethodMirror;
3+
4+
import '../class_info.dart';
5+
import '../json_map.dart';
6+
import '../mapper.dart';
7+
import 'field_handler.dart';
8+
import 'reflection_handler.dart';
9+
10+
class PropertyHandler {
11+
final JsonMapper _mapper;
12+
13+
PropertyHandler(this._mapper);
14+
15+
void enumeratePublicProperties(InstanceMirror instanceMirror,
16+
JsonMap? jsonMap, DeserializationContext context, Function visitor) {
17+
final classInfo = ClassInfo.fromCache(instanceMirror.type, _mapper.classes);
18+
final classMeta = classInfo.getMeta(context.options.scheme);
19+
20+
for (var name in classInfo.publicFieldNames) {
21+
final declarationMirror = classInfo.getDeclarationMirror(name);
22+
if (declarationMirror == null) {
23+
continue;
24+
}
25+
final declarationType = ReflectionHandler.getDeclarationType(declarationMirror);
26+
final isGetterOnly = classInfo.isGetterOnly(name);
27+
final meta = classInfo.getDeclarationMeta(
28+
declarationMirror, context.options.scheme);
29+
if (meta == null &&
30+
Json.getProcessAnnotatedMembersOnly(classMeta, context.options) == true) {
31+
continue;
32+
}
33+
34+
if (FieldHandler.isFieldIgnored(classMeta, meta, context.options)) {
35+
continue;
36+
}
37+
final propertyContext =
38+
context.reBuild(classMeta: classMeta, jsonPropertyMeta: meta);
39+
final property = resolveProperty(
40+
name, jsonMap, propertyContext, classMeta, meta, (name, jsonName, _) {
41+
var result = instanceMirror.invokeGetter(name);
42+
if (result == null && jsonMap != null) {
43+
result = jsonMap.getPropertyValue(jsonName);
44+
}
45+
return result;
46+
});
47+
48+
FieldHandler.checkFieldConstraints(
49+
property.value, name, jsonMap?.hasProperty(property.name), meta);
50+
51+
if (FieldHandler.isFieldIgnoredByValue(
52+
property.value, classMeta, meta, propertyContext.options)) {
53+
continue;
54+
}
55+
final typeInfo =
56+
_mapper.typeInfoHandler.getDeclarationTypeInfo(declarationType, property.value?.runtimeType);
57+
visitor(name, property, isGetterOnly, meta, _mapper.converterHandler.getConverter(meta, typeInfo),
58+
typeInfo);
59+
}
60+
61+
classInfo.enumerateJsonGetters((MethodMirror mm, JsonProperty meta) {
62+
final declarationType = ReflectionHandler.getDeclarationType(mm);
63+
final propertyContext =
64+
context.reBuild(classMeta: classMeta, jsonPropertyMeta: meta);
65+
final property = resolveProperty(
66+
mm.simpleName, jsonMap, propertyContext, classMeta, meta,
67+
(name, jsonName, _) {
68+
var result = instanceMirror.invoke(name, []);
69+
if (result == null && jsonMap != null) {
70+
result = jsonMap.getPropertyValue(jsonName);
71+
}
72+
return result;
73+
});
74+
75+
FieldHandler.checkFieldConstraints(property.value, mm.simpleName,
76+
jsonMap?.hasProperty(property.name), meta);
77+
if (FieldHandler.isFieldIgnoredByValue(
78+
property.value, classMeta, meta, context.options)) {
79+
return;
80+
}
81+
final typeInfo =
82+
_mapper.typeInfoHandler.getDeclarationTypeInfo(declarationType, property.value?.runtimeType);
83+
visitor(mm.simpleName, property, true, meta,
84+
_mapper.converterHandler.getConverter(meta, typeInfo), _mapper.typeInfoHandler.getTypeInfo(declarationType));
85+
}, context.options.scheme);
86+
}
87+
88+
PropertyDescriptor resolveProperty(
89+
String name,
90+
JsonMap? jsonMap,
91+
DeserializationContext context,
92+
Json? classMeta,
93+
JsonProperty? meta,
94+
Function getValueByName) {
95+
String? jsonName = name;
96+
97+
if (meta != null && meta.name != null) {
98+
jsonName = JsonProperty.getPrimaryName(meta);
99+
}
100+
jsonName = context.transformIdentifier(jsonName!);
101+
var value = getValueByName(name, jsonName, meta?.defaultValue);
102+
if (jsonMap != null &&
103+
meta != null &&
104+
(value == null || !jsonMap.hasProperty(jsonName))) {
105+
final initialValue = value;
106+
for (final alias in JsonProperty.getAliases(meta)!) {
107+
final targetJsonName = transformIdentifierCaseStyle(
108+
alias, context.targetCaseStyle, context.sourceCaseStyle);
109+
if (value != initialValue || !jsonMap.hasProperty(targetJsonName)) {
110+
continue;
111+
}
112+
jsonName = targetJsonName;
113+
value = jsonMap.getPropertyValue(jsonName);
114+
}
115+
}
116+
if (meta != null &&
117+
meta.inject == true &&
118+
context.options.injectableValues != null) {
119+
final injectionJsonMap = JsonMap(context.options.injectableValues!);
120+
if (injectionJsonMap.hasProperty(jsonName!)) {
121+
value = injectionJsonMap.getPropertyValue(jsonName);
122+
return PropertyDescriptor(jsonName, value, false);
123+
} else {
124+
return PropertyDescriptor(jsonName, null, false);
125+
}
126+
}
127+
if (jsonName == JsonProperty.parentReference) {
128+
return PropertyDescriptor(
129+
jsonName!, context.parentObjectInstances!.last, false);
130+
}
131+
if (value == null &&
132+
meta?.defaultValue != null &&
133+
FieldHandler.isFieldIgnoredByDefault(
134+
meta, classMeta, context.options as SerializationOptions)) {
135+
return PropertyDescriptor(jsonName!, meta?.defaultValue, true);
136+
}
137+
return PropertyDescriptor(jsonName!, value, true);
138+
}
139+
}

mapper/lib/src/logic/serialization_handler.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ class SerializationHandler {
2020
}
2121

2222
final im = ReflectionHandler.safeGetInstanceMirror(object);
23-
final converter = _mapper.getConverter(
23+
final converter = _mapper.converterHandler.getConverter(
2424
context!.jsonPropertyMeta, _mapper.typeInfoHandler.getTypeInfo(object.runtimeType));
2525
if (converter != null) {
26-
_mapper.configureConverter(converter, context, value: object);
27-
return _mapper.getConvertedValue(converter, object, context);
26+
_mapper.converterHandler.configureConverter(converter, context, value: object);
27+
return _mapper.converterHandler.getConvertedValue(converter, object, context);
2828
}
2929

3030
if (im == null) {
@@ -60,7 +60,7 @@ class SerializationHandler {
6060
}
6161
}
6262
_dumpDiscriminatorToObjectProperty(result, im.type, context.options);
63-
_mapper.enumeratePublicProperties(im, null, context, (name, property, isGetterOnly,
63+
_mapper.propertyHandler.enumeratePublicProperties(im, null, context, (name, property, isGetterOnly,
6464
JsonProperty? meta, converter, TypeInfo typeInfo) {
6565
dynamic convertedValue;
6666
final propertyContext = context.reBuild(
@@ -104,11 +104,11 @@ class SerializationHandler {
104104
return;
105105
}
106106

107-
final actualConverter = _mapper.getConverter(meta, typeInfo);
107+
final actualConverter = _mapper.converterHandler.getConverter(meta, typeInfo);
108108
if (actualConverter != null) {
109109
final valueToConvert = property.value ?? meta?.defaultValue;
110-
_mapper.configureConverter(actualConverter, propertyContext, value: valueToConvert);
111-
convertedValue = _mapper.getConvertedValue(actualConverter, valueToConvert, propertyContext);
110+
_mapper.converterHandler.configureConverter(actualConverter, propertyContext, value: valueToConvert);
111+
convertedValue = _mapper.converterHandler.getConvertedValue(actualConverter, valueToConvert, propertyContext);
112112
} else {
113113
convertedValue = this.serializeObject(property.value, propertyContext);
114114
}

0 commit comments

Comments
 (0)