Skip to content

Commit 530a2de

Browse files
committed
fix: unexpected error when merging java files.
1 parent 421a341 commit 530a2de

File tree

5 files changed

+187
-93
lines changed

5 files changed

+187
-93
lines changed

src/main/java/com/spawpaw/mybatis/generator/gui/ProjectConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public class ProjectConfig {
5757
@ExportToTab(tabName = SHORTCUT, index = 10)
5858
@ExportToTab(tabName = tabs.BASIC_SETTINGS, index = 1)
5959
@Config(bundle = "project.overwrite", type = ConfigType.CheckBox)
60-
public SimpleBooleanProperty overwrite = new SimpleBooleanProperty(false);
60+
public SimpleBooleanProperty overwrite = new SimpleBooleanProperty(true);
6161

6262

6363
/****DAO层配置******************************************************************************************************/

src/main/java/com/spawpaw/mybatis/generator/gui/util/MyShellCallback.java

Lines changed: 179 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
import com.github.javaparser.ast.ImportDeclaration;
66
import com.github.javaparser.ast.Node;
77
import com.github.javaparser.ast.NodeList;
8-
import com.github.javaparser.ast.body.FieldDeclaration;
9-
import com.github.javaparser.ast.body.MethodDeclaration;
10-
import com.github.javaparser.ast.body.TypeDeclaration;
8+
import com.github.javaparser.ast.body.*;
119
import org.mybatis.generator.api.ShellCallback;
1210
import org.mybatis.generator.config.MergeConstants;
1311
import org.mybatis.generator.exception.ShellException;
@@ -16,13 +14,12 @@
1614
import java.io.FileNotFoundException;
1715
import java.util.*;
1816

19-
import static org.mybatis.generator.api.dom.OutputUtilities.newLine;
2017
import static org.mybatis.generator.internal.util.messages.Messages.getString;
2118

2219
/**
2320
* Created By [email protected] 2018-04-15
2421
*
25-
* @author BenBenShang [email protected]
22+
* @author BenBenShang [email protected] 版权所有,盗用必究
2623
*/
2724
public class MyShellCallback implements ShellCallback {
2825

@@ -90,116 +87,210 @@ public String mergeJavaFile(String newFileSource,
9087
try {
9188
CompilationUnit newCompilationUnit = JavaParser.parse(newFileSource);
9289
CompilationUnit existingCompilationUnit = JavaParser.parse(existingFile);
93-
return mergerFile(newCompilationUnit, existingCompilationUnit);
90+
return mergeCompilationUnit(existingCompilationUnit, newCompilationUnit).toString();
9491
} catch (FileNotFoundException e) {
9592
throw new UnsupportedOperationException();
9693
}
9794
}
9895

99-
public String mergerFile(CompilationUnit newCompilationUnit, CompilationUnit existingCompilationUnit) {
96+
/**
97+
* 合并可编译单元(即合并两个Java文件)
98+
*/
99+
private CompilationUnit mergeCompilationUnit(CompilationUnit oldCompilationUnit, CompilationUnit newCompilationUnit) {
100+
CompilationUnit finalCompilationUnit = new CompilationUnit();
100101

101-
System.out.println("合并java代码...");
102-
StringBuilder sb = new StringBuilder(newCompilationUnit.getPackageDeclaration().get().toString());
103-
newCompilationUnit.removePackageDeclaration();
102+
//修改包名为新类的包名
103+
if (newCompilationUnit.getPackageDeclaration().isPresent())
104+
finalCompilationUnit.setPackageDeclaration(newCompilationUnit.getPackageDeclaration().get());
104105

105-
//合并imports
106-
NodeList<ImportDeclaration> imports = newCompilationUnit.getImports();
107-
imports.addAll(existingCompilationUnit.getImports());
106+
//合并import
108107
Set<ImportDeclaration> importSet = new HashSet<>();
109-
importSet.addAll(imports);
108+
importSet.addAll(oldCompilationUnit.getImports());
109+
importSet.addAll(newCompilationUnit.getImports());
110110

111-
NodeList<ImportDeclaration> newImports = new NodeList<>();
112-
newImports.addAll(importSet);
113-
newCompilationUnit.setImports(newImports);
114-
for (ImportDeclaration i : newCompilationUnit.getImports()) {
115-
sb.append(i.toString());
111+
NodeList<ImportDeclaration> imports = new NodeList<>();
112+
imports.addAll(importSet);
113+
finalCompilationUnit.setImports(imports);
114+
115+
//合并topLevelClass
116+
finalCompilationUnit.setTypes(mergeTypes(oldCompilationUnit.getTypes(), newCompilationUnit.getTypes()));
117+
118+
119+
return finalCompilationUnit;
120+
}
121+
122+
/**
123+
* 合并Java类(一个Java文件可能有多个类)
124+
*/
125+
private NodeList<TypeDeclaration<?>> mergeTypes(NodeList<TypeDeclaration<?>> oldTypes, NodeList<TypeDeclaration<?>> newTypes) {
126+
Map<String, TypeDeclaration<?>> finalTypes = new Hashtable<>();
127+
for (TypeDeclaration<?> newType : newTypes) {
128+
finalTypes.put(newType.getNameAsString(), newType);
116129
}
117-
newLine(sb);
118-
NodeList<TypeDeclaration<?>> types = newCompilationUnit.getTypes();
119-
NodeList<TypeDeclaration<?>> oldTypes = existingCompilationUnit.getTypes();
120-
121-
for (int i = 0; i < types.size(); i++) {
122-
//截取Class
123-
String classNameInfo = types.get(i).toString().substring(0, types.get(i).toString().indexOf("{") + 1);
124-
sb.append(classNameInfo);
125-
newLine(sb);
126-
newLine(sb);
127-
128-
//合并fields
129-
Map<String, FieldDeclaration> newFieldsToWrite = new Hashtable<>();//将要写入的
130-
131-
for (FieldDeclaration fieldDeclaration : oldTypes.get(i).getFields()) {//之前存在的
132-
boolean flag = true;
133-
for (String tag : MergeConstants.OLD_ELEMENT_TAGS)
134-
if (fieldDeclaration.toString().contains(tag)) {
135-
flag = false;
136-
break;
137-
}
138-
if (flag) {//如果该字段不是自动生成的,则重新加入
139-
newFieldsToWrite.put(fieldDeclaration.getVariables().toString(), fieldDeclaration);
140-
}
141-
}
142-
for (FieldDeclaration fieldDeclaration : types.get(i).getFields()) {//新生成的
143-
newFieldsToWrite.put(fieldDeclaration.getVariables().toString(), fieldDeclaration);
144-
}
145-
for (FieldDeclaration f : newFieldsToWrite.values()) {
146-
sb.append("\t" + f.toString());
147-
newLine(sb);
148-
newLine(sb);
130+
131+
for (TypeDeclaration<?> oldType : oldTypes) {//对于旧CompilationUnit中的每一个TopLevelClass
132+
if (finalTypes.containsKey(oldType.getNameAsString())) {//如果存在同名类则合并
133+
finalTypes.put(oldType.getNameAsString(), mergeType(oldType, finalTypes.get(oldType.getNameAsString())));
134+
} else if (!isGeneratedNode(oldType)) {//如果不存在同名类且不是生成的类
135+
finalTypes.put(oldType.getNameAsString(), mergeType(oldType, finalTypes.get(oldType.getNameAsString())));
149136
}
137+
}
150138

151-
//合并methods
152-
List<MethodDeclaration> methods = types.get(i).getMethods();
153-
List<MethodDeclaration> existingMethods = oldTypes.get(i).getMethods();
154-
List<String> newMethods = new ArrayList<String>();
139+
return new NodeList<>(finalTypes.values());
140+
}
155141

156-
for (MethodDeclaration f : methods) {
157-
String res = f.toString().replaceAll("\r\n", "\r\n ");
158-
sb.append(" " + res);
159-
newLine(sb);
160-
newLine(sb);
142+
/**
143+
* 合并两个同名类
144+
*/
145+
private TypeDeclaration<?> mergeType(TypeDeclaration<?> oldType, TypeDeclaration<?> newType) {
146+
TypeDeclaration<?> finalTypeDeclaration;
147+
if (newType.isClassOrInterfaceDeclaration() && oldType.isClassOrInterfaceDeclaration()) {
148+
finalTypeDeclaration = new ClassOrInterfaceDeclaration();
149+
ClassOrInterfaceDeclaration oldClass = oldType.asClassOrInterfaceDeclaration();
150+
ClassOrInterfaceDeclaration newClass = newType.asClassOrInterfaceDeclaration();
151+
152+
//设置修饰符及类名
153+
finalTypeDeclaration.setModifiers(newClass.getModifiers());//修饰符
154+
finalTypeDeclaration.asClassOrInterfaceDeclaration().setInterface(//是否为接口
155+
newClass.isInterface()
156+
);
157+
finalTypeDeclaration.setName(newClass.getName());//类名
158+
finalTypeDeclaration.asClassOrInterfaceDeclaration().setExtendedTypes(newClass.getExtendedTypes());//继承的类
159+
finalTypeDeclaration.asClassOrInterfaceDeclaration().setImplementedTypes(newClass.getImplementedTypes());//继承的接口
160+
finalTypeDeclaration.asClassOrInterfaceDeclaration().setAnnotations(newClass.getAnnotations());//注解
161+
if (newClass.getComment().isPresent())//注释
162+
finalTypeDeclaration.asClassOrInterfaceDeclaration().setComment(newClass.getComment().get());
163+
164+
165+
//合并initializer(possibly static)
166+
//保留所有旧类中的initializer(MBG并不会生成initializer,不考虑保留旧initializer会出现的问题)
167+
for (BodyDeclaration<?> bodyDeclaration : oldClass.getMembers())
168+
if (bodyDeclaration.isInitializerDeclaration())
169+
finalTypeDeclaration.addMember(bodyDeclaration);
170+
171+
//合并构造函数
172+
for (ConstructorDeclaration constructorDeclaration : mergeConstructors(oldClass.getConstructors(), newClass.getConstructors())) {
173+
finalTypeDeclaration.addMember(constructorDeclaration);
161174
}
162175

163-
for (MethodDeclaration m : methods) {
164-
newMethods.add(m.getName().toString());
176+
//合并Field
177+
for (FieldDeclaration fieldDeclaration : mergeFields(oldClass.getFields(), newClass.getFields())) {
178+
finalTypeDeclaration.addMember(fieldDeclaration);
165179
}
166-
newMethods.add("toString");
167-
newMethods.add("hashCode");
168-
newMethods.add("equals");
169180

170-
for (MethodDeclaration m : existingMethods) {
171-
if (newMethods.contains(m.getName().toString())) {
172-
continue;
173-
}
181+
//合并Method
182+
for (MethodDeclaration methodDeclaration : mergeMethods(oldClass.getMethods(), newClass.getMethods())) {
183+
finalTypeDeclaration.addMember(methodDeclaration);
184+
}
174185

175-
boolean flag = true;
176-
for (String tag : MergeConstants.OLD_ELEMENT_TAGS) {
177-
if (m.toString().contains(tag)) {
178-
flag = false;
179-
break;
180-
}
186+
//合并内部类(class/enum/interface)
187+
NodeList<TypeDeclaration<?>> oldTypes = new NodeList<>();
188+
NodeList<TypeDeclaration<?>> newTypes = new NodeList<>();
189+
for (BodyDeclaration<?> bodyDeclaration : oldClass.getMembers()) {
190+
if (bodyDeclaration.isClassOrInterfaceDeclaration() ||
191+
bodyDeclaration.isEnumDeclaration() ||
192+
bodyDeclaration.isAnnotationDeclaration()) {
193+
oldTypes.add(bodyDeclaration.asTypeDeclaration());
194+
// System.out.println("旧内部类:" + bodyDeclaration.asTypeDeclaration().getNameAsString());
181195
}
182-
if (flag) {
183-
String res = m.toString().replaceAll("\r\n", "\r\n ");
184-
sb.append(" " + res);
185-
newLine(sb);
186-
newLine(sb);
196+
}
197+
for (BodyDeclaration<?> bodyDeclaration : newClass.getMembers()) {
198+
if (bodyDeclaration.isClassOrInterfaceDeclaration() ||
199+
bodyDeclaration.isEnumDeclaration() ||
200+
bodyDeclaration.isAnnotationDeclaration()) {
201+
newTypes.add(bodyDeclaration.asTypeDeclaration());
202+
// System.out.println("新内部类:" + bodyDeclaration.asTypeDeclaration().getNameAsString());
203+
// System.out.println("新内部类修饰符:" + bodyDeclaration.asTypeDeclaration().getModifiers());
187204
}
188205
}
206+
for (TypeDeclaration<?> typeDeclaration : mergeTypes(oldTypes, newTypes)) {
207+
finalTypeDeclaration.addMember(typeDeclaration);
208+
}
189209

190-
//判断是否有内部类
191-
types.get(i).getChildNodes();
192-
for (Node n : types.get(i).getChildNodes()) {
193-
if (n.toString().contains("static class") || n.toString().contains("public enum Column")) {
194-
String res = n.toString().replaceAll("\r\n", "\r\n ");
195-
sb.append(" " + res);
196-
}
210+
return finalTypeDeclaration;
211+
} else if (newType.isEnumDeclaration() && oldType.isEnumDeclaration()) {
212+
finalTypeDeclaration = new EnumDeclaration();
213+
return newType;
214+
} else if (newType.isAnnotationDeclaration() && oldType.isAnnotationDeclaration()) {
215+
finalTypeDeclaration = new AnnotationDeclaration();
216+
return newType;
217+
} else {
218+
throw new RuntimeException(String.format("新类和旧类的类型不一样,无法判断该以何种方式合并,请删除旧文件或者将旧文件更改为正确的类型 (类名:%s)", newType.getNameAsString()));
219+
// return newType;
220+
}
221+
}
222+
223+
/**
224+
* 合并构造函数
225+
*/
226+
private List<ConstructorDeclaration> mergeConstructors(List<ConstructorDeclaration> oldConstructors, List<ConstructorDeclaration> newConstructors) {
227+
228+
Map<String, ConstructorDeclaration> constructorDeclarationMap = new Hashtable<>();//
229+
for (ConstructorDeclaration newConstructor : newConstructors) {
230+
if (!constructorDeclarationMap.containsKey(newConstructor.getDeclarationAsString(false, false, false))
231+
&& !isGeneratedNode(newConstructor)) {//如果新生成的类中不包含该构造函数且该构造函数不是自动生成的
232+
constructorDeclarationMap.put(newConstructor.getDeclarationAsString(false, false, false), newConstructor);
197233
}
234+
}
235+
for (ConstructorDeclaration oldConstructor : oldConstructors) {
236+
constructorDeclarationMap.put(oldConstructor.getDeclarationAsString(false, false, false), oldConstructor);
237+
// System.out.println("构造函数:" + oldConstructor.getDeclarationAsString(true, true, false));
238+
}
239+
return new ArrayList<>(constructorDeclarationMap.values());
240+
}
198241

242+
/**
243+
* 合并字段
244+
*/
245+
private List<FieldDeclaration> mergeFields(List<FieldDeclaration> oldFields, List<FieldDeclaration> newFields) {
246+
Map<String, FieldDeclaration> fieldDeclarationMap = new Hashtable<>();//
247+
for (FieldDeclaration newField : newFields) {
248+
//mbg生成的一个变量声明不会包含多个变量
249+
String key = "";
250+
for (VariableDeclarator variableDeclarator : newField.getVariables()) {
251+
key += variableDeclarator.getNameAsString() + ",";
252+
}
253+
fieldDeclarationMap.put(key, newField);
254+
}
255+
for (FieldDeclaration oldField : oldFields) {
256+
String key = "";
257+
for (VariableDeclarator variableDeclarator : oldField.getVariables()) {
258+
key += variableDeclarator.getNameAsString() + ",";
259+
}
260+
if (!fieldDeclarationMap.containsKey(key) && !isGeneratedNode(oldField)) {
261+
fieldDeclarationMap.put(key, oldField);
262+
}
199263
}
264+
return new ArrayList<>(fieldDeclarationMap.values());
265+
}
200266

201-
return sb.append(System.getProperty("line.separator") + "}").toString();
267+
/**
268+
* 合并方法
269+
*/
270+
private List<MethodDeclaration> mergeMethods(List<MethodDeclaration> oldMethods, List<MethodDeclaration> newMethods) {
271+
Map<String, MethodDeclaration> methodDeclarationMap = new Hashtable<>();
272+
for (MethodDeclaration newMethod : newMethods) {
273+
methodDeclarationMap.put(newMethod.getDeclarationAsString(false, false, false), newMethod);
274+
}
275+
for (MethodDeclaration oldMethod : oldMethods) {
276+
if (!methodDeclarationMap.containsKey(oldMethod.getDeclarationAsString(false, false, false)) && !isGeneratedNode(oldMethod)) {
277+
methodDeclarationMap.put(oldMethod.getDeclarationAsString(false, false, false), oldMethod);
278+
}
279+
}
280+
return new ArrayList<>(methodDeclarationMap.values());
202281
}
203282

283+
284+
/**
285+
* 判断是否为自动生成的节点(即注释中包含指定tag)
286+
*/
287+
private boolean isGeneratedNode(Node node) {
288+
for (String tag : MergeConstants.OLD_ELEMENT_TAGS) {
289+
if (node.getComment().toString().contains(tag)) {
290+
return true;
291+
}
292+
}
293+
return false;
294+
}
204295
}
205296

src/main/resources/i18n/locale.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,8 @@ project.trimStrings.helpText=This property is used to select whether MyBatis Gen
346346
##
347347

348348
project.overwrite.labelText=overwrite existing java file
349-
project.overwrite.helpText=if true, the old java file will be overwritten instead of being merged.
349+
project.overwrite.helpText=if true, the old java file will be overwritten instead of being merged.\n\
350+
if you meet problems when merging java files,please open this switch to overwrite the existing java file.
350351
##
351352

352353
project.enableCorrespondingTable.labelText=Add corresponding table info.

src/main/resources/i18n/locale_en.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,8 @@ project.trimStrings.helpText=This property is used to select whether MyBatis Gen
346346
##
347347

348348
project.overwrite.labelText=overwrite existing java file
349-
project.overwrite.helpText=if true, the old java file will be overwritten instead of being merged.
349+
project.overwrite.helpText=if true, the old java file will be overwritten instead of being merged.\n\
350+
if you meet problems when merging java files,please open this switch to overwrite the existing java file.
350351
##
351352

352353
project.enableCorrespondingTable.labelText=Add corresponding table info.

src/main/resources/i18n/locale_zh_CN.properties

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,10 @@ project.trimStrings.helpText=\u6B64\u914D\u7F6E\u51B3\u5B9A\u662F\u5426\u8BA9MBG
370370
\u8FD9\u4E2A\u914D\u7F6E\u5728\u4F60\u7684\u6570\u636E\u4EE5char\u800C\u4E0D\u662Fvarchar\u7C7B\u578B\u5B58\u50A8\u65F6\u53EF\u80FD\u4F1A\u6709\u7528
371371
##
372372

373-
project.overwrite.labelText=\u662F\u5426\u8986\u76D6\u539F\u6709java\u6587\u4EF6
373+
project.overwrite.labelText=\u662F\u5426\u8986\u76D6\u539F\u6709java\u6587\u4EF6(\u5982\u4E0D\u9009\u5219\u5408\u5E76)
374374
project.overwrite.helpText=\u5982\u679C\u52FE\u9009\uFF0C\u5C06\u4F1A\u8986\u76D6\u4E4B\u524D\u751F\u6210\u7684\u6587\u4EF6\uFF08\u76EE\u524D\u4EC5\u652F\u6301\u8986\u76D6Java\uFF09\n\
375-
\u5426\u5219\u5C06\u548C\u4E4B\u524D\u751F\u6210\u7684\u6587\u4EF6\u8FDB\u884C\u5408\u5E76\uFF0C\u6240\u6709\u6CA1\u6709\u6DFB\u52A0`@mbg.generated`\u6CE8\u91CA\u7684\u5B57\u6BB5\u6216\u65B9\u6CD5\u90FD\u5C06\u88AB\u4FDD\u7559
375+
\u5426\u5219\u5C06\u548C\u4E4B\u524D\u751F\u6210\u7684\u6587\u4EF6\u8FDB\u884C\u5408\u5E76\uFF0C\u6240\u6709\u6CA1\u6709\u6DFB\u52A0`@mbg.generated`\u6CE8\u91CA\u7684\u5B57\u6BB5\u6216\u65B9\u6CD5\u90FD\u5C06\u88AB\u4FDD\u7559\u3002\n\
376+
\u4F5C\u8005\u5728\u6D4B\u8BD5\u7684\u8FC7\u7A0B\u4E2D\u6CA1\u6709\u53D1\u73B0\u6B64\u9879\u529F\u80FD\u6709\u95EE\u9898\uFF0C\u5982\u679C\u60A8\u5728\u5408\u5E76Java\u6587\u4EF6\u540E\u9047\u5230\u4E86\u95EE\u9898\uFF0C\u8BF7\u5F00\u542F\u6B64\u9009\u9879\u4EE5\u8986\u76D6\u539F\u6709java\u6587\u4EF6\u3002
376377
##
377378

378379
project.enableCorrespondingTable.labelText=\u662F\u5426\u5728\u6CE8\u91CA\u4E2D\u6DFB\u52A0\u76F8\u5173\u8054\u7684\u8868\u7684\u4FE1\u606F

0 commit comments

Comments
 (0)