java
@Data
@IndexName("demo")
public class EasyEsDemo {
@IndexId
private String id;
private String name;
private int age;
// 这个Map字段因为NameFilter过滤器,导致fastjson序列化后为{null:"value"}这种形式,insert报错
private Map<String, Object> data;
}
上面Map类型字段保存报错如下:
java
Caused by: ElasticsearchException[Elasticsearch exception [type=json_parse_exception, reason=Unexpected character ('n' (code 110)): was expecting double-quote to start field name
.....
此错误主要原因是:EntityInfoHelper中创建的NameFilter是一个匿名类,看上去主要功能就是过滤排除字段,但是针对Map类型字段就出现了问题,导致序列化时候Map的key字段变成了个null. 导致fastjson序列化后为{null:"value"}这种形式,insert报错。
EntityInfoHelper中NameFilter过滤器代码如下:这个过滤器导致序列化Map类型字段时,获取的key当成类的字段属性处理,而类中没有名字为key的字段,所以过滤器过滤完后key变成了null
java
/**
* 添加fastjson字段过滤器
*
* @param entityInfo 实体信息
*/
private static void addNameFilter(EntityInfo entityInfo, List<SerializeFilter> preFilters) {
Map<String, String> mappingColumnMap = entityInfo.getMappingColumnMap();
Map<Class<?>, Map<String, String>> nestedClassMappingColumnMap = entityInfo.getNestedClassMappingColumnMap();
if (!mappingColumnMap.isEmpty()) {
NameFilter nameFilter = (object, name, value) -> {
Map<String, String> nestedMappingColumnMap = nestedClassMappingColumnMap.get(object.getClass());
if (Objects.nonNull(nestedMappingColumnMap)) {
String nestedMappingColumn = nestedMappingColumnMap.get(name);
if (Objects.equals(nestedMappingColumn, name)) {
return name;
} else {
return nestedMappingColumn;
}
}
String mappingColumn = mappingColumnMap.get(name);
if (Objects.equals(mappingColumn, name)) {
return name;
}
return mappingColumn;
};
preFilters.add(nameFilter);
}
}
不知道是个bug还是不推荐使用Map类型字段。或者说有别的处理方式。目前使用的处理方式如下:自定义一个Map的序列化器,并在Map类型字段增加注解
java
public static class MyMapSerializer extends MapSerializer {
@Override
protected String processKey(JSONSerializer jsonBeanDeser, Object object, String key, Object propertyValue) {
// 删除了 jsonBeanDeser.nameFilters 的处理逻辑
if (this.nameFilters != null) {
for (NameFilter nameFilter : this.nameFilters) {
key = nameFilter.process(object, key, propertyValue);
}
}
return key;
}
}
// 手动指定自定义的序列化处理器
@JSONField(serializeUsing = MyMapSerializer.class)
private Map<String, Object> data;