Skip to content

Commit b000e3d

Browse files
committed
refactor: pojo to json
1 parent b565db8 commit b000e3d

31 files changed

+760
-367
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.github.linyimin.plugin.constant;
2+
3+
import com.google.common.collect.Lists;
4+
import java.util.List;
5+
6+
/**
7+
* @author yiminlin
8+
* @date 2022/01/31 2:32 上午
9+
* @description constant class
10+
**/
11+
public class Constant {
12+
public static final String MAPPER = "mapper";
13+
public static final List<String> MYBATIS_OPS = Lists.newArrayList(
14+
"insert", "update", "delete", "select"
15+
);
16+
17+
public static final String PARAM_ANNOTATION = "org.apache.ibatis.annotations.Param";
18+
19+
public static final String APPLICATION_NAME = "mybatis-sql-viewer";
20+
21+
public static final String DATABASE_URL_TEMPLATE = "jdbc:mysql://%s:%s/%s";
22+
23+
}

src/main/java/io/github/linyimin/plugin/dom/Constant.java

Lines changed: 0 additions & 72 deletions
This file was deleted.

src/main/java/io/github/linyimin/plugin/mybatis/scripting/tags/DynamicContext.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ public DynamicContext(Object parameterObject) {
5252
bindings.put("array", array);
5353
}
5454

55+
if (parameterObject != null && JSONObject.isValidObject(parameterObject.toString())) {
56+
JSONObject object = JSONObject.parseObject(parameterObject.toString());
57+
if (object.size() != 1) {
58+
return;
59+
}
60+
Collection<Object> values = object.values();
61+
for (Object value : values) {
62+
if (JSONObject.isValidArray(value.toString())) {
63+
JSONArray array = JSONObject.parseArray(value.toString());
64+
bindings.put("collection", array);
65+
bindings.put("list", array);
66+
bindings.put("array", array);
67+
}
68+
}
69+
}
70+
5571
}
5672

5773
public Map<String, Object> getBindings() {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.github.linyimin.plugin.pojo2json;
2+
3+
import io.github.linyimin.plugin.pojo2json.type.SpecifyType;
4+
5+
/**
6+
* @author banzhe
7+
* @date 2022/11/21 21:12
8+
**/
9+
public class DefaultPOJO2JSONParser extends POJO2JSONParser {
10+
@Override
11+
protected Object getFakeValue(SpecifyType specifyType) {
12+
return specifyType.def();
13+
}
14+
}
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
package io.github.linyimin.plugin.pojo2json;
2+
3+
import com.intellij.navigation.NavigationItem;
4+
import com.intellij.psi.*;
5+
import com.intellij.psi.javadoc.PsiDocComment;
6+
import com.intellij.psi.javadoc.PsiDocTag;
7+
import com.intellij.psi.util.PsiUtil;
8+
import io.github.linyimin.plugin.mybatis.parsing.ParseException;
9+
import io.github.linyimin.plugin.pojo2json.type.*;
10+
import org.apache.commons.lang3.StringUtils;
11+
import org.apache.commons.lang3.tuple.Pair;
12+
13+
import java.util.*;
14+
import java.util.stream.Collectors;
15+
16+
/**
17+
* @author banzhe
18+
* @date 2022/11/21 20:17
19+
**/
20+
public abstract class POJO2JSONParser {
21+
22+
private final Map<String, SpecifyType> specifyTypes = new HashMap<>();
23+
24+
private final List<String> iterableTypes = Arrays.asList(
25+
"Iterable",
26+
"Collection",
27+
"List",
28+
"Set"
29+
);
30+
31+
public POJO2JSONParser() {
32+
33+
DecimalType decimalType = new DecimalType();
34+
LocalDateTimeType localDateTimeType = new LocalDateTimeType();
35+
36+
specifyTypes.put("Boolean", new BooleanType());
37+
specifyTypes.put("Float", decimalType);
38+
specifyTypes.put("Double", decimalType);
39+
specifyTypes.put("BigDecimal", decimalType);
40+
specifyTypes.put("Number", new IntegerType());
41+
specifyTypes.put("Character", new CharType());
42+
specifyTypes.put("CharSequence", new StringType());
43+
specifyTypes.put("Date", localDateTimeType);
44+
specifyTypes.put("Temporal", new TemporalType());
45+
specifyTypes.put("LocalDateTime", localDateTimeType);
46+
specifyTypes.put("LocalDate", new LocalDateType());
47+
specifyTypes.put("LocalTime", new LocalTimeType());
48+
specifyTypes.put("ZonedDateTime", new ZonedDateTimeType());
49+
specifyTypes.put("YearMonth", new YearMonthType());
50+
specifyTypes.put("UUID", new UUIDType());
51+
}
52+
53+
protected abstract Object getFakeValue(SpecifyType specifyType);
54+
55+
public Map<String, Object> parseClass(PsiClass psiClass, int level, List<String> ignoreProperties, Map<String, PsiType> psiClassGenerics) {
56+
PsiAnnotation annotation = psiClass.getAnnotation(com.fasterxml.jackson.annotation.JsonIgnoreType.class.getName());
57+
if (annotation != null) {
58+
return null;
59+
}
60+
return Arrays.stream(psiClass.getAllFields())
61+
.map(field -> parseField(field, level, ignoreProperties, psiClassGenerics))
62+
.filter(Objects::nonNull)
63+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (ov, nv) -> ov, LinkedHashMap::new));
64+
}
65+
66+
67+
private Map.Entry<String, Object> parseField(PsiField field, int level, List<String> ignoreProperties, Map<String, PsiType> psiClassGenerics) {
68+
// 移除所有 static 属性,这其中包括 kotlin 中的 companion object 和 INSTANCE
69+
if (field.hasModifierProperty(PsiModifier.STATIC)) {
70+
return null;
71+
}
72+
73+
if (ignoreProperties.contains(field.getName())) {
74+
return null;
75+
}
76+
77+
PsiAnnotation annotation = field.getAnnotation(com.fasterxml.jackson.annotation.JsonIgnore.class.getName());
78+
if (annotation != null) {
79+
return null;
80+
}
81+
82+
PsiDocComment docComment = field.getDocComment();
83+
if (docComment != null) {
84+
PsiDocTag psiDocTag = docComment.findTagByName("JsonIgnore");
85+
if (psiDocTag != null && "JsonIgnore".equals(psiDocTag.getName())) {
86+
return null;
87+
}
88+
89+
ignoreProperties = POJO2JSONParserUtils.docTextToList("@JsonIgnoreProperties", docComment.getText());
90+
} else {
91+
annotation = field.getAnnotation(com.fasterxml.jackson.annotation.JsonIgnoreProperties.class.getName());
92+
if (annotation != null && annotation.findAttributeValue("value") != null) {
93+
ignoreProperties = POJO2JSONParserUtils.arrayTextToList(annotation.findAttributeValue("value").getText());
94+
}
95+
}
96+
97+
String fieldKey = parseFieldKey(field);
98+
if (fieldKey == null) {
99+
return null;
100+
}
101+
Object fieldValue = parseFieldValue(field, level, ignoreProperties, psiClassGenerics);
102+
if (fieldValue == null) {
103+
return null;
104+
}
105+
return Pair.of(fieldKey, fieldValue);
106+
}
107+
108+
private String parseFieldKey(PsiField field) {
109+
110+
PsiAnnotation annotation = field.getAnnotation(com.fasterxml.jackson.annotation.JsonProperty.class.getName());
111+
if (annotation != null) {
112+
String fieldName = POJO2JSONParserUtils.psiTextToString(annotation.findAttributeValue("value").getText());
113+
if (StringUtils.isNotBlank(fieldName)) {
114+
return fieldName;
115+
}
116+
}
117+
118+
annotation = field.getAnnotation("com.alibaba.fastjson.annotation.JSONField");
119+
if (annotation != null) {
120+
String fieldName = POJO2JSONParserUtils.psiTextToString(annotation.findAttributeValue("name").getText());
121+
if (StringUtils.isNotBlank(fieldName)) {
122+
return fieldName;
123+
}
124+
}
125+
return field.getName();
126+
}
127+
128+
private Object parseFieldValue(PsiField field, int level, List<String> ignoreProperties, Map<String, PsiType> psiClassGenerics) {
129+
return parseFieldValueType(field.getType(), level, ignoreProperties, psiClassGenerics);
130+
}
131+
132+
/**
133+
* PsiType 转换为特定 Object
134+
*
135+
* @param type PsiType
136+
* @param level 当前转换层级。当递归层级过深时会导致stack overflow,这个参数用于控制递归层级
137+
* @param ignoreProperties 过滤的属性,这个参数只在这里使用 {@link POJO2JSONParser#parseField}
138+
* 用于过滤用户指定移除的属性
139+
* @param psiClassGenerics 当前PsiType的Class所拥有的泛型Map,Map中包含当前PsiClass所定义的 泛型 和 泛型对应的用户指定类型 (E=CustomObject)
140+
* 并在解析当前PsiClass所包含的Field时,尝试获取这个Field所定义的泛型Map,然后传入下一层
141+
* @return JSON Value所期望的Object
142+
*/
143+
public Object parseFieldValueType(PsiType type,
144+
int level,
145+
List<String> ignoreProperties,
146+
Map<String, PsiType> psiClassGenerics) {
147+
148+
level = level + 1;
149+
150+
if (type instanceof PsiPrimitiveType) { //primitive Type
151+
152+
return getPrimitiveTypeValue(type);
153+
154+
} else if (type instanceof PsiArrayType) { //array type
155+
156+
PsiType deepType = type.getDeepComponentType();
157+
Object obj = parseFieldValueType(deepType, level, ignoreProperties, getPsiClassGenerics(deepType));
158+
return obj != null ? Collections.singletonList(obj) : new ArrayList<>();
159+
160+
} else { //reference Type
161+
162+
PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(type);
163+
164+
if (psiClass == null) {
165+
return new LinkedHashMap<>();
166+
}
167+
168+
if (psiClass.isEnum()) { // enum
169+
170+
return this.getFakeValue(new EnumType(psiClass));
171+
172+
} else {
173+
174+
List<String> fieldTypeNames = new ArrayList<>();
175+
176+
fieldTypeNames.add(psiClass.getName());
177+
fieldTypeNames.addAll(Arrays.stream(psiClass.getSupers())
178+
.map(PsiClass::getName).collect(Collectors.toList()));
179+
180+
boolean iterable = fieldTypeNames.stream().anyMatch(iterableTypes::contains);
181+
182+
if (iterable) {// Iterable List<Test<String>>
183+
184+
PsiType deepType = PsiUtil.extractIterableTypeParameter(type, false);
185+
Object obj = parseFieldValueType(deepType, level, ignoreProperties, getPsiClassGenerics(deepType));
186+
return obj != null ? Collections.singletonList(obj) : new ArrayList<>();
187+
188+
} else { // Object Test<String,String>
189+
190+
List<String> retain = new ArrayList<>(fieldTypeNames);
191+
retain.retainAll(specifyTypes.keySet());
192+
if (!retain.isEmpty()) {
193+
return this.getFakeValue(specifyTypes.get(retain.get(0)));
194+
} else {
195+
196+
if (level > 500) {
197+
throw new ParseException("This class reference level exceeds maximum limit or has nested references!");
198+
}
199+
200+
PsiType deepType = psiClassGenerics.get(psiClass.getName());
201+
if (deepType != null) {
202+
return parseFieldValueType(deepType, level, ignoreProperties, getPsiClassGenerics(deepType));
203+
}
204+
205+
return parseClass(psiClass, level, ignoreProperties, getPsiClassGenerics(type));
206+
}
207+
}
208+
}
209+
}
210+
}
211+
212+
private Map<String, PsiType> getPsiClassGenerics(PsiType type) {
213+
PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(type);
214+
if (psiClass != null) {
215+
return Arrays.stream(psiClass.getTypeParameters())
216+
.collect(Collectors.toMap(NavigationItem::getName, p -> PsiUtil.substituteTypeParameter(type, psiClass, p.getIndex(), false)));
217+
}
218+
return new HashMap<>();
219+
}
220+
221+
public Object getPrimitiveTypeValue(PsiType type) {
222+
switch (type.getCanonicalText()) {
223+
case "boolean":
224+
return this.getFakeValue(specifyTypes.get("Boolean"));
225+
case "byte":
226+
case "short":
227+
case "int":
228+
case "long":
229+
return this.getFakeValue(specifyTypes.get("Number"));
230+
case "float":
231+
case "double":
232+
return this.getFakeValue(specifyTypes.get("BigDecimal"));
233+
case "char":
234+
return this.getFakeValue(specifyTypes.get("Character"));
235+
default:
236+
return null;
237+
}
238+
}
239+
240+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.github.linyimin.plugin.pojo2json;
2+
3+
/**
4+
* @author banzhe
5+
* @date 2022/11/21 21:13
6+
**/
7+
public class POJO2JSONParserFactory {
8+
public static final POJO2JSONParser DEFAULT_POJO_2_JSON_PARSER = new DefaultPOJO2JSONParser();
9+
public static final POJO2JSONParser RANDOM_POJO_2_JSON_PARSER = new RandomPOJO2JSONParser();
10+
}

0 commit comments

Comments
 (0)