Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiJavaFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.util.AstLoadingFilter;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -91,6 +92,7 @@ public void invoke(@NotNull final Project project, @NotNull final Editor editor,
.selectedFields(selectedFields)
.factory(JavaPsiFacade.getElementFactory(project))
.codeStyleManager(JavaCodeStyleManager.getInstance(project))
.psiManager(PsiManager.getInstance(project))
.build();
var generatorParams = GeneratorParams.builder()
.project(project)
Expand All @@ -108,17 +110,21 @@ private Set<JavaInnerBuilderOption> currentOptions() {
final var options = EnumSet.noneOf(JavaInnerBuilderOption.class);
final var propertiesComponent = PropertiesComponent.getInstance();
for (var option : JavaInnerBuilderOption.values()) {

if (Boolean.TRUE.equals(option.isBooleanProperty())) {
final boolean currentSetting = propertiesComponent.getBoolean(option.getProperty(), false);
if (currentSetting) {
options.add(option);
}
} else {
String currentValue = String.valueOf(propertiesComponent.getValue(option.getProperty()));
if (currentValue != null) {
switch (option.getType()) {
case BOOLEAN:
if (propertiesComponent.getBoolean(option.getProperty(), false)) {
options.add(option);
}
break;
case LIST:
var list = propertiesComponent.getList(option.getProperty());
if (null != list && !list.isEmpty()) {
options.add(option);
}
break;
default:
String currentValue = String.valueOf(propertiesComponent.getValue(option.getProperty()));
JavaInnerBuilderOption.findValue(currentValue).ifPresent(options::add);
}
}
}
return options;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ abstract class AbstractGenerator {

protected final GeneratorFactory generatorFactory;
protected final GeneratorParams generatorParams;
protected final GenerationResult generationResult;

protected AbstractGenerator(GeneratorFactory generatorFactory, GeneratorParams generatorParams) {
this.generatorFactory = generatorFactory;
this.generatorParams = generatorParams;
this.generationResult = new GenerationResult();
}

protected PsiElement addElement(PsiElement target, PsiElement element, PsiElement after) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public GenerationResult generate() {

var methodsGenerator = generatorFactory.createBuilderMethodsGenerator(generatorParams,
builderClassParams, fieldsGenerator);
return methodsGenerator.generate();
return generationResult.merge(methodsGenerator.generate());
}

private PsiMethod generateBuilderConstructor() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class BuilderMethodsGenerator extends AbstractGenerator implements MethodsGenera

private final BuilderClassParams builderClassParams;
private final FieldsGenerator fieldsGenerator;
private final GenerationResult generationResult;

private boolean isPublic;

Expand All @@ -27,7 +26,6 @@ class BuilderMethodsGenerator extends AbstractGenerator implements MethodsGenera
super(generatorFactory, generatorParams);
this.builderClassParams = builderClassParams;
this.fieldsGenerator = fieldsGenerator;
this.generationResult = new GenerationResult();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ public void when(Code code, Runnable runnable) {
runnable.run();
}
}

public GenerationResult merge(GenerationResult other) {
result.or(other.result);
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.github.junkfactory.innerbuilder.ui.JavaInnerBuilderOption;
import com.intellij.codeInsight.generation.PsiFieldMember;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiJavaFile;
Expand Down Expand Up @@ -59,12 +60,13 @@ public GenerationResult generate() {
.builderType(builderType)
.build();
var result = generatorFactory.createBuilderClassGenerator(generatorParams, params).generate();

generationResult.merge(result);
targetClass.add(builderClass);
var codeStyleManager = generatorParams.psi().codeStyleManager();
result.when(ANNOTATIONS_ADDED, () -> codeStyleManager.shortenClassReferences(file));
result.when(IMPORTS_ADDED, () -> codeStyleManager.removeRedundantImports((PsiJavaFile) file));
generationResult.when(ANNOTATIONS_ADDED, () -> codeStyleManager.shortenClassReferences(targetClass));
generationResult.when(IMPORTS_ADDED, () -> codeStyleManager.removeRedundantImports((PsiJavaFile) file));
CodeStyleManager.getInstance(generatorParams.project()).reformat(builderClass);
return result;
return generationResult;
}

private PsiMethod generateToBuilderMethod(PsiClass targetClass,
Expand Down Expand Up @@ -162,11 +164,22 @@ private PsiClass findOrCreateBuilderClass(final PsiClass targetClass) {

@NotNull
private PsiClass createBuilderClass(final PsiClass targetClass) {
var builderClass = (PsiClass) targetClass.add(generatorParams.psi().factory()
.createClass(BUILDER_CLASS_NAME));
PsiUtil.setModifierProperty(builderClass, PsiModifier.STATIC, true);
PsiUtil.setModifierProperty(builderClass, PsiModifier.FINAL, true);
return builderClass;
var classDef = new StringBuilder();
if (generatorParams.options().contains(JavaInnerBuilderOption.WITH_BUILDER_CLASS_ANNOTATIONS)) {
var propertiesComponent = PropertiesComponent.getInstance();
var annotationOptions =
propertiesComponent.getList(JavaInnerBuilderOption.WITH_BUILDER_CLASS_ANNOTATIONS.getProperty());
if (annotationOptions != null) {
annotationOptions.forEach(a -> classDef.append('@').append(a).append(System.lineSeparator()));
generationResult.set(GenerationResult.Code.ANNOTATIONS_ADDED);
}
}
classDef.append("public static final class ")
.append(BUILDER_CLASS_NAME)
.append(" {}")
.append(System.lineSeparator());
return generatorParams.psi().factory().createClassFromText(classDef.toString(), targetClass)
.getInnerClasses()[0];
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
import com.intellij.codeInsight.generation.PsiFieldMember;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;

import java.util.List;

public record PsiParams(PsiFile file,
List<PsiFieldMember> selectedFields,
PsiElementFactory factory,
JavaCodeStyleManager codeStyleManager) {
JavaCodeStyleManager codeStyleManager,
PsiManager psiManager) {

public static Builder builder() {
return new Builder();
Expand All @@ -21,6 +23,7 @@ public static final class Builder {
private List<PsiFieldMember> selectedFields;
private PsiElementFactory factory;
private JavaCodeStyleManager codeStyleManager;
private PsiManager psiManager;

private Builder() {
}
Expand All @@ -45,8 +48,13 @@ public Builder codeStyleManager(JavaCodeStyleManager codeStyleManager) {
return this;
}

public Builder psiManager(PsiManager psiManager) {
this.psiManager = psiManager;
return this;
}

public PsiParams build() {
return new PsiParams(file, selectedFields, factory, codeStyleManager);
return new PsiParams(file, selectedFields, factory, codeStyleManager, psiManager);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;

public class Utils {
@NonNls
Expand Down Expand Up @@ -134,5 +137,19 @@ public static boolean isFieldInitializedWithImmutableInstance(PsiField field) {
return null != initializerClass && initializerClass.hasModifierProperty(PsiModifier.ABSTRACT);
}

public static List<String> stringToList(String str) {
if (null == str || str.isBlank()) {
return List.of();
}
return Arrays.stream(str.split(System.lineSeparator()))
.map(String::trim)
.filter(Predicate.not(String::isBlank))
.toList();
}

public static String parseType(String text) {
var parenthesisIndex = text.indexOf('(');
return parenthesisIndex == -1 ? text : text.substring(0, parenthesisIndex);
}

}
Original file line number Diff line number Diff line change
@@ -1,43 +1,96 @@
package com.github.junkfactory.innerbuilder.ui;

import com.github.junkfactory.innerbuilder.generators.Utils;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.ui.ComponentValidator;
import com.intellij.openapi.ui.LabeledComponent;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.ClassUtil;
import com.intellij.ui.JBColor;
import com.intellij.ui.border.CustomLineBorder;
import com.intellij.util.ui.JBUI;

import javax.swing.JComponent;
import javax.swing.JTextArea;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;

public enum JavaInnerBuilderOption {
WITH_TO_BUILDER_METHOD("toBuilder", "Generate 'toBuilder()' method"),
WITH_VALIDATE_METHOD("validate", "Generate 'validate()' method");
WITH_TO_BUILDER_METHOD("JavaInnerBuilderOption.toBuilder",
"Generate 'toBuilder()' method",
Type.BOOLEAN),
WITH_VALIDATE_METHOD("JavaInnerBuilderOption.validate",
"Generate 'validate()' method",
Type.BOOLEAN),
WITH_BUILDER_CLASS_ANNOTATIONS("JavaInnerBuilderOption.builderClassAnnotations",
"Generate annotations for the builder class",
Type.LIST,
(p, d, j) -> new ComponentValidator(d).withValidator(() -> {
if (j instanceof JTextArea textArea) {
var errors = new StringBuilder();
var annotations = Utils.stringToList(textArea.getText());
for (var annotationText : annotations) {
var annotation = Utils.parseType(annotationText);
if (ClassUtil.findPsiClass(p, annotation) == null) {
errors.append(" - ").append(annotation).append("\n");
}
}
if (!errors.isEmpty()) {
textArea.setBorder(new CustomLineBorder(JBColor.RED, JBUI.insets(1)));
return new ValidationInfo(errors.insert(0, "Annotations not found")
.append(System.lineSeparator()).toString(), textArea);
}
textArea.setBorder(new CustomLineBorder(JBColor.border(), JBUI.insets(1)));
}
return null;
}).installOn(j));

private final String property;
private final String description;
private final Boolean booleanProperty;
private final Type type;
private final OptionValidatorFactory validatorFactory;

JavaInnerBuilderOption(final String property, String description) {
this(property, description, true);
JavaInnerBuilderOption(String property, String description, Type type) {
this(property, description, type, (p, d, j) -> {
});
}

JavaInnerBuilderOption(final String property, String description, final Boolean booleanProperty) {
JavaInnerBuilderOption(String property, String description, Type type,
OptionValidatorFactory validatorFactory) {
this.property = String.format("JavaInnerBuilder.%s", property);
this.description = description;
this.booleanProperty = booleanProperty;
this.type = type;
this.validatorFactory = validatorFactory;
}

public String getProperty() {
return property;
}

public Boolean isBooleanProperty() {
return booleanProperty;
public Type getType() {
return type;
}

public String getDescription() {
return description;
}

public void createValidator(PsiManager psiManager, Disposable disposable, JComponent component) {
if (component instanceof LabeledComponent<?> labeledComponent) {
component = labeledComponent.getComponent();
}
validatorFactory.create(psiManager, disposable, component);
}

public static Optional<JavaInnerBuilderOption> findValue(String value) {
return Arrays.stream(values())
.filter(it -> Objects.equals(it.getProperty(), value))
.findFirst();
}

public enum Type {
BOOLEAN, LIST
}
}
Loading