✨ json字符串生成java实体类
parent
826062dcef
commit
9ae0250410
@ -0,0 +1,26 @@
|
|||||||
|
package org.alis.generator.domain.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lc
|
||||||
|
* @date 2023/11/22 16:55
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Content {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件文本
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输出的path
|
||||||
|
*/
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 源配置
|
||||||
|
*/
|
||||||
|
private String source;
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package org.alis.generator.domain.model;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lc
|
||||||
|
* @date 2023/11/22 16:58
|
||||||
|
*/
|
||||||
|
public class ContextConfig extends Properties {
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return this.getProperty("type");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.put("type", type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setSource(String source) {
|
||||||
|
this.put("source", source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSource() {
|
||||||
|
return this.getProperty("source");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPackagePath(String packagePath) {
|
||||||
|
this.put("packagePath", packagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPackagePath() {
|
||||||
|
return this.getProperty("packagePath", "org.alis.exam");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClassName(String className) {
|
||||||
|
this.put("className", className);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassName() {
|
||||||
|
return this.getProperty("className", "Example");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(String author) {
|
||||||
|
this.put("author", author);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return this.getProperty("author", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.alis.generator.domain.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lc
|
||||||
|
* @date 2023/11/22 18:39
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class JsonNode {
|
||||||
|
private String name;
|
||||||
|
private String alias;
|
||||||
|
private String type;
|
||||||
|
private String absolutePath;
|
||||||
|
private List<JsonNode> nodes;
|
||||||
|
private Boolean arrayFlag=Boolean.FALSE;
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package org.alis.generator.factory;
|
||||||
|
|
||||||
|
import org.alis.generator.domain.model.Content;
|
||||||
|
import org.alis.generator.domain.model.ContextConfig;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件生成类
|
||||||
|
*
|
||||||
|
* @author lc
|
||||||
|
* @date 2023/11/22 16:20
|
||||||
|
*/
|
||||||
|
public interface Generator {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心生成接口
|
||||||
|
*
|
||||||
|
* @param prop 配置项
|
||||||
|
* @return 实现
|
||||||
|
*/
|
||||||
|
Content generator(ContextConfig prop);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
package org.alis.generator.factory;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import org.alis.generator.domain.model.Content;
|
||||||
|
import org.alis.generator.domain.model.ContextConfig;
|
||||||
|
import org.alis.generator.domain.model.JsonNode;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lc
|
||||||
|
* @date 2023/11/22 17:01
|
||||||
|
*/
|
||||||
|
public class JsonGenerator implements Generator {
|
||||||
|
@Override
|
||||||
|
public Content generator(ContextConfig prop) {
|
||||||
|
String source = prop.getSource().trim();
|
||||||
|
if (!StringUtils.hasLength(source)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JSONObject jsonObject;
|
||||||
|
// 翻译source
|
||||||
|
if (StringUtils.startsWithIgnoreCase(source, "[")) {
|
||||||
|
// 如果是数组 只会取第一个对象
|
||||||
|
JSONArray array = JSONUtil.parseArray(source);
|
||||||
|
jsonObject = JSONUtil.parseObj(array.get(0));
|
||||||
|
} else {
|
||||||
|
jsonObject = JSONUtil.parseObj(source);
|
||||||
|
}
|
||||||
|
// 使用组合模式
|
||||||
|
List<JsonNode> fieldNodes = new ArrayList<>();
|
||||||
|
// 匿名内部类
|
||||||
|
List<JsonNode> classNodes = new ArrayList<>();
|
||||||
|
|
||||||
|
dealMap(jsonObject, fieldNodes, classNodes);
|
||||||
|
|
||||||
|
// merge删除对应的类
|
||||||
|
Map<String, String> merge = merge(classNodes);
|
||||||
|
|
||||||
|
// 生成class 文件
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
// 包路径
|
||||||
|
builder.append("package ").append(prop.getPackagePath()).append(";").append("\n\n");
|
||||||
|
// 注解的包
|
||||||
|
builder.append("import lombok.Data;").append("\n");
|
||||||
|
// 导入所有的包
|
||||||
|
List<String> importList = new ArrayList<>();
|
||||||
|
fillAllType(fieldNodes, importList);
|
||||||
|
importList.stream().filter(Objects::nonNull).distinct().forEach(path -> builder.append("import ").append(path).append(";").append("\n\n"));
|
||||||
|
|
||||||
|
// 注解信息
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
String localDate = now.toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||||
|
String localTime = now.toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm"));
|
||||||
|
String author = "/**\n * @author {0}\n * @date {1} {2}\n **/";
|
||||||
|
String format = MessageFormat.format(author, prop.getAuthor(), localDate, localTime);
|
||||||
|
builder.append(format).append("\n");
|
||||||
|
// 类名
|
||||||
|
builder.append("@Data").append("\n");
|
||||||
|
builder.append("public class ").append(prop.getClassName()).append("{\n");
|
||||||
|
|
||||||
|
// 构造函数
|
||||||
|
builder.append(" ").append("public ").append(prop.getClassName()).append("(){}\n");
|
||||||
|
|
||||||
|
// 生成属性
|
||||||
|
fieldNodes.forEach(node -> builder.append(" ").append("private ").append(merge.getOrDefault(node.getType(), node.getType())).append(" ").append(node.getName()).append(";\n"));
|
||||||
|
|
||||||
|
// 生成静态属性类
|
||||||
|
classNodes.forEach(clazzNode -> {
|
||||||
|
builder.append(" ").append("@Data").append("\n");
|
||||||
|
builder.append(" ").append("public static class ").append(clazzNode.getAlias()).append("{\n");
|
||||||
|
List<JsonNode> files = clazzNode.getNodes();
|
||||||
|
files.forEach(node -> builder.append(" ").append(" ").append("private ").append(node.getType()).append(" ").append(node.getName()).append(";\n"));
|
||||||
|
builder.append(" ").append("}\n");
|
||||||
|
});
|
||||||
|
builder.append("}\n");
|
||||||
|
|
||||||
|
|
||||||
|
Content content = new Content();
|
||||||
|
content.setPath(prop.getPackagePath());
|
||||||
|
content.setSource(prop.getSource());
|
||||||
|
content.setContent(builder.toString());
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void dealMap(JSONObject jsonObject, List<JsonNode> fields, List<JsonNode> classNodes) {
|
||||||
|
for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
|
||||||
|
Object value = entry.getValue();
|
||||||
|
String name = entry.getKey();
|
||||||
|
JsonNode node = new JsonNode();
|
||||||
|
node.setAlias(name);
|
||||||
|
node.setName(name);
|
||||||
|
node.setType(value.getClass().getSimpleName());
|
||||||
|
node.setAbsolutePath(value.getClass().getName());
|
||||||
|
List<JsonNode> nodes = new ArrayList<>();
|
||||||
|
|
||||||
|
if (value instanceof JSONObject) {
|
||||||
|
String className = upFirstChar(name) + "DTO";
|
||||||
|
node.setType(className);
|
||||||
|
node.setAlias(className);
|
||||||
|
classNodes.add(node);
|
||||||
|
node.setAbsolutePath(null);
|
||||||
|
dealMap((JSONObject) value, nodes, classNodes);
|
||||||
|
} else if (value instanceof JSONArray) {
|
||||||
|
node.setAbsolutePath(null);
|
||||||
|
node.setAbsolutePath("java.util.List");
|
||||||
|
JSONArray jsonArray = (JSONArray) value;
|
||||||
|
node.setArrayFlag(Boolean.TRUE);
|
||||||
|
if (CollectionUtils.isEmpty(jsonArray)) {
|
||||||
|
node.setType("List<Object>");
|
||||||
|
} else {
|
||||||
|
Object arrayModel = jsonArray.get(0);
|
||||||
|
if (arrayModel instanceof JSONObject) {
|
||||||
|
String className = upFirstChar(name) + "DTO";
|
||||||
|
node.setType("List<" + className + ">");
|
||||||
|
node.setAlias(className);
|
||||||
|
classNodes.add(node);
|
||||||
|
dealMap(JSONUtil.parseObj(jsonArray.get(0)), nodes, classNodes);
|
||||||
|
} else {
|
||||||
|
node.setType("List<" + arrayModel.getClass().getSimpleName() + ">");
|
||||||
|
node.setAlias(name);
|
||||||
|
// node.setAbsolutePath(arrayModel.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
node.setNodes(nodes);
|
||||||
|
fields.add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void fillAllType(List<JsonNode> jsonNodes, List<String> typeList) {
|
||||||
|
if (CollectionUtils.isEmpty(jsonNodes)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (JsonNode jsonNode : jsonNodes) {
|
||||||
|
typeList.add(jsonNode.getAbsolutePath());
|
||||||
|
fillAllType(jsonNode.getNodes(), typeList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String upFirstChar(String name) {
|
||||||
|
String first = name.substring(0, 1);
|
||||||
|
return name.replaceFirst(first, first.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Map<String, String> merge(List<JsonNode> classNodes) {
|
||||||
|
Map<String, String> mapping = new HashMap<>();
|
||||||
|
Map<Integer, String> hashTable = new HashMap<>();
|
||||||
|
Iterator<JsonNode> iterator = classNodes.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
JsonNode next = iterator.next();
|
||||||
|
int hash = next.getNodes().stream().map(JsonNode::getName).sorted(String::compareTo)
|
||||||
|
.collect(Collectors.joining()).hashCode();
|
||||||
|
// 如果存在
|
||||||
|
if (hashTable.containsKey(hash)) {
|
||||||
|
mapping.put(next.getType(), hashTable.get(hash));
|
||||||
|
if (Boolean.TRUE.equals(next.getArrayFlag())) {
|
||||||
|
mapping.put(next.getType(), "List<" + hashTable.get(hash) + ">");
|
||||||
|
}
|
||||||
|
iterator.remove();
|
||||||
|
} else {
|
||||||
|
hashTable.put(hash, next.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果遇到名称相同的 直接组合成大对象
|
||||||
|
Iterator<JsonNode> duplicate = classNodes.iterator();
|
||||||
|
Map<String, JsonNode> duplicateMap = new HashMap<>();
|
||||||
|
while (duplicate.hasNext()) {
|
||||||
|
JsonNode next = duplicate.next();
|
||||||
|
if (duplicateMap.containsKey(next.getType())) {
|
||||||
|
duplicate.remove();
|
||||||
|
List<JsonNode> nodes = duplicateMap.get(next.getType()).getNodes();
|
||||||
|
Set<String> collect = nodes.stream().map(JsonNode::getName).collect(Collectors.toSet());
|
||||||
|
next.getNodes().stream().filter(no -> !collect.contains(no.getName())).forEach(nodes::add);
|
||||||
|
} else {
|
||||||
|
duplicateMap.put(next.getType(), next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package org.alis.generator;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import java.lang.String;
|
||||||
|
|
||||||
|
import java.lang.Integer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author robin
|
||||||
|
* @date 2023-11-23 18:31
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
public class Example{
|
||||||
|
public Example(){}
|
||||||
|
private String userName;
|
||||||
|
private Integer userId;
|
||||||
|
private Integer age;
|
||||||
|
private ExtDTO ext;
|
||||||
|
private List<BirdDTO> extOne;
|
||||||
|
private List<ExtTwoDTO> extTwo;
|
||||||
|
@Data
|
||||||
|
public static class ExtDTO{
|
||||||
|
private String idCard;
|
||||||
|
private BirdDTO bird;
|
||||||
|
}
|
||||||
|
@Data
|
||||||
|
public static class BirdDTO{
|
||||||
|
private String idCard;
|
||||||
|
}
|
||||||
|
@Data
|
||||||
|
public static class ExtTwoDTO{
|
||||||
|
private Integer mode;
|
||||||
|
private List<Integer> x;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package org.alis.generator;
|
||||||
|
|
||||||
|
import org.alis.generator.domain.model.Content;
|
||||||
|
import org.alis.generator.domain.model.ContextConfig;
|
||||||
|
import org.alis.generator.factory.JsonGenerator;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
|
||||||
|
class TestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGeneratorJson() {
|
||||||
|
ContextConfig contextConfig = new ContextConfig();
|
||||||
|
String str = "{\n" +
|
||||||
|
" \"userName\": \"username\",\n" +
|
||||||
|
" \"userId\": 1,\n" +
|
||||||
|
" \"age\": 1,\n" +
|
||||||
|
" \"ext\": {\n" +
|
||||||
|
" \"idCard\": \"idCard\",\n" +
|
||||||
|
" \"bird\":{\n" +
|
||||||
|
" \"idCard\":\"idCard\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"extOne\": [{\n" +
|
||||||
|
" \"idCard\": \"idCard\"\n" +
|
||||||
|
" }],\n" +
|
||||||
|
" \"extTwo\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"mode\": 1,\n" +
|
||||||
|
" \"x\": [1\n" +
|
||||||
|
" ]\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
"}";
|
||||||
|
contextConfig.setSource(str);
|
||||||
|
contextConfig.setType("json");
|
||||||
|
contextConfig.setAuthor("robin");
|
||||||
|
contextConfig.setPackagePath("org.alis.generator");
|
||||||
|
JsonGenerator jsonGenerator = new JsonGenerator();
|
||||||
|
Content generator = jsonGenerator.generator(contextConfig);
|
||||||
|
try (FileOutputStream outputStream = new FileOutputStream("src/test/java/org/alis/generator/Example.java")) {
|
||||||
|
outputStream.write(generator.getContent().getBytes(StandardCharsets.UTF_8));
|
||||||
|
outputStream.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue