简介:
通过SPEL 和 fastjson 配合使用,指定JSON中字段解析的表达式,实现指定字段按照指定表达式填充的效果。
以使用三目运算符指定解析为例,代码如下。
首先,定义字段的反序列化解析类 SpelExpressDeserializer
import java.lang.reflect.Type;
import org.springframework.expression.expression;
import org.springframework.expression.expressionParser;
import org.springframework.expression.spel.standard.SpelexpressionParser;
import org.springframework.expression.spel.support.StandardevaluationContext;
import org.springframework.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.deserializer.ContextObjectDeserializer;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SpelExpressDeserializer extends ContextObjectDeserializer implements ObjectDeserializer {
private expressionParser spel = new SpelexpressionParser();
@Override
public int getFastMatchToken() {
return 0;
}
@SuppressWarnings("unchecked")
@Override
public T deserialze(DefaultJSonParser parser, Type type, Object fieldName, String format, int features) {
Object parse = parser.parse(fieldName);
if (null == parse || StringUtils.isEmpty(format)) {
return null;
}
// 通过SPEL运算出结果。
StandardevaluationContext context = new StandardevaluationContext();
context.setVariables(JSON.parseObject(parser.getInput()));
T value = null;
try {
String express = format.replaceAll("'", """);
expression exp = spel.parseexpression(express);
value = (T) exp.getValue(context, type.getTypeName());
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return value;
}
}
然后,单元测试如下
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.Test;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
public class JsonFormatWithSpelTest {
@Data
static class DemoBill {
private String billNo;
private String remark;
@JSonField(alternateNames = "remark", format = "#remark == null || #remark.isEmpty()? false:true", deserializeUsing = SpelExpressDeserializer.class)
private Boolean has_remark;
@JSonField(alternateNames = "remark", format = "#remark == null || #remark.isEmpty()? 0:#remark.length()", deserializeUsing = SpelExpressDeserializer.class)
private Integer remark_length;
}
@Test
public void testDeserializer() {
String json_a = "{"billNo":"No0001","remark":"1234","_remark":"1234"}";
DemoBill demo_a = fillJson(json_a, DemoBill.class);
System.out.println("demo_a: " + JSON.toJSonString(demo_a));
String json_b = "{"billNo":"No0002"}";
DemoBill demo_b = fillJson(json_b, DemoBill.class);
System.out.println("demo_b: " + JSON.toJSonString(demo_b));
}
private T fillJson(String sourceJson, Class clazz) {
Map> fieldMap = getNameMapping(clazz);
JSonObject json = JSON.parseObject(sourceJson);
// 填充自定义标签字段值,用关联字段填充,因为JSON数据中不包含当前属性时,反序列化方法不会执行。
for (Entry> entry : fieldMap.entrySet()) {
String key = entry.getKey();
Object val = json.containsKey(key) ? json.get(entry.getKey()) : "";
entry.getValue().forEach(a -> json.put(a, val));
}
return JSON.parseObject(json.toJSonString(), clazz);
}
private Map> getNameMapping(Class> clazz) {
Map> fieldMap = new HashMap<>();
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
declaredField.isAnnotationPresent(JSONField.class);
JSonField annotation = declaredField.getAnnotation(JSONField.class);
if (null == annotation) {
continue;
}
if (annotation.deserializeUsing().equals(SpelExpressDeserializer.class)) {
String name = declaredField.getName();
String refField = annotation.alternateNames()[0];
List list = fieldMap.get(refField);
if (null == list) {
list = new ArrayList<>();
}
list.add(name);
fieldMap.put(refField, list);
}
}
return fieldMap;
}
}
说明:JSON字符串中不包含某个属性时,不会进入反序列化方法
打印结果如下。
demo_a: {"billNo":"No0001","has_remark":true,"remark":"1234","remark_length":4}
demo_b: {"billNo":"No0002","has_remark":false,"remark_length":0}



