浏览代码

[dart-gen] Support Null-safe and omitempty json tag (#3134)

fondoger 2 年之前
父节点
当前提交
078825b4eb
共有 3 个文件被更改,包括 74 次插入7 次删除
  1. 19 5
      tools/goctl/api/dartgen/gendata.go
  2. 52 2
      tools/goctl/api/dartgen/util.go
  3. 3 0
      tools/goctl/api/dartgen/vars.go

+ 19 - 5
tools/goctl/api/dartgen/gendata.go

@@ -42,15 +42,29 @@ class {{.Name}} {
 	{{range .Members}}  required this.{{lowCamelCase .Name}},
 	{{end}}}{{end}});
 	factory {{.Name}}.fromJson(Map<String,dynamic> m) {
-		return {{.Name}}({{range .Members}}
-			{{lowCamelCase .Name}}: {{if isDirectType .Type.Name}}m['{{getPropertyFromMember .}}']
-			{{else if isClassListType .Type.Name}}(m['{{getPropertyFromMember .}}'] as List<dynamic>).map((i) => {{getCoreType .Type.Name}}.fromJson(i)).toList()
-			{{else}}{{.Type.Name}}.fromJson(m['{{getPropertyFromMember .}}']){{end}},{{end}}
+		return {{.Name}}(
+			{{range .Members}}
+				{{lowCamelCase .Name}}: {{appendNullCoalescing .}}
+					{{if isDirectType .Type.Name}}
+						m['{{getPropertyFromMember .}}'] {{appendDefaultEmptyValue .Type.Name}}
+					{{else if isClassListType .Type.Name}}
+						((m['{{getPropertyFromMember .}}'] {{appendDefaultEmptyValue .Type.Name}}) as List<dynamic>).map((i) => {{getCoreType .Type.Name}}.fromJson(i)).toList()
+					{{else}}
+						{{.Type.Name}}.fromJson(m['{{getPropertyFromMember .}}']){{end}}
+			,{{end}}
 		);
 	}
 	Map<String,dynamic> toJson() {
 		return { {{range .Members}}
-			'{{getPropertyFromMember .}}': {{if isDirectType .Type.Name}}{{lowCamelCase .Name}}{{else if isClassListType .Type.Name}}{{lowCamelCase .Name}}.map((i) => i.toJson()){{else}}{{lowCamelCase .Name}}.toJson(){{end}},{{end}}
+			'{{getPropertyFromMember .}}': 
+				{{if isDirectType .Type.Name}}
+					{{lowCamelCase .Name}}
+				{{else if isClassListType .Type.Name}}
+					{{lowCamelCase .Name}}{{if isNullableType .Type.Name}}?{{end}}.map((i) => i.toJson())
+				{{else}}
+					{{lowCamelCase .Name}}{{if isNullableType .Type.Name}}?{{end}}.toJson()
+				{{end}}
+			,{{end}}
 		};
 	}
 }

+ 52 - 2
tools/goctl/api/dartgen/util.go

@@ -74,6 +74,52 @@ func isClassListType(s string) bool {
 	return strings.HasPrefix(s, "List<") && !isAtomicType(getCoreType(s))
 }
 
+func isMapType(s string) bool {
+	return strings.HasPrefix(s, "Map<")
+}
+
+// Only interface types are nullable
+func isNullableType(s string) bool {
+	return strings.HasSuffix(s, "?")
+}
+
+func appendNullCoalescing(member spec.Member) string {
+	if isNullableType(member.Type.Name()) {
+		return "m['" + getPropertyFromMember(member) + "'] == null ? null : "
+	}
+	return ""
+}
+
+// To be compatible with omitempty tags in Golang
+// Only set default value for non-nullable types
+func appendDefaultEmptyValue(s string) string {
+	if isNullableType(s) {
+		return ""
+	}
+
+	if isAtomicType(s) {
+		switch s {
+		case "String":
+			return `?? ""`
+		case "int":
+			return "?? 0"
+		case "double":
+			return "?? 0.0"
+		case "bool":
+			return "?? false"
+		default:
+			panic(errors.New("unknown atomic type"))
+		}
+	}
+	if isListType(s) {
+		return "?? []"
+	}
+	if isMapType(s) {
+		return "?? {}"
+	}
+	return ""
+}
+
 func getCoreType(s string) string {
 	if isAtomicType(s) {
 		return s
@@ -139,9 +185,13 @@ func specTypeToDart(tp spec.Type) (string, error) {
 		}
 		return fmt.Sprintf("List<%s>", valueType), nil
 	case spec.InterfaceType:
-		return "Object", nil
+		return "Object?", nil
 	case spec.PointerType:
-		return specTypeToDart(v.Type)
+		valueType, err := specTypeToDart(v.Type)
+		if err != nil {
+			return "", err
+		}
+		return fmt.Sprintf("%s?", valueType), nil
 	}
 
 	return "", errors.New("unsupported primitive type " + tp.Name())

+ 3 - 0
tools/goctl/api/dartgen/vars.go

@@ -8,6 +8,9 @@ var funcMap = template.FuncMap{
 	"isDirectType":                    isDirectType,
 	"isNumberType":                    isNumberType,
 	"isClassListType":                 isClassListType,
+	"isNullableType":                  isNullableType,
+	"appendNullCoalescing":            appendNullCoalescing,
+	"appendDefaultEmptyValue":         appendDefaultEmptyValue,
 	"getCoreType":                     getCoreType,
 	"lowCamelCase":                    lowCamelCase,
 	"normalizeHandlerName":            normalizeHandlerName,