Skip to content

Commit

Permalink
[dart][dio][built_value] Fix missing serializer factory builders for …
Browse files Browse the repository at this point in the history
…additionalProperties (#11011)

Refactor the addition of custom serializer factories.
  • Loading branch information
kuhnroyal authored Dec 4, 2021
1 parent 85985e8 commit ecddd4c
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
super.postProcessModelProperty(model, property);
if (!model.isEnum && property.isEnum) {
// These are inner enums, enums which do not exist as models, just as properties.
// They are handled via the enum_inline template and and are generated in the
// They are handled via the enum_inline template and are generated in the
// same file as the containing class. To prevent name clashes the inline enum classes
// are prefix with the classname of the containing class in the template.
// Here the datatypeWithEnum template variable gets updated to match that scheme.
Expand All @@ -529,9 +529,9 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List<Server> servers) {
final CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers);
for (CodegenResponse r : op.responses) {
// By default only set types are automatically added to operation imports, not sure why.
// By default, only set types are automatically added to operation imports, not sure why.
// Add all container type imports here, by default 'dart:core' imports are skipped
// but other sub classes may required specific container type imports.
// but other sub-classes may require specific container type imports.
if (r.containerType != null && typeMapping().containsKey(r.containerType)) {
final String value = typeMapping().get(r.containerType);
if (needToImport(value)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,21 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
// enums are generated with built_value and make use of BuiltSet
model.imports.add("BuiltSet");
}

if (property.isContainer) {
// Figure out if there are any container type additionalProperties
// that need a custom serializer builder factory added.
final CodegenProperty items = property.items;
if (items.getAdditionalProperties() != null) {
addBuiltValueSerializer(new BuiltValueSerializer(
items.isArray,
items.getUniqueItems(),
items.isMap,
items.items.isNullable,
items.getAdditionalProperties().dataType
));
}
}
}
}

Expand All @@ -332,7 +347,6 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");

Set<Map<String, Object>> serializers = new HashSet<>();
Set<String> resultImports = new HashSet<>();

for (CodegenOperation op : operationList) {
Expand Down Expand Up @@ -370,12 +384,13 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
// Generate serializer factories for all container type parameters.
// But skip binary and file parameters, JSON serializers don't make sense there.
if (param.isContainer && !(param.isBinary || param.isFile )) {
final Map<String, Object> serializer = new HashMap<>();
serializer.put("isArray", param.isArray);
serializer.put("uniqueItems", param.uniqueItems);
serializer.put("isMap", param.isMap);
serializer.put("baseType", param.baseType);
serializers.add(serializer);
addBuiltValueSerializer(new BuiltValueSerializer(
param.isArray,
param.uniqueItems,
param.isMap,
param.items.isNullable,
param.baseType
));
}
}

Expand All @@ -387,17 +402,17 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
// Generate serializer factories for response types.
// But skip binary and file response, JSON serializers don't make sense there.
if (op.returnContainer != null && !(op.isResponseBinary || op.isResponseFile)) {
final Map<String, Object> serializer = new HashMap<>();
serializer.put("isArray", Objects.equals("array", op.returnContainer) || Objects.equals("set", op.returnContainer));
serializer.put("uniqueItems", op.uniqueItems);
serializer.put("isMap", Objects.equals("map", op.returnContainer));
serializer.put("baseType", op.returnBaseType);
serializers.add(serializer);
addBuiltValueSerializer(new BuiltValueSerializer(
Objects.equals("array", op.returnContainer) || Objects.equals("set", op.returnContainer),
op.uniqueItems,
Objects.equals("map", op.returnContainer),
false,
op.returnBaseType
));
}
}

objs.put("imports", resultImports.stream().sorted().collect(Collectors.toList()));
objs.put("serializers", serializers);

return objs;
}
Expand All @@ -410,6 +425,19 @@ private void addBuiltValueSerializerImport(String type) {
});
}

/**
* Adds the serializer to the global list of custom built_value serializers.
* @param serializer
*/
private void addBuiltValueSerializer(BuiltValueSerializer serializer) {
System.out.println("######## Add serializer!");
additionalProperties.compute("builtValueSerializers", (k, v) -> {
Set<BuiltValueSerializer> serializers = v == null ? Sets.newHashSet() : ((Set<BuiltValueSerializer>) v);
serializers.add(serializer);
return serializers;
});
}

private Set<String> rewriteImports(Set<String> originalImports, boolean isModel) {
Set<String> resultImports = Sets.newHashSet();
for (String modelImport : originalImports) {
Expand All @@ -428,4 +456,58 @@ private Set<String> rewriteImports(Set<String> originalImports, boolean isModel)
}
return resultImports;
}

static class BuiltValueSerializer {

final boolean isArray;

final boolean uniqueItems;

final boolean isMap;

final boolean isNullable;

final String dataType;

private BuiltValueSerializer(boolean isArray, boolean uniqueItems, boolean isMap, boolean isNullable, String dataType) {
this.isArray = isArray;
this.uniqueItems = uniqueItems;
this.isMap = isMap;
this.isNullable = isNullable;
this.dataType = dataType;
}

public boolean isArray() {
return isArray;
}

public boolean isUniqueItems() {
return uniqueItems;
}

public boolean isMap() {
return isMap;
}

public boolean isNullable() {
return isNullable;
}

public String getDataType() {
return dataType;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BuiltValueSerializer that = (BuiltValueSerializer) o;
return isArray == that.isArray && uniqueItems == that.uniqueItems && isMap == that.isMap && isNullable == that.isNullable && dataType.equals(that.dataType);
}

@Override
public int hashCode() {
return Objects.hash(isArray, uniqueItems, isMap, isNullable, dataType);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ part 'serializers.g.dart';
@SerializersFor([{{#models}}{{#model}}
{{classname}},{{/model}}{{/models}}
])
Serializers serializers = (_$serializers.toBuilder(){{#apiInfo}}{{#apis}}{{#serializers}}
Serializers serializers = (_$serializers.toBuilder(){{#builtValueSerializers}}
..addBuilderFactory(
{{#isArray}}
const FullType(Built{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}, [FullType({{baseType}})]),
() => {{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}Builder<{{baseType}}>(),
const FullType(Built{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}, [FullType{{#isNullable}}.nullable{{/isNullable}}({{dataType}})]),
() => {{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}Builder<{{dataType}}>(),
{{/isArray}}
{{#isMap}}
const FullType(BuiltMap, [FullType(String), FullType({{baseType}})]),
() => MapBuilder<String, {{baseType}}>(),
const FullType(BuiltMap, [FullType(String), FullType{{#isNullable}}.nullable{{/isNullable}}({{dataType}})]),
() => MapBuilder<String, {{dataType}}>(),
{{/isMap}}
){{/serializers}}{{/apis}}{{/apiInfo}}{{#useDateLibTimeMachine}}
){{/builtValueSerializers}}{{#useDateLibTimeMachine}}
..add(const OffsetDateSerializer())
..add(const OffsetDateTimeSerializer()){{/useDateLibTimeMachine}}{{#useDateLibCore}}
..add(const DateSerializer())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,26 +110,22 @@ part 'serializers.g.dart';
User,
])
Serializers serializers = (_$serializers.toBuilder()
..addBuilderFactory(
const FullType(BuiltList, [FullType(String)]),
() => ListBuilder<String>(),
)
..addBuilderFactory(
const FullType(BuiltMap, [FullType(String), FullType(String)]),
() => MapBuilder<String, String>(),
)
..addBuilderFactory(
const FullType(BuiltList, [FullType(String)]),
() => ListBuilder<String>(),
)
..addBuilderFactory(
const FullType(BuiltSet, [FullType(Pet)]),
() => SetBuilder<Pet>(),
const FullType(BuiltList, [FullType(User)]),
() => ListBuilder<User>(),
)
..addBuilderFactory(
const FullType(BuiltSet, [FullType(String)]),
() => SetBuilder<String>(),
)
..addBuilderFactory(
const FullType(BuiltSet, [FullType(Pet)]),
() => SetBuilder<Pet>(),
)
..addBuilderFactory(
const FullType(BuiltList, [FullType(Pet)]),
() => ListBuilder<Pet>(),
Expand All @@ -139,8 +135,8 @@ Serializers serializers = (_$serializers.toBuilder()
() => MapBuilder<String, int>(),
)
..addBuilderFactory(
const FullType(BuiltList, [FullType(User)]),
() => ListBuilder<User>(),
const FullType(BuiltList, [FullType(String)]),
() => ListBuilder<String>(),
)
..add(const DateSerializer())
..add(Iso8601DateTimeSerializer()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,26 +110,22 @@ part 'serializers.g.dart';
User,
])
Serializers serializers = (_$serializers.toBuilder()
..addBuilderFactory(
const FullType(BuiltList, [FullType(String)]),
() => ListBuilder<String>(),
)
..addBuilderFactory(
const FullType(BuiltMap, [FullType(String), FullType(String)]),
() => MapBuilder<String, String>(),
)
..addBuilderFactory(
const FullType(BuiltList, [FullType(String)]),
() => ListBuilder<String>(),
)
..addBuilderFactory(
const FullType(BuiltSet, [FullType(Pet)]),
() => SetBuilder<Pet>(),
const FullType(BuiltList, [FullType(User)]),
() => ListBuilder<User>(),
)
..addBuilderFactory(
const FullType(BuiltSet, [FullType(String)]),
() => SetBuilder<String>(),
)
..addBuilderFactory(
const FullType(BuiltSet, [FullType(Pet)]),
() => SetBuilder<Pet>(),
)
..addBuilderFactory(
const FullType(BuiltList, [FullType(Pet)]),
() => ListBuilder<Pet>(),
Expand All @@ -139,8 +135,8 @@ Serializers serializers = (_$serializers.toBuilder()
() => MapBuilder<String, int>(),
)
..addBuilderFactory(
const FullType(BuiltList, [FullType(User)]),
() => ListBuilder<User>(),
const FullType(BuiltList, [FullType(String)]),
() => ListBuilder<String>(),
)
..add(const DateSerializer())
..add(Iso8601DateTimeSerializer()))
Expand Down

0 comments on commit ecddd4c

Please sign in to comment.