Skip to content

Commit 268af6d

Browse files
authored
Generator refactor (#9)
* Set proper method modifiers based on target class modifier * Refactor generators to return GenerationResult * shortenClassReferences only when Annotations added
1 parent cd3a0e4 commit 268af6d

14 files changed

+253
-81
lines changed

src/main/java/com/github/junkfactory/innerbuilder/JavaInnerBuilderHandler.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.github.junkfactory.innerbuilder.generators.PsiParams;
77
import com.github.junkfactory.innerbuilder.generators.Utils;
88
import com.github.junkfactory.innerbuilder.ui.JavaInnerBuilderOption;
9+
import com.github.junkfactory.innerbuilder.ui.JavaInnerBuilderOptionSelector;
910
import com.intellij.ide.util.PropertiesComponent;
1011
import com.intellij.lang.LanguageCodeInsightActionHandler;
1112
import com.intellij.openapi.application.ApplicationManager;
@@ -16,14 +17,13 @@
1617
import com.intellij.psi.JavaPsiFacade;
1718
import com.intellij.psi.PsiFile;
1819
import com.intellij.psi.PsiJavaFile;
20+
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
1921
import com.intellij.util.AstLoadingFilter;
2022
import org.jetbrains.annotations.NotNull;
2123

2224
import java.util.EnumSet;
2325
import java.util.Set;
2426

25-
import static com.github.junkfactory.innerbuilder.ui.JavaInnerBuilderOptionSelector.selectFieldsAndOptions;
26-
2727
class JavaInnerBuilderHandler implements LanguageCodeInsightActionHandler {
2828

2929
private static final GeneratorFactory generatorFactory = GeneratorFactory.create();
@@ -48,7 +48,7 @@ public boolean startInWriteAction() {
4848
}
4949

5050
private static boolean isApplicable(final PsiFile file, final Editor editor) {
51-
return FieldCollector.builder()
51+
return file instanceof PsiJavaFile && FieldCollector.builder()
5252
.file(file)
5353
.editor(editor)
5454
.build()
@@ -77,7 +77,11 @@ public void invoke(@NotNull final Project project, @NotNull final Editor editor,
7777
return;
7878
}
7979

80-
var selectedFields = selectFieldsAndOptions(existingFields, project);
80+
var optionsDialog = JavaInnerBuilderOptionSelector.builder()
81+
.project(project)
82+
.members(existingFields)
83+
.build();
84+
var selectedFields = optionsDialog.selectFieldsAndOptions();
8185
if (selectedFields.isEmpty()) {
8286
return;
8387
}
@@ -86,6 +90,7 @@ public void invoke(@NotNull final Project project, @NotNull final Editor editor,
8690
.file(file)
8791
.selectedFields(selectedFields)
8892
.factory(JavaPsiFacade.getElementFactory(project))
93+
.codeStyleManager(JavaCodeStyleManager.getInstance(project))
8994
.build();
9095
var generatorParams = GeneratorParams.builder()
9196
.project(project)

src/main/java/com/github/junkfactory/innerbuilder/generators/AbstractGenerator.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22

33
import com.intellij.psi.PsiClass;
44
import com.intellij.psi.PsiElement;
5+
import com.intellij.psi.PsiJavaFile;
56
import com.intellij.psi.PsiMethod;
7+
import com.intellij.psi.PsiType;
8+
import com.intellij.psi.util.PsiUtil;
69
import org.jetbrains.annotations.NonNls;
710
import org.jetbrains.annotations.NotNull;
811
import org.jetbrains.annotations.Nullable;
912

10-
abstract class AbstractGenerator implements Runnable {
13+
import java.util.Objects;
14+
15+
abstract class AbstractGenerator {
1116

1217
@NonNls
1318
static final String BUILDER_CLASS_NAME = "Builder";
@@ -19,6 +24,10 @@ abstract class AbstractGenerator implements Runnable {
1924
static final String EMPTY = "";
2025
@NonNls
2126
static final String SPACE = " ";
27+
@NonNls
28+
static final String THIS_DOT = "this.";
29+
@NonNls
30+
static final String RETURN_THIS = "return this;";
2231

2332
protected final GeneratorFactory generatorFactory;
2433
protected final GeneratorParams generatorParams;
@@ -49,6 +58,12 @@ protected PsiElement addMethod(@NotNull final PsiClass target, @Nullable final P
4958
return existingMethod;
5059
}
5160

61+
protected boolean addImport(PsiType psiType) {
62+
var psiClass = Objects.requireNonNull(PsiUtil.resolveClassInType(psiType),
63+
"Unable to resolve " + psiType.toString());
64+
return generatorParams.psi().codeStyleManager().addImport((PsiJavaFile) generatorParams.psi().file(), psiClass);
65+
}
66+
5267
private PsiMethod findConstructor(PsiClass target, PsiMethod newMethod) {
5368
for (var constructor : target.getConstructors()) {
5469
if (Utils.areParameterListsEqual(constructor.getParameterList(), newMethod.getParameterList())) {

src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderClassGenerator.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import com.intellij.psi.PsiModifier;
55
import com.intellij.psi.util.PsiUtil;
66

7-
class BuilderClassGenerator extends AbstractGenerator {
7+
class BuilderClassGenerator extends AbstractGenerator implements Generator {
88

99
private final BuilderClassParams builderClassParams;
1010

@@ -16,18 +16,18 @@ class BuilderClassGenerator extends AbstractGenerator {
1616
}
1717

1818
@Override
19-
public void run() {
19+
public GenerationResult generate() {
2020
//builder constructor
2121
var builderClass = builderClassParams.builderClass();
2222
var builderConstructor = generateBuilderConstructor();
2323
addMethod(builderClass, null, builderConstructor, false);
2424

2525
var fieldsGenerator = generatorFactory.createBuilderFieldsGenerator(generatorParams, builderClassParams);
26-
fieldsGenerator.run();
26+
fieldsGenerator.generate();
2727

2828
var methodsGenerator = generatorFactory.createBuilderMethodsGenerator(generatorParams,
2929
builderClassParams, fieldsGenerator);
30-
methodsGenerator.run();
30+
return methodsGenerator.generate();
3131
}
3232

3333
private PsiMethod generateBuilderConstructor() {

src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderFieldsGenerator.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ public List<PsiField> getFields() {
2727
}
2828

2929
@Override
30-
public void run() {
30+
public GenerationResult generate() {
3131
PsiField lastAddedField = null;
3232
for (var fieldMember : generatorParams.psi().selectedFields()) {
3333
lastAddedField = createOrUpdateField(builderClassParams.builderClass(), fieldMember, lastAddedField);
3434
fields.add(lastAddedField);
3535
}
3636
cleanupFields(builderClassParams.builderClass());
37+
return GenerationResult.NO_RESULT;
3738
}
3839

3940
private void cleanupFields(PsiClass builderClass) {
@@ -44,8 +45,8 @@ private void cleanupFields(PsiClass builderClass) {
4445
}
4546
}
4647

47-
private PsiField createOrUpdateField(final PsiClass builderClass, final PsiFieldMember member,
48-
@Nullable final PsiElement last) {
48+
private PsiField createOrUpdateField(PsiClass builderClass, PsiFieldMember member,
49+
@Nullable PsiElement last) {
4950
var psiFactory = generatorParams.psi().factory();
5051
var field = member.getElement();
5152
var fieldName = field.getName();

src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java

Lines changed: 90 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.github.junkfactory.innerbuilder.ui.JavaInnerBuilderOption;
44
import com.intellij.openapi.util.text.StringUtil;
5+
import com.intellij.psi.PsiClass;
56
import com.intellij.psi.PsiElement;
67
import com.intellij.psi.PsiField;
78
import com.intellij.psi.PsiMethod;
@@ -15,6 +16,9 @@ class BuilderMethodsGenerator extends AbstractGenerator implements MethodsGenera
1516

1617
private final BuilderClassParams builderClassParams;
1718
private final FieldsGenerator fieldsGenerator;
19+
private final GenerationResult generationResult;
20+
21+
private boolean isPublic;
1822

1923
BuilderMethodsGenerator(GeneratorFactory generatorFactory,
2024
GeneratorParams generatorParams,
@@ -23,11 +27,15 @@ class BuilderMethodsGenerator extends AbstractGenerator implements MethodsGenera
2327
super(generatorFactory, generatorParams);
2428
this.builderClassParams = builderClassParams;
2529
this.fieldsGenerator = fieldsGenerator;
30+
this.generationResult = new GenerationResult();
2631
}
2732

2833
@Override
29-
public void run() {
34+
public GenerationResult generate() {
3035
var builderClass = builderClassParams.builderClass();
36+
var targetClass = builderClassParams.targetClass();
37+
var targetModifierList = Objects.requireNonNull(targetClass.getModifierList());
38+
isPublic = targetModifierList.hasModifierProperty(PsiModifier.PUBLIC);
3139
PsiElement lastAddedElement = null;
3240
for (var field : fieldsGenerator.getFields()) {
3341
var setterMethod = generateFieldMethod(field);
@@ -41,8 +49,9 @@ public void run() {
4149
addMethod(builderClass, lastAddedElement, validateMethod, false);
4250
}
4351

44-
var buildMethod = generateBuildMethod();
52+
var buildMethod = generateBuildMethod(targetClass);
4553
addMethod(builderClass, null, buildMethod, builderClassParams.targetClass().isRecord());
54+
return generationResult;
4655
}
4756

4857
private PsiMethod generateValidateMethod() {
@@ -71,58 +80,108 @@ private PsiMethod generatePutToMap(PsiField field, PsiMethod fieldPutMethod) {
7180
//resolve the generic type of the map via the parameter type of the put method
7281
var param1 = Objects.requireNonNull(fieldPutMethod.getParameterList().getParameter(0));
7382
var param1Type = Utils.resolveGenericParameterType(field.getType(), param1);
83+
var importAdded = addImport(param1Type);
84+
7485
var param2 = Objects.requireNonNull(fieldPutMethod.getParameterList().getParameter(1));
7586
var param2Type = Utils.resolveGenericParameterType(field.getType(), param2);
87+
importAdded = addImport(param2Type) || importAdded;
88+
if (importAdded) {
89+
generationResult.set(GenerationResult.Code.IMPORTS_ADDED);
90+
}
7691

77-
//now build the put method
7892
var methodName = "putTo" + StringUtil.capitalize(field.getName());
79-
var methodText = """
80-
public %s %s(%s key, %s value) {
81-
this.%s.put(key, value);
82-
return this;
83-
}""".formatted(BUILDER_CLASS_NAME, methodName, param1Type.getPresentableText(),
84-
param2Type.getPresentableText(), field.getName());
93+
var methodText = new StringBuilder();
94+
if (isPublic) {
95+
methodText.append(PsiModifier.PUBLIC).append(' ');
96+
}
97+
methodText.append(BUILDER_CLASS_NAME)
98+
.append(' ')
99+
.append(methodName)
100+
.append('(')
101+
.append(param1Type.getPresentableText())
102+
.append(' ')
103+
.append(param1.getName().toLowerCase())
104+
.append(", ")
105+
.append(param2Type.getPresentableText())
106+
.append(' ')
107+
.append(param2.getName().toLowerCase())
108+
.append(") {")
109+
.append(THIS_DOT)
110+
.append(field.getName())
111+
.append(".put(")
112+
.append(param1.getName().toLowerCase())
113+
.append(", ")
114+
.append(param2.getName().toLowerCase())
115+
.append(");")
116+
.append(RETURN_THIS)
117+
.append('}');
85118
var psiElementFactory = generatorParams.psi().factory();
86-
return psiElementFactory.createMethodFromText(methodText, field);
119+
return psiElementFactory.createMethodFromText(methodText.toString(), field);
87120
}
88121

89122
private PsiMethod generateAddToCollection(PsiField field, PsiMethod fieldAddMethod) {
90123
//resolve the generic type of the collection via the parameter type of the add method
91124
var param = Objects.requireNonNull(fieldAddMethod.getParameterList().getParameter(0));
92125
var paramType = Utils.resolveGenericParameterType(field.getType(), param);
126+
if (addImport(paramType)) {
127+
generationResult.set(GenerationResult.Code.IMPORTS_ADDED);
128+
}
93129

94-
//now build the add method
95130
var methodName = "addTo" + StringUtil.capitalize(field.getName());
96-
var methodText = """
97-
public %s %s(%s %s) {
98-
this.%s.add(%s);
99-
return this;
100-
}""".formatted(BUILDER_CLASS_NAME, methodName, paramType.getPresentableText(),
101-
param.getName().toLowerCase(), field.getName(), param.getName());
131+
var methodText = new StringBuilder();
132+
if (isPublic) {
133+
methodText.append(PsiModifier.PUBLIC).append(' ');
134+
}
135+
methodText.append(BUILDER_CLASS_NAME)
136+
.append(' ')
137+
.append(methodName)
138+
.append('(')
139+
.append(paramType.getPresentableText())
140+
.append(' ')
141+
.append(param.getName().toLowerCase())
142+
.append(") {")
143+
.append(THIS_DOT)
144+
.append(field.getName())
145+
.append(".add(")
146+
.append(param.getName())
147+
.append(");")
148+
.append(RETURN_THIS)
149+
.append('}');
150+
102151
var psiElementFactory = generatorParams.psi().factory();
103-
return psiElementFactory.createMethodFromText(methodText, field);
152+
return psiElementFactory.createMethodFromText(methodText.toString(), field);
104153
}
105154

106155
private PsiMethod generateBuilderSetter(PsiField field) {
107156
var fieldType = field.getType();
108157
var fieldName = Utils.hasOneLetterPrefix(field.getName()) ?
109158
Character.toLowerCase(field.getName().charAt(1)) + field.getName().substring(2) : field.getName();
110159

111-
var methodText = """
112-
public %s %s(%s %s) {
113-
this.%s = %s;
114-
return this;
115-
}""".formatted(BUILDER_CLASS_NAME, fieldName, fieldType.getPresentableText(),
116-
fieldName, field.getName(), fieldName);
160+
var methodText = new StringBuilder();
161+
if (isPublic) {
162+
methodText.append(PsiModifier.PUBLIC).append(' ');
163+
}
164+
methodText.append(BUILDER_CLASS_NAME)
165+
.append(' ')
166+
.append(fieldName)
167+
.append('(')
168+
.append(fieldType.getPresentableText())
169+
.append(' ')
170+
.append(fieldName)
171+
.append(") {")
172+
.append(THIS_DOT)
173+
.append(field.getName())
174+
.append(" = ")
175+
.append(fieldName)
176+
.append(";")
177+
.append(RETURN_THIS)
178+
.append('}');
179+
117180
var psiElementFactory = generatorParams.psi().factory();
118-
return psiElementFactory.createMethodFromText(methodText, field);
181+
return psiElementFactory.createMethodFromText(methodText.toString(), field);
119182
}
120183

121-
private PsiMethod generateBuildMethod() {
122-
var targetClass = builderClassParams.targetClass();
123-
var targetModifierList = Objects.requireNonNull(targetClass.getModifierList());
124-
boolean isPublic = targetModifierList.hasModifierProperty(PsiModifier.PUBLIC);
125-
184+
private PsiMethod generateBuildMethod(PsiClass targetClass) {
126185
var buildMethod = new StringBuilder()
127186
.append(isPublic ? PsiModifier.PUBLIC : EMPTY)
128187
.append(isPublic ? SPACE : EMPTY)
@@ -149,4 +208,5 @@ private PsiMethod generateBuildMethod() {
149208

150209
return generatorParams.psi().factory().createMethodFromText(buildMethod.toString(), targetClass);
151210
}
211+
152212
}

src/main/java/com/github/junkfactory/innerbuilder/generators/FieldsGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44

55
import java.util.List;
66

7-
public interface FieldsGenerator extends Runnable {
7+
public interface FieldsGenerator extends Generator {
88
List<PsiField> getFields();
99
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.github.junkfactory.innerbuilder.generators;
2+
3+
import java.util.BitSet;
4+
5+
public class GenerationResult {
6+
7+
static final GenerationResult NO_RESULT = new GenerationResult();
8+
9+
public enum Code {
10+
IMPORTS_ADDED,
11+
ANNOTATIONS_ADDED
12+
}
13+
14+
private final BitSet result;
15+
16+
GenerationResult() {
17+
this.result = new BitSet();
18+
}
19+
20+
void set(Code code) {
21+
result.set(code.ordinal());
22+
}
23+
24+
public boolean isEmpty() {
25+
return !result.isEmpty();
26+
}
27+
28+
public boolean did(Code code) {
29+
return result.get(code.ordinal());
30+
}
31+
32+
public void when(Code code, Runnable runnable) {
33+
if (did(code)) {
34+
runnable.run();
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)