【修复】修复json,xml,lua数据源未正确处理可空字段的bug

main
walon 2021-07-01 14:58:56 +08:00
parent 1a9547769d
commit 346febc8cb
6 changed files with 76 additions and 22 deletions

View File

@ -24,9 +24,12 @@ Luban适合有以下需求的开发者
3. 希望做其他自定义生成或者缓存 3. 希望做其他自定义生成或者缓存
====**如果觉得不错烦请点个star你的支持会给予我们巨大动力 ^_^**====
## 支持和联系 ## 支持和联系
有使用上的疑问请即时加QQ群询问随时帮助解决。 有使用方面的疑问请及时加QQ群询问随时有人帮助解决。
- QQ 群: 692890842 - QQ 群: 692890842
- 邮箱: taojingjian#gmail.com - 邮箱: taojingjian#gmail.com
@ -44,19 +47,19 @@ Luban适合有以下需求的开发者
- [示例项目](https://github.com/focus-creative-games/luban_examples) - [示例项目](https://github.com/focus-creative-games/luban_examples)
## 特性 ## 特性
- 支持增强的excel格式可以在excel里比较简洁填写出任意复杂的数据 - 支持增强的excel格式可以在excel里比较简洁填写出任意复杂的数据
- 支持excel族、json、xml、lua 多种数据格式,基本统一了游戏内的配置数据 - 支持excel族、json、xml、lua 多种数据格式,基本统一了游戏内的配置数据
- 灵活的数据源定义。一个表可以来自多个文件或者一个文件内定义多个表或者一个表对应一个目录下所有文件,以及以上的组合。 - 强大完备的类型系统。支持所有常见原生类型、容器类型list,set,map、枚举和结构、**多态结构**以及**可空类型**
- 强大完备的类型系统。支持所有常见原生类型、容器类型list,set,map、枚举和结构、**多态结构**以及**可空类型**。 - 灵活的数据源定义。一个表可以来自多个文件或者一个文件内定义多个表或者一个表对应一个目录下所有文件,以及以上的组合
- 支持表与字段级别分组。可以选择性地导出客户端或者服务器所用的表及字段 - 支持表与字段级别分组。可以选择性地导出客户端或者服务器所用的表及字段
- 多种导出数据格式支持。支持binary、json、lua 等导出数据格式 - 多种导出数据格式支持。支持binary、json、lua 等导出数据格式
- 支持数据标签。 可以选择导出符合要求的数据,发布正式数据时策划不必手动注释掉那些测试或者非正式数据了 - 支持数据标签。 可以选择导出符合要求的数据,发布正式数据时策划不必手动注释掉那些测试或者非正式数据了
- 强大的数据校验能力。支持内建数据格式检查支持ref表引用检查策划不用担心填错id支持path资源检查策划不用担心填错资源路径 - 强大的数据校验能力。支持内建数据格式检查支持ref表引用检查策划不用担心填错id支持path资源检查策划不用担心填错资源路径支持高级自定义校验比如两字段和必须100
- 支持常量别名。策划不必再为诸如 升级丹 这样的道具手写具体道具id了 - 支持常量别名。策划不必再为诸如 升级丹 这样的道具手写具体道具id了
- 支持多种常见数据表模式。 one(单例表)、map常规key-value表 - 支持多种常见数据表模式。 one(单例表)、map常规key-value表
- 支持emmylua anntations。生成的lua包含符合emmylua 格式anntations信息。配合emmylua有良好的配置代码提示能力 - 支持emmylua anntations。生成的lua包含符合emmylua 格式anntations信息。配合emmylua有良好的配置代码提示能力
- 支持res资源标记。可以一键导出配置中引用的所有资源列表(icon,ui,assetbundle等等) - 支持res资源标记。可以一键导出配置中引用的所有资源列表(icon,ui,assetbundle等等)
- 生成代码良好模块化 - 生成代码良好模块化
- **本地化支持** - **本地化支持**
- 支持时间本地化。datetime类型数据会根据指定的timezone转换为目标地区该时刻的UTC时间方便程序使用。 - 支持时间本地化。datetime类型数据会根据指定的timezone转换为目标地区该时刻的UTC时间方便程序使用。
- **支持文本静态本地化。导出时所有text类型数据正确替换为最终的本地化字符串。** - **支持文本静态本地化。导出时所有text类型数据正确替换为最终的本地化字符串。**
@ -200,7 +203,7 @@ Luban适合有以下需求的开发者
![ex_32](docs/images/examples/ex_32.png) ![ex_32](docs/images/examples/ex_32.png)
### 可空数据类型 ### 可空数据类型
配置数据中经常有空值的语义需求实际项目中往往混杂地使用0或-1表达空值既不自然清晰也不统一。luban借鉴了c#中的可空变量的概念,特地提供可空数据支持。除了string外的所有原生数据类型以及enum、bean、和多态bean类型都有相应的可空数据类型。定义方式为 <类型名>?与c#里的Nullable类型定义方式相同。例如 bool?,int?,long?,double?, EColor?, DemoType? 配置数据中经常有空值的语义需求实际项目中往往混杂地使用0或-1表达空值既不自然清晰也不统一。luban借鉴了c#中的可空变量的概念特地提供可空数据支持。所有原生数据类型以及enum、bean、和多态bean类型都有相应的可空数据类型。定义方式为 <类型名>?与c#里的Nullable类型定义方式相同。例如 bool?,int?,long?,double?, EColor?, DemoType?
```xml ```xml
<bean name="DemoType1"> <bean name="DemoType1">

View File

@ -259,7 +259,19 @@ namespace Luban.Job.Cfg.DataCreators
{ {
throw new InvalidExcelDataException("excel string类型在标题头对应模式下必须正好占据一个单元格"); throw new InvalidExcelDataException("excel string类型在标题头对应模式下必须正好占据一个单元格");
} }
return new DString(ParseString(x.Read(x.NamedMode))); var s = ParseString(x.Read(x.NamedMode));
if (s == null)
{
if (type.IsNullable)
{
return null;
}
else
{
throw new InvalidExcelDataException("字段不是nullable类型不能为null");
}
}
return new DString(s);
} }
public DType Accept(TBytes type, object converter, ExcelStream x, DefAssembly ass) public DType Accept(TBytes type, object converter, ExcelStream x, DefAssembly ass)
@ -271,7 +283,7 @@ namespace Luban.Job.Cfg.DataCreators
{ {
if (d == null) if (d == null)
{ {
return ""; return string.Empty;
} }
else if (d is string s) else if (d is string s)
{ {
@ -290,6 +302,18 @@ namespace Luban.Job.Cfg.DataCreators
throw new InvalidExcelDataException("excel text 类型在标题头对应模式下必须正好占据2个单元格"); throw new InvalidExcelDataException("excel text 类型在标题头对应模式下必须正好占据2个单元格");
} }
string key = ParseString(x.Read(x.NamedMode)); string key = ParseString(x.Read(x.NamedMode));
if (key == null)
{
if (type.IsNullable)
{
return null;
}
else
{
throw new InvalidExcelDataException("该字段不是nullable类型不能为null");
}
}
string text = ParseString(x.Read(x.NamedMode)); string text = ParseString(x.Read(x.NamedMode));
DataUtil.ValidateText(key, text); DataUtil.ValidateText(key, text);
return new DText(key, text); return new DText(key, text);

View File

@ -133,6 +133,19 @@ namespace Luban.Job.Cfg.DataCreators
foreach (var field in implBean.HierarchyFields) foreach (var field in implBean.HierarchyFields)
{ {
if (x.TryGetProperty(field.Name, out var ele)) if (x.TryGetProperty(field.Name, out var ele))
{
if (ele.ValueKind == JsonValueKind.Null || ele.ValueKind == JsonValueKind.Undefined)
{
if (field.CType.IsNullable)
{
fields.Add(null);
}
else
{
throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 不能 null or undefined ");
}
}
else
{ {
try try
{ {
@ -143,6 +156,11 @@ namespace Luban.Job.Cfg.DataCreators
throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 读取失败 => {e.Message}", e); throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 读取失败 => {e.Message}", e);
} }
} }
}
else if (field.CType.IsNullable)
{
fields.Add(null);
}
else else
{ {
throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 缺失"); throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 缺失");

View File

@ -188,6 +188,10 @@ namespace Luban.Job.Cfg.DataCreators
throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 读取失败 => {e.Message}", e); throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 读取失败 => {e.Message}", e);
} }
} }
else if (field.CType.IsNullable)
{
fields.Add(null);
}
else else
{ {
throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 缺失"); throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 缺失");

View File

@ -120,9 +120,13 @@ namespace Luban.Job.Cfg.DataCreators
XElement fele = feles.FirstOrDefault(); XElement fele = feles.FirstOrDefault();
if (fele == null) if (fele == null)
{ {
if (field.CType.IsNullable)
{
fields.Add(null);
continue;
}
throw new Exception($"字段:{field.Name} 缺失"); throw new Exception($"字段:{field.Name} 缺失");
} }
try try
{ {
fields.Add(field.CType.Apply(this, fele, ass)); fields.Add(field.CType.Apply(this, fele, ass));

View File

@ -70,11 +70,12 @@ namespace Luban.Job.Cfg.Utils
public static string UnEscapeString(string s) public static string UnEscapeString(string s)
{ {
if (s == "null" || s == "\"\"") switch (s)
{ {
return ""; case "null": return null;
case "\"\"": return string.Empty;
default: return s;
} }
return s;
} }
public static (string Key, string Text) ExtractText(string rawKeyAndText) public static (string Key, string Text) ExtractText(string rawKeyAndText)