/
BuilderProcessor.java
92 lines (78 loc) · 4.06 KB
/
BuilderProcessor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package de.plushnikov.intellij.plugin.processor.clazz.builder;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import de.plushnikov.intellij.plugin.problem.ProblemBuilder;
import de.plushnikov.intellij.plugin.processor.LombokPsiElementUsage;
import de.plushnikov.intellij.plugin.processor.clazz.AbstractClassProcessor;
import de.plushnikov.intellij.plugin.processor.clazz.constructor.AllArgsConstructorProcessor;
import de.plushnikov.intellij.plugin.processor.handler.BuilderHandler;
import de.plushnikov.intellij.plugin.settings.ProjectSettings;
import de.plushnikov.intellij.plugin.util.PsiAnnotationSearchUtil;
import de.plushnikov.intellij.plugin.util.PsiClassUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Singular;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
/**
* Inspect and validate @Builder lombok annotation on a class.
* Creates methods for a builder pattern for initializing a class.
*
* @author Tomasz Kalkosiński
* @author Michail Plushnikov
*/
public class BuilderProcessor extends AbstractClassProcessor {
private static final String SINGULAR_CLASS = Singular.class.getName();
private static final String BUILDER_DEFAULT_CLASS = Builder.Default.class.getName().replace("$", ".");
private final BuilderHandler builderHandler;
private final AllArgsConstructorProcessor allArgsConstructorProcessor;
public BuilderProcessor(@NotNull AllArgsConstructorProcessor allArgsConstructorProcessor, @NotNull BuilderHandler builderHandler) {
super(PsiMethod.class, Builder.class);
this.builderHandler = builderHandler;
this.allArgsConstructorProcessor = allArgsConstructorProcessor;
}
@Override
public boolean isEnabled(@NotNull PropertiesComponent propertiesComponent) {
return ProjectSettings.isEnabled(propertiesComponent, ProjectSettings.IS_BUILDER_ENABLED);
}
@NotNull
@Override
public Collection<PsiAnnotation> collectProcessedAnnotations(@NotNull PsiClass psiClass) {
final Collection<PsiAnnotation> result = super.collectProcessedAnnotations(psiClass);
addFieldsAnnotation(result, psiClass, SINGULAR_CLASS, BUILDER_DEFAULT_CLASS);
return result;
}
@Override
protected boolean validate(@NotNull PsiAnnotation psiAnnotation, @NotNull PsiClass psiClass, @NotNull ProblemBuilder builder) {
// we skip validation here, bacause it will be validated by other BuilderClassProcessor
return true;//builderHandler.validate(psiClass, psiAnnotation, builder);
}
protected void generatePsiElements(@NotNull PsiClass psiClass, @NotNull PsiAnnotation psiAnnotation, @NotNull List<? super PsiElement> target) {
if (PsiAnnotationSearchUtil.isNotAnnotatedWith(psiClass, AllArgsConstructor.class)) {
// Create all args constructor only if there is no declared constructors and no lombok constructor annotations
final Collection<PsiMethod> definedConstructors = PsiClassUtil.collectClassConstructorIntern(psiClass);
if (definedConstructors.isEmpty()) {
target.addAll(allArgsConstructorProcessor.createAllArgsConstructor(psiClass, PsiModifier.PACKAGE_LOCAL, psiAnnotation));
}
}
PsiClass builderClass = builderHandler.getExistInnerBuilderClass(psiClass, null, psiAnnotation).orElse(null);
if (null == builderClass) {
// have to create full class (with all methods) here, or auto completion doesn't work
builderClass = builderHandler.createBuilderClass(psiClass, psiAnnotation);
}
builderHandler.createBuilderMethodIfNecessary(psiClass, null, builderClass, psiAnnotation)
.ifPresent(target::add);
builderHandler.createToBuilderMethodIfNecessary(psiClass, null, builderClass, psiAnnotation)
.ifPresent(target::add);
}
@Override
public LombokPsiElementUsage checkFieldUsage(@NotNull PsiField psiField, @NotNull PsiAnnotation psiAnnotation) {
return LombokPsiElementUsage.READ_WRITE;
}
}