CodeAction, Problem and Fix descriptors API reworked. Reload action fix

This commit is contained in:
aboyko
2022-10-05 11:06:00 -04:00
parent 4db1297ac8
commit f8393859dd
21 changed files with 410 additions and 460 deletions

View File

@@ -344,11 +344,11 @@
<extension
point="org.eclipse.ui.quickAccess">
<computer
class="org.springframework.tooling.boot.ls.commands.RewriteCommandsQuickAccessProvider"
class="org.springframework.tooling.boot.ls.commands.LiveProcessCommandsQuickAccessProvider"
name="Spring - Live Process Information"
requiresUIAccess="false"/>
<computer
class="org.springframework.tooling.boot.ls.QuickAccessComputer1"
class="org.springframework.tooling.boot.ls.commands.RewriteCommandsQuickAccessProvider"
name="Spring - Rewrite Recipes">
</computer>
</extension>

View File

@@ -10,7 +10,10 @@
*******************************************************************************/
package org.springframework.rewrite.test;
import java.util.List;
import org.openrewrite.ExecutionContext;
import org.openrewrite.SourceFile;
import org.openrewrite.Tree;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaVisitor;
@@ -26,23 +29,12 @@ import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDes
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeSpringJavaProblemDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
public class HelloMethodRenameProblemDescriptor implements RecipeSpringJavaProblemDescriptor {
@Override
public String getRecipeId() {
return "org.springframework.rewrite.test.HelloMethodRenameRecipe";
}
@Override
public String getLabel(RecipeScope s) {
return RecipeCodeActionDescriptor.buildLabel("Switch hello method into bye", s);
}
@Override
public RecipeScope[] getScopes() {
return RecipeScope.values();
}
private static final String LABEL = "Switch hello method into bye";
private static final String RECIPE_ID = "org.springframework.rewrite.test.HelloMethodRenameRecipe";
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
@@ -52,7 +44,17 @@ public class HelloMethodRenameProblemDescriptor implements RecipeSpringJavaProbl
public MethodDeclaration visitMethodDeclaration(MethodDeclaration method, ExecutionContext p) {
MethodDeclaration m = super.visitMethodDeclaration(method, p);
if ("hello".equals(method.getSimpleName())) {
FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), getId()).withRecipeId(getRecipeId()).withScope(m.getMarkers().findFirst(Range.class).get());
String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toString();
FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), getId())
.withFixes(
new FixDescriptor(RECIPE_ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.NODE))
.withRecipeScope(RecipeScope.NODE)
.withRangeScope(m.getMarkers().findFirst(Range.class).get()),
new FixDescriptor(RECIPE_ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.FILE))
.withRecipeScope(RecipeScope.FILE),
new FixDescriptor(RECIPE_ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)
);
m = m.withName(m.getName().withMarkers(m.getName().getMarkers().add(marker)));
}
return m;

View File

@@ -21,12 +21,6 @@ public interface RecipeCodeActionDescriptor {
return getClass().getName();
}
String getRecipeId();
String getLabel(RecipeScope s);
RecipeScope[] getScopes();
JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext);
boolean isApplicable(IJavaProject project);

View File

@@ -1,24 +1,30 @@
/*******************************************************************************
* Copyright (c) 2022 VMware, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.rewrite.java;
import java.util.Collections;
import java.util.Map;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import org.openrewrite.marker.Marker;
import org.openrewrite.marker.Range;
public class FixAssistMarker implements Marker {
private UUID id;
private Range scope;
private String recipeId;
private String descriptorId;
private Map<String, Object> parameters = Collections.emptyMap();
private List<FixDescriptor> fixes = new ArrayList<>();;
public FixAssistMarker(UUID id, String descriptorId) {
super();
@@ -38,40 +44,27 @@ public class FixAssistMarker implements Marker {
return this;
}
public FixAssistMarker withScope(Range scope) {
this.scope = scope;
return this;
}
public Range getScope() {
return scope;
}
public FixAssistMarker withRecipeId(String recipeId) {
this.recipeId = recipeId;
return this;
}
public String getRecipeId() {
return recipeId;
}
public FixAssistMarker withParameters(Map<String, Object> parameters) {
this.parameters = parameters;
return this;
}
public Map<String, Object> getParameters() {
return parameters;
}
public String getDescriptorId() {
return descriptorId;
}
public FixAssistMarker withFix(FixDescriptor f) {
fixes.add(f);
return this;
}
public FixAssistMarker withFixes(FixDescriptor... fixes) {
this.fixes.addAll(Arrays.asList(fixes));
return this;
}
public List<FixDescriptor> getFixes() {
return fixes;
}
@Override
public int hashCode() {
return Objects.hash(descriptorId, id, parameters, recipeId, scope);
return Objects.hash(descriptorId, fixes, id);
}
@Override
@@ -83,10 +76,9 @@ public class FixAssistMarker implements Marker {
if (getClass() != obj.getClass())
return false;
FixAssistMarker other = (FixAssistMarker) obj;
return Objects.equals(descriptorId, other.descriptorId) && Objects.equals(id, other.id)
&& Objects.equals(parameters, other.parameters) && Objects.equals(recipeId, other.recipeId)
&& Objects.equals(scope, other.scope);
return Objects.equals(descriptorId, other.descriptorId) && Objects.equals(fixes, other.fixes)
&& Objects.equals(id, other.id);
}
}

View File

@@ -0,0 +1,78 @@
/*******************************************************************************
* Copyright (c) 2022 VMware, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.rewrite.java;
import java.util.List;
import java.util.Map;
import org.openrewrite.marker.Range;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
final public class FixDescriptor {
private String recipeId;
private RecipeScope recipeScope;
private Range rangeScope;
private List<String> docUris;
private Map<String, Object> parameters;
private String label;
public FixDescriptor(String recipeId, List<String> docUris, String label) {
this.recipeId = recipeId;
this.docUris = docUris;
this.label = label;
}
public FixDescriptor withRecipeScope(RecipeScope recipeScope) {
this.recipeScope = recipeScope;
return this;
}
public FixDescriptor withRangeScope(Range rangeScope) {
this.rangeScope = rangeScope;
return this;
}
public FixDescriptor withParameters(Map<String, Object> parameters) {
this.parameters = parameters;
return this;
}
public String getRecipeId() {
return recipeId;
}
public RecipeScope getRecipeScope() {
return recipeScope;
}
public Range getRangeScope() {
return rangeScope;
}
public List<String> getDocUris() {
return docUris;
}
public Map<String, Object> getParameters() {
return parameters;
}
public String getLabel() {
return label;
}
}

View File

@@ -13,9 +13,7 @@ package org.springframework.ide.vscode.boot.java.rewrite;
import java.util.List;
import org.springframework.ide.vscode.boot.java.rewrite.codeaction.AutowiredFieldIntoConstructorParameterCodeAction;
import org.springframework.ide.vscode.boot.java.rewrite.codeaction.BeanMethodsNotPublicCodeAction;
import org.springframework.ide.vscode.boot.java.rewrite.codeaction.NoRequestMappingAnnotationCodeAction;
import org.springframework.ide.vscode.boot.java.rewrite.codeaction.UnnecessarySpringExtensionCodeAction;
import org.springframework.ide.vscode.boot.java.rewrite.reconcile.BeanMethodNotPublicProblem;
import org.springframework.ide.vscode.boot.java.rewrite.reconcile.BeanPostProcessingIgnoreInAotProblem;
import org.springframework.ide.vscode.boot.java.rewrite.reconcile.NoAutowiredOnConstructorProblem;
@@ -32,9 +30,7 @@ public class BootCodeActionRepository extends CodeActionRepository {
public List<RecipeCodeActionDescriptor> getCodeActionDescriptors() {
return List.of(
new AutowiredFieldIntoConstructorParameterCodeAction(),
new BeanMethodsNotPublicCodeAction(),
new NoRequestMappingAnnotationCodeAction(),
new UnnecessarySpringExtensionCodeAction()
new NoRequestMappingAnnotationCodeAction()
);
}

View File

@@ -12,10 +12,8 @@ package org.springframework.ide.vscode.boot.java.rewrite;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.eclipse.lsp4j.CodeAction;
@@ -41,9 +39,8 @@ import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
import org.springframework.ide.vscode.commons.languageserver.util.LspClient.Client;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeSpringJavaProblemDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -103,7 +100,6 @@ public class RewriteCodeActionHandler implements JavaCodeActionHandler {
List<RecipeCodeActionDescriptor> descriptors = recipeRepo.getCodeActionRecipeDescriptors().stream()
// If Recipe not present - don't show quick assist as it won't be handled without the Rewrite recipe present
.filter(d -> recipeRepo.getRecipe(d.getRecipeId()).isPresent())
.filter(d -> d.isApplicable(project))
.collect(Collectors.toList());
@@ -151,34 +147,20 @@ public class RewriteCodeActionHandler implements JavaCodeActionHandler {
private CodeAction[] createCodeActions(IDocument doc, FixAssistMarker m, J astNode) {
if (astNode != null) {
Range range = astNode.getMarkers().findFirst(Range.class).orElse(null);
RecipeCodeActionDescriptor descriptor = recipeRepo.getCodeActionRecipeDescriptor(m.getRecipeId());
if (descriptor != null && descriptor.getScopes() != null) {
// Fix descriptor code actions may have the overlapping scopes with assist descriptors. Quick fixes are provided separately hence overlapping scopes will produces duplicates quick assist.
// Therefore, need to compute recipe scopes that don't overlap with quick fix descriptor recipe scopes.
RecipeSpringJavaProblemDescriptor fixDescriptor = recipeRepo.getProblemRecipeDescriptor(m.getDescriptorId());
return Arrays.stream(descriptor.getScopes())
.filter(s -> fixDescriptor == null || !Arrays.asList(fixDescriptor.getScopes()).contains(s))
.map(s -> createCodeActionFromScope(doc, descriptor, s, m, range))
.filter(Objects::nonNull)
.toArray(CodeAction[]::new);
}
return m.getFixes().stream()
.filter(d -> recipeRepo.getRecipe(d.getRecipeId()) != null)
.map(d -> createCodeActionFromScope(doc, d))
.toArray(CodeAction[]::new);
}
return new CodeAction[0];
}
private CodeAction createCodeActionFromScope(IDocument doc, RecipeCodeActionDescriptor descriptor,
RecipeScope s, FixAssistMarker m, Range range) {
private CodeAction createCodeActionFromScope(IDocument doc,
FixDescriptor d) {
CodeAction ca = new CodeAction();
ca.setKind(CodeActionKind.Refactor);
ca.setTitle(descriptor.getLabel(s));
ca.setData(new RewriteRefactorings.Data(
m.getRecipeId(),
doc.getUri(),
s,
m.getScope() == null ? null : m.getScope(),
m.getParameters() == null ? Collections.emptyMap() : m.getParameters()
));
ca.setTitle(d.getLabel());
ca.setData(d);
return ca;
}

View File

@@ -37,7 +37,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.app.BootJavaConfig;
import org.springframework.ide.vscode.boot.java.reconcilers.JavaReconciler;
import org.springframework.ide.vscode.boot.java.rewrite.RewriteRefactorings.Data;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix.QuickfixData;
@@ -47,9 +46,9 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemC
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeSpringJavaProblemDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -115,13 +114,15 @@ public class RewriteReconciler implements JavaReconciler {
ProblemType problemType = recipeFixDescriptor.getProblemType();
ReconcileProblemImpl problem = new ReconcileProblemImpl(problemType, problemType.getLabel(), range.getStart().getOffset(), range.getEnd().getOffset() - range.getStart().getOffset());
QuickfixType quickfixType = quickfixRegistry.getQuickfixType(RewriteRefactorings.REWRITE_RECIPE_QUICKFIX);
if (quickfixType != null && m.getRecipeId() != null && recipeRepo.getRecipe(recipeFixDescriptor.getRecipeId()).isPresent()) {
for (RecipeScope s : recipeFixDescriptor.getScopes()) {
problem.addQuickfix(new QuickfixData<>(
quickfixType,
new Data(m.getRecipeId(), doc.getUri(), s, m.getScope(), m.getParameters()),
recipeFixDescriptor.getLabel(s)
));
if (quickfixType != null) {
for (FixDescriptor f : m.getFixes()) {
if (recipeRepo.getRecipe(f.getRecipeId()) != null) {
problem.addQuickfix(new QuickfixData<>(
quickfixType,
f,
f.getLabel()
));
}
}
}
return problem;
@@ -137,19 +138,21 @@ public class RewriteReconciler implements JavaReconciler {
List<RecipeSpringJavaProblemDescriptor> descriptors = getProblemRecipeDescriptors(project);
JavaParser javaParser = ORAstUtils.createJavaParser(project);
List<CompilationUnit> cus = ORAstUtils.parseInputs(javaParser, docs.stream().map(d -> new Parser.Input(Path.of(d.getUri()), () -> {
return new ByteArrayInputStream(d.get().getBytes());
})).collect(Collectors.toList()));
if (!descriptors.isEmpty()) {
if (javaParser != null) {
List<CompilationUnit> cus = ORAstUtils.parseInputs(javaParser, docs.stream().map(d -> new Parser.Input(Path.of(d.getUri()), () -> {
return new ByteArrayInputStream(d.get().getBytes());
})).collect(Collectors.toList()));
for(int i = 0; i < cus.size(); i++) {
final IDocument doc = docs.get(i);
List<ReconcileProblem> problems = new ArrayList<>();
collectProblems(descriptors, doc, cus.get(i), problems::add);
if (!problems.isEmpty()) {
allProblems.put(doc, problems);
}
if (!descriptors.isEmpty()) {
for(int i = 0; i < cus.size(); i++) {
final IDocument doc = docs.get(i);
List<ReconcileProblem> problems = new ArrayList<>();
collectProblems(descriptors, doc, cus.get(i), problems::add);
if (!problems.isEmpty()) {
allProblems.put(doc, problems);
}
}
}
}
} catch (Exception e) {

View File

@@ -13,8 +13,8 @@ package org.springframework.ide.vscode.boot.java.rewrite;
import java.lang.reflect.Field;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -42,6 +42,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.CodeActionReso
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
import org.springframework.ide.vscode.commons.rewrite.ORDocUtils;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -107,8 +108,8 @@ public class RewriteRefactorings implements CodeActionResolver, QuickfixHandler
}
public WorkspaceEdit createEdit(JsonElement o) {
Data data = gson.fromJson(o, Data.class);
if (data != null && data.id != null) {
FixDescriptor data = gson.fromJson(o, FixDescriptor.class);
if (data != null && data.getRecipeId() != null) {
return perform(data);
}
return null;
@@ -133,32 +134,29 @@ public class RewriteRefactorings implements CodeActionResolver, QuickfixHandler
return workspaceEdit;
}
private WorkspaceEdit perform(Data data) {
Optional<IJavaProject> project = projectFinder.find(new TextDocumentIdentifier(data.docUri));
private WorkspaceEdit perform(FixDescriptor data) {
Optional<IJavaProject> project = projectFinder.find(new TextDocumentIdentifier(data.getDocUris().get(0)));
if (project.isPresent()) {
boolean projectWide = data.recipeScope == RecipeScope.PROJECT;
boolean projectWide = data.getRecipeScope() == RecipeScope.PROJECT;
Recipe r = createRecipe(data);
if (projectWide) {
return applyRecipe(r, project.get(), ORAstUtils.parse(documents, project.get()));
} else {
CompilationUnit cu = cuCache.getCU(project.get(), URI.create(data.docUri));
if (cu == null) {
throw new IllegalStateException("Cannot parse Java file: " + data.docUri);
}
return applyRecipe(r, project.get(), List.of(cu));
List<CompilationUnit> cus = data.getDocUris().stream().map(docUri -> cuCache.getCU(project.get(), URI.create(docUri))).filter(Objects::nonNull).collect(Collectors.toList());
return applyRecipe(r, project.get(), cus);
}
}
return null;
}
private Recipe createRecipe(Data d) {
Recipe r = recipeRepo.getRecipe(d.id).orElse(null);
private Recipe createRecipe(FixDescriptor d) {
Recipe r = recipeRepo.getRecipe(d.getRecipeId()).orElse(null);
if (!(r instanceof DeclarativeRecipe)) {
r = RecipeIntrospectionUtils.constructRecipe(r.getClass());
}
if (d.params != null) {
for (Entry<String, Object> entry : d.params.entrySet()) {
if (d.getParameters() != null) {
for (Entry<String, Object> entry : d.getParameters().entrySet()) {
try {
Field f = r.getClass().getDeclaredField(entry.getKey());
f.setAccessible(true);
@@ -168,15 +166,15 @@ public class RewriteRefactorings implements CodeActionResolver, QuickfixHandler
}
}
}
if (d.recipeScope == RecipeScope.NODE) {
if (d.scope == null) {
if (d.getRecipeScope() == RecipeScope.NODE) {
if (d.getRangeScope() == null) {
throw new IllegalArgumentException("Missing scope AST node!");
} else {
r = ORAstUtils.nodeRecipe(r, j -> {
if (j != null) {
Range range = j.getMarkers().findFirst(Range.class).orElse(null);
if (range != null) {
return d.scope.getStart().getOffset() <= range.getStart().getOffset() && range.getEnd().getOffset() <= d.scope.getEnd().getOffset();
return d.getRangeScope().getStart().getOffset() <= range.getStart().getOffset() && range.getEnd().getOffset() <= d.getRangeScope().getEnd().getOffset();
}
}
return false;
@@ -185,21 +183,4 @@ public class RewriteRefactorings implements CodeActionResolver, QuickfixHandler
}
return r;
}
public static class Data {
public String id;
public String docUri;
public RecipeScope recipeScope;
public Range scope;
public Map<String, Object> params;
public Data(String id, String docUri, RecipeScope recipeScope, Range scope, Map<String, Object> params) {
this.id = id;
this.docUri = docUri;
this.recipeScope = recipeScope;
this.scope = scope;
this.params = params;
}
}
}

View File

@@ -19,6 +19,7 @@ import java.util.stream.Collectors;
import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.SourceFile;
import org.openrewrite.Tree;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaVisitor;
@@ -36,6 +37,7 @@ import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDes
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.AnnotationHierarchies;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils;
public class AutowiredFieldIntoConstructorParameterCodeAction implements RecipeCodeActionDescriptor {
@@ -44,21 +46,6 @@ public class AutowiredFieldIntoConstructorParameterCodeAction implements RecipeC
private static final String ID = "org.springframework.ide.vscode.commons.rewrite.java.ConvertAutowiredFieldIntoConstructorParameter";
private static final String AUTOWIRED = "org.springframework.beans.factory.annotation.Autowired";
@Override
public String getRecipeId() {
return ID;
}
@Override
public String getLabel(RecipeScope s) {
return RecipeCodeActionDescriptor.buildLabel(LABEL, s);
}
@Override
public RecipeScope[] getScopes() {
return new RecipeScope[] { RecipeScope.NODE };
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<>() {
@@ -76,10 +63,14 @@ public class AutowiredFieldIntoConstructorParameterCodeAction implements RecipeC
if (fqType != null && isApplicableType(fqType)) {
List<MethodDeclaration> constructors = ORAstUtils.getMethods(classDeclaration).stream().filter(c -> c.isConstructor()).limit(2).collect(Collectors.toList());
String fieldName = multiVariable.getVariables().get(0).getSimpleName();
String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toString();
FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), getId())
.withRecipeId(getRecipeId())
.withScope(classDeclaration.getMarkers().findFirst(Range.class).get())
.withParameters(Map.of("classFqName", fqType.getFullyQualifiedName(), "fieldName", fieldName));
.withFix(
new FixDescriptor(ID, List.of(uri), LABEL)
.withRangeScope(classDeclaration.getMarkers().findFirst(Range.class).get())
.withParameters(Map.of("classFqName", fqType.getFullyQualifiedName(), "fieldName", fieldName))
.withRecipeScope(RecipeScope.NODE)
);
if (constructors.size() == 0) {
m = m.withMarkers(m.getMarkers().add(marker));
} else if (constructors.size() == 1 && !AutowiredFieldIntoConstructorParameterVisitor.isConstructorInitializingField(constructors.get(0), fieldName)) {

View File

@@ -1,84 +0,0 @@
/*******************************************************************************
* Copyright (c) 2022 VMware, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.rewrite.codeaction;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Tree;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.AnnotationMatcher;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.TypeUtils;
import org.openrewrite.marker.Range;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
public class BeanMethodsNotPublicCodeAction implements RecipeCodeActionDescriptor {
private static final String ID = "org.openrewrite.java.spring.BeanMethodsNotPublic";
private static final String LABEL = "Remove 'public' from @Bean method";
private static final AnnotationMatcher BEAN_ANNOTATION_MATCHER = new AnnotationMatcher("@org.springframework.context.annotation.Bean");
@Override
public String getRecipeId() {
return ID;
}
@Override
public String getLabel(RecipeScope s) {
return RecipeCodeActionDescriptor.buildLabel(LABEL, s);
}
@Override
public RecipeScope[] getScopes() {
return RecipeScope.values();
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext executionContext) {
J.MethodDeclaration m = super.visitMethodDeclaration(method, executionContext);
if (m.getAllAnnotations().stream().anyMatch(BEAN_ANNOTATION_MATCHER::matches)
&& Boolean.FALSE.equals(TypeUtils.isOverride(method.getMethodType()))) {
// mark public modifier
FixAssistMarker fixAssistMarker = new FixAssistMarker(Tree.randomId(), getId())
.withRecipeId(ID)
.withScope(m.getMarkers().findFirst(Range.class).get());
m = m.withModifiers(ListUtils.map(m.getModifiers(), modifier -> {
if (modifier.getType() == J.Modifier.Type.Public) {
return modifier.withMarkers(modifier.getMarkers().add(fixAssistMarker));
}
return modifier;
}));
}
return m;
}
};
}
@Override
public boolean isApplicable(IJavaProject project) {
return SpringProjectUtil.getDependencyVersion(project, SpringProjectUtil.SPRING_BOOT) != null;
}
}

View File

@@ -12,7 +12,10 @@ package org.springframework.ide.vscode.boot.java.rewrite.codeaction;
import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.springBootVersionGreaterOrEqual;
import java.util.List;
import org.openrewrite.ExecutionContext;
import org.openrewrite.SourceFile;
import org.openrewrite.Tree;
import org.openrewrite.java.AnnotationMatcher;
import org.openrewrite.java.JavaIsoVisitor;
@@ -24,6 +27,7 @@ import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
public class NoRequestMappingAnnotationCodeAction implements RecipeCodeActionDescriptor {
@@ -31,21 +35,6 @@ public class NoRequestMappingAnnotationCodeAction implements RecipeCodeActionDes
private static final String ID = "org.openrewrite.java.spring.NoRequestMappingAnnotation";
private static final AnnotationMatcher REQUEST_MAPPING_ANNOTATION_MATCHER = new AnnotationMatcher("@org.springframework.web.bind.annotation.RequestMapping");
@Override
public String getRecipeId() {
return ID;
}
@Override
public String getLabel(RecipeScope s) {
return RecipeCodeActionDescriptor.buildLabel(LABEL, s);
}
@Override
public RecipeScope[] getScopes() {
return RecipeScope.values();
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<ExecutionContext>() {
@@ -53,9 +42,17 @@ public class NoRequestMappingAnnotationCodeAction implements RecipeCodeActionDes
public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) {
J.Annotation a = super.visitAnnotation(annotation, ctx);
if (REQUEST_MAPPING_ANNOTATION_MATCHER.matches(a) && getCursor().getParentOrThrow().getValue() instanceof J.MethodDeclaration) {
String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toString();
FixAssistMarker fixAssistMarker = new FixAssistMarker(Tree.randomId(), getId())
.withRecipeId(getRecipeId())
.withScope(a.getMarkers().findFirst(Range.class).get());
.withFixes(
new FixDescriptor(ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.NODE))
.withRangeScope(a.getMarkers().findFirst(Range.class).get())
.withRecipeScope(RecipeScope.NODE),
new FixDescriptor(ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.FILE))
.withRecipeScope(RecipeScope.FILE),
new FixDescriptor(ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)
);
a = a.withMarkers(a.getMarkers().add(fixAssistMarker));
}
return a;

View File

@@ -1,103 +0,0 @@
/*******************************************************************************
* Copyright (c) 2022 VMware, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.rewrite.codeaction;
import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.springBootVersionGreaterOrEqual;
import java.util.Arrays;
import java.util.List;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Tree;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.AnnotationMatcher;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J.ClassDeclaration;
import org.openrewrite.java.tree.JavaType.FullyQualified;
import org.openrewrite.java.tree.TypeUtils;
import org.openrewrite.marker.Range;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
public class UnnecessarySpringExtensionCodeAction implements RecipeCodeActionDescriptor {
private static final String LABEL = "Remove unnecessary @SpringExtension";
private static final String ID = "org.openrewrite.java.spring.boot2.UnnecessarySpringExtension";
private static final List<String> SPRING_BOOT_TEST_ANNOTATIONS = Arrays.asList(
"org.springframework.boot.test.context.SpringBootTest",
"org.springframework.boot.test.autoconfigure.jdbc.JdbcTest",
"org.springframework.boot.test.autoconfigure.web.client.RestClientTest",
"org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest",
"org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest",
"org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest",
"org.springframework.boot.test.autoconfigure.webservices.client.WebServiceClientTest",
"org.springframework.boot.test.autoconfigure.jooq.JooqTest",
"org.springframework.boot.test.autoconfigure.json.JsonTest",
"org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest",
"org.springframework.boot.test.autoconfigure.data.jdbc.DataJdbcTest",
"org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest",
"org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest",
"org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest",
"org.springframework.boot.test.autoconfigure.data.r2dbc.DataR2dbcTest",
"org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest"
);
private static final AnnotationMatcher SPRING_EXTENSION_ANNOTATIN_MATCHER = new AnnotationMatcher("@org.junit.jupiter.api.extension.ExtendWith(org.springframework.test.context.junit.jupiter.SpringExtension.class)");
@Override
public String getRecipeId() {
return ID;
}
@Override
public String getLabel(RecipeScope s) {
return RecipeCodeActionDescriptor.buildLabel(LABEL, s);
}
@Override
public RecipeScope[] getScopes() {
return new RecipeScope[] { RecipeScope.PROJECT };
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<>() {
@Override
public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, ExecutionContext p) {
ClassDeclaration c = super.visitClassDeclaration(classDecl, p);
if (c.getLeadingAnnotations().stream().anyMatch(a -> {
FullyQualified fq = TypeUtils.asFullyQualified(a.getType());
return fq != null && SPRING_BOOT_TEST_ANNOTATIONS.contains(fq.getFullyQualifiedName());
})) {
Range range = c.getMarkers().findFirst(Range.class).get();
c = c.withLeadingAnnotations(ListUtils.map(c.getLeadingAnnotations(), a -> {
if (SPRING_EXTENSION_ANNOTATIN_MATCHER.matches(a)) {
return a.withMarkers(a.getMarkers().add(new FixAssistMarker(Tree.randomId(), getId()).withRecipeId(ID).withScope(range)));
}
return a;
}));
}
return c;
}
};
}
@Override
public boolean isApplicable(IJavaProject project) {
return springBootVersionGreaterOrEqual(2, 1, 0).test(project);
}
}

View File

@@ -10,16 +10,75 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.rewrite.reconcile;
import java.util.List;
import org.openrewrite.ExecutionContext;
import org.openrewrite.SourceFile;
import org.openrewrite.Tree;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.AnnotationMatcher;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.TypeUtils;
import org.openrewrite.marker.Range;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
import org.springframework.ide.vscode.boot.java.rewrite.codeaction.BeanMethodsNotPublicCodeAction;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeSpringJavaProblemDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
public class BeanMethodNotPublicProblem extends BeanMethodsNotPublicCodeAction implements RecipeSpringJavaProblemDescriptor {
public class BeanMethodNotPublicProblem implements RecipeSpringJavaProblemDescriptor {
private static final String ID = "org.openrewrite.java.spring.BeanMethodsNotPublic";
private static final String LABEL = "Remove 'public' from @Bean method";
private static final AnnotationMatcher BEAN_ANNOTATION_MATCHER = new AnnotationMatcher("@org.springframework.context.annotation.Bean");
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext executionContext) {
J.MethodDeclaration m = super.visitMethodDeclaration(method, executionContext);
if (m.getAllAnnotations().stream().anyMatch(BEAN_ANNOTATION_MATCHER::matches)
&& Boolean.FALSE.equals(TypeUtils.isOverride(method.getMethodType()))) {
// mark public modifier
String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toString();
FixAssistMarker fixAssistMarker = new FixAssistMarker(Tree.randomId(), getId())
.withFixes(
new FixDescriptor(ID, List.of(uri), LABEL)
.withRangeScope(m.getMarkers().findFirst(Range.class).get())
.withRecipeScope(RecipeScope.NODE),
new FixDescriptor(ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.FILE))
.withRecipeScope(RecipeScope.FILE),
new FixDescriptor(ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)
);
m = m.withModifiers(ListUtils.map(m.getModifiers(), modifier -> {
if (modifier.getType() == J.Modifier.Type.Public) {
return modifier.withMarkers(modifier.getMarkers().add(fixAssistMarker));
}
return modifier;
}));
}
return m;
}
};
}
@Override
public RecipeScope[] getScopes() {
return new RecipeScope[] { RecipeScope.NODE };
public boolean isApplicable(IJavaProject project) {
return SpringProjectUtil.getDependencyVersion(project, SpringProjectUtil.SPRING_BOOT) != null;
}
@Override

View File

@@ -16,6 +16,7 @@ import java.util.List;
import java.util.stream.Collectors;
import org.openrewrite.ExecutionContext;
import org.openrewrite.SourceFile;
import org.openrewrite.Tree;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaVisitor;
@@ -31,26 +32,13 @@ import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeSpringJavaProblemDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.BeanPostProcessingIgnoreInAot;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
public class BeanPostProcessingIgnoreInAotProblem implements RecipeSpringJavaProblemDescriptor {
private static final String RECIPE_ID = "org.springframework.ide.vscode.commons.rewrite.java.BeanPostProcessingIgnoreInAot";
private static final String LABEL = "Add method 'isBeanExcludedFromAotProcessing' that returns 'false'";
@Override
public String getRecipeId() {
return "org.springframework.ide.vscode.commons.rewrite.java.BeanPostProcessingIgnoreInAot";
}
@Override
public String getLabel(RecipeScope s) {
return RecipeCodeActionDescriptor.buildLabel(LABEL, s);
}
@Override
public RecipeScope[] getScopes() {
return RecipeScope.values();
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<ExecutionContext>() {
@@ -63,9 +51,17 @@ public class BeanPostProcessingIgnoreInAotProblem implements RecipeSpringJavaPro
.filter(MethodDeclaration.class::isInstance).map(MethodDeclaration.class::cast)
.filter(BeanPostProcessingIgnoreInAot::isApplicableMethod)
.collect(Collectors.toList());
String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toString();
FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), getId())
.withRecipeId(getRecipeId())
.withScope(classDecl.getMarkers().findFirst(Range.class).orElse(null));
.withFixes(
new FixDescriptor(RECIPE_ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.NODE))
.withRangeScope(classDecl.getMarkers().findFirst(Range.class).orElse(null))
.withRecipeScope(RecipeScope.NODE),
new FixDescriptor(RECIPE_ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.FILE))
.withRecipeScope(RecipeScope.FILE),
new FixDescriptor(RECIPE_ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)
);
if (methods.isEmpty()) {
// Didn't find a method. Default implementation return true therefore mark it.
c = c.withName(c.getName().withMarkers(c.getName().getMarkers().add(marker)));

View File

@@ -12,7 +12,10 @@ package org.springframework.ide.vscode.boot.java.rewrite.reconcile;
import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.springBootVersionGreaterOrEqual;
import java.util.List;
import org.openrewrite.ExecutionContext;
import org.openrewrite.SourceFile;
import org.openrewrite.Tree;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaIsoVisitor;
@@ -32,27 +35,13 @@ import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeSpringJavaProblemDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.AnnotationHierarchies;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
public class NoAutowiredOnConstructorProblem implements RecipeSpringJavaProblemDescriptor {
private static final String ID = "org.openrewrite.java.spring.NoAutowiredOnConstructor";
private static final String LABEL = "Remove Unnecessary @Autowired";
@Override
public String getRecipeId() {
return ID;
}
@Override
public String getLabel(RecipeScope s) {
return LABEL;
}
@Override
public RecipeScope[] getScopes() {
return new RecipeScope[] { RecipeScope.NODE };
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<ExecutionContext>() {
@@ -77,9 +66,13 @@ public class NoAutowiredOnConstructorProblem implements RecipeSpringJavaProblemD
return s;
}
MethodDeclaration constructor = (MethodDeclaration) s;
String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toString();
FixAssistMarker fixAssistMarker = new FixAssistMarker(Tree.randomId(), getId())
.withRecipeId(ID)
.withScope(getCursor().firstEnclosing(ClassDeclaration.class).getMarkers().findFirst(Range.class).get());
.withFix(
new FixDescriptor(ID, List.of(uri), LABEL)
.withRecipeScope(RecipeScope.NODE)
.withRangeScope(getCursor().firstEnclosing(ClassDeclaration.class).getMarkers().findFirst(Range.class).get())
);
constructor = constructor.withLeadingAnnotations(ListUtils.map(constructor.getLeadingAnnotations(), a -> {
if (TypeUtils.isOfClassType(a.getType(), Annotations.AUTOWIRED)) {
a = a.withMarkers(a.getMarkers().add(fixAssistMarker));

View File

@@ -1,3 +1,13 @@
/*******************************************************************************
* Copyright (c) 2022 VMware, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.rewrite.reconcile;
import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.springBootVersionGreaterOrEqual;
@@ -13,8 +23,6 @@ import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J.ClassDeclaration;
import org.openrewrite.java.tree.JavaType.FullyQualified;
import org.openrewrite.java.tree.TypeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
import org.springframework.ide.vscode.boot.java.Boot3JavaProblemType;
@@ -22,38 +30,17 @@ import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformatio
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeSpringJavaProblemDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
public class NotRegisteredBeansProblem implements RecipeSpringJavaProblemDescriptor {
private static final Logger log = LoggerFactory.getLogger(NotRegisteredBeansProblem.class);
private static final List<String> AOT_BEANS = List.of(
"org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor",
"org.springframework.beans.factory.aot.BeanRegistrationAotProcessor",
"org.springframework.beans.factory.aot.RuntimeHintsRegistrar"
);
@Override
public String getRecipeId() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getLabel(RecipeScope s) {
// TODO Auto-generated method stub
return null;
}
@Override
public RecipeScope[] getScopes() {
// TODO Auto-generated method stub
return new RecipeScope[0];
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<ExecutionContext>() {
@@ -73,7 +60,6 @@ public class NotRegisteredBeansProblem implements RecipeSpringJavaProblemDescrip
for (SymbolAddOnInformation info : additionalInformation) {
if (info instanceof BeansSymbolAddOnInformation) {
BeansSymbolAddOnInformation info2 = (BeansSymbolAddOnInformation) info;
// log.info("Bean: id=" + info2.getBeanID() + ", type=" + info2.getBeanType());
return beanClassName.equals(info2.getBeanType());
}
}

View File

@@ -12,16 +12,19 @@ package org.springframework.ide.vscode.boot.java.rewrite.reconcile;
import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.springBootVersionGreaterOrEqual;
import java.util.List;
import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.SourceFile;
import org.openrewrite.Tree;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.Return;
import org.openrewrite.marker.Range;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.TypeUtils;
import org.openrewrite.marker.Range;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.boot.java.Boot3JavaProblemType;
import org.springframework.ide.vscode.commons.java.IJavaProject;
@@ -29,28 +32,16 @@ import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDes
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeSpringJavaProblemDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
public class PreciseBeanTypeProblem implements RecipeSpringJavaProblemDescriptor {
private static final String RECIPE_ID = "org.openrewrite.java.spring.boot3.PreciseBeanType";
private static final String LABEL = "Ensure concrete bean type";
private static final String MSG_KEY = "returnType";
@Override
public String getRecipeId() {
return "org.openrewrite.java.spring.boot3.PreciseBeanType";
}
@Override
public String getLabel(RecipeScope s) {
return RecipeCodeActionDescriptor.buildLabel(LABEL, s);
}
@Override
public RecipeScope[] getScopes() {
return RecipeScope.values();
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<>() {
@@ -62,8 +53,19 @@ public class PreciseBeanTypeProblem implements RecipeSpringJavaProblemDescriptor
if (o != null && !o.equals(m.getReturnTypeExpression().getType())) {
if ((o instanceof JavaType.FullyQualified && m.getReturnTypeExpression().getType() instanceof JavaType.FullyQualified)
|| (o instanceof JavaType.Array && m.getReturnTypeExpression().getType() instanceof JavaType.Array)) {
m = m.withReturnTypeExpression(m.getReturnTypeExpression().withMarkers(m.getReturnTypeExpression().getMarkers().add(
new FixAssistMarker(Tree.randomId(), getId()).withScope(m.getMarkers().findFirst(Range.class).get()).withRecipeId(getRecipeId()))));
String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toString();
FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), getId())
.withFixes(
new FixDescriptor(RECIPE_ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.NODE))
.withRecipeScope(RecipeScope.NODE)
.withRangeScope(m.getMarkers().findFirst(Range.class).get()),
new FixDescriptor(RECIPE_ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.FILE))
.withRecipeScope(RecipeScope.FILE),
new FixDescriptor(RECIPE_ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.PROJECT))
.withRecipeScope(RecipeScope.PROJECT)
);
m = m.withReturnTypeExpression(m.getReturnTypeExpression().withMarkers(m.getReturnTypeExpression().getMarkers().add(marker)));
}
}
}

View File

@@ -10,17 +10,84 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.rewrite.reconcile;
import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.springBootVersionGreaterOrEqual;
import java.util.Arrays;
import java.util.List;
import org.openrewrite.ExecutionContext;
import org.openrewrite.SourceFile;
import org.openrewrite.Tree;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.AnnotationMatcher;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J.ClassDeclaration;
import org.openrewrite.java.tree.JavaType.FullyQualified;
import org.openrewrite.java.tree.TypeUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
import org.springframework.ide.vscode.boot.java.rewrite.codeaction.UnnecessarySpringExtensionCodeAction;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeSpringJavaProblemDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
public class UnnecessarySpringExtensionProblem extends UnnecessarySpringExtensionCodeAction
implements RecipeSpringJavaProblemDescriptor {
public class UnnecessarySpringExtensionProblem implements RecipeSpringJavaProblemDescriptor {
private static final String LABEL = "Remove unnecessary @SpringExtension";
private static final String ID = "org.openrewrite.java.spring.boot2.UnnecessarySpringExtension";
private static final List<String> SPRING_BOOT_TEST_ANNOTATIONS = Arrays.asList(
"org.springframework.boot.test.context.SpringBootTest",
"org.springframework.boot.test.autoconfigure.jdbc.JdbcTest",
"org.springframework.boot.test.autoconfigure.web.client.RestClientTest",
"org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest",
"org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest",
"org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest",
"org.springframework.boot.test.autoconfigure.webservices.client.WebServiceClientTest",
"org.springframework.boot.test.autoconfigure.jooq.JooqTest",
"org.springframework.boot.test.autoconfigure.json.JsonTest",
"org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest",
"org.springframework.boot.test.autoconfigure.data.jdbc.DataJdbcTest",
"org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest",
"org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest",
"org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest",
"org.springframework.boot.test.autoconfigure.data.r2dbc.DataR2dbcTest",
"org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest"
);
private static final AnnotationMatcher SPRING_EXTENSION_ANNOTATIN_MATCHER = new AnnotationMatcher("@org.junit.jupiter.api.extension.ExtendWith(org.springframework.test.context.junit.jupiter.SpringExtension.class)");
@Override
public RecipeScope[] getScopes() {
return new RecipeScope[] { RecipeScope.FILE };
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<>() {
@Override
public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, ExecutionContext p) {
ClassDeclaration c = super.visitClassDeclaration(classDecl, p);
if (c.getLeadingAnnotations().stream().anyMatch(a -> {
FullyQualified fq = TypeUtils.asFullyQualified(a.getType());
return fq != null && SPRING_BOOT_TEST_ANNOTATIONS.contains(fq.getFullyQualifiedName());
})) {
c = c.withLeadingAnnotations(ListUtils.map(c.getLeadingAnnotations(), a -> {
if (SPRING_EXTENSION_ANNOTATIN_MATCHER.matches(a)) {
String uri = getCursor().firstEnclosing(SourceFile.class).getSourcePath().toUri().toString();
FixAssistMarker fixMarker = new FixAssistMarker(Tree.randomId(), getId())
.withFix(new FixDescriptor(ID, List.of(uri), RecipeCodeActionDescriptor.buildLabel(LABEL, RecipeScope.PROJECT)));
return a.withMarkers(a.getMarkers().add(fixMarker));
}
return a;
}));
}
return c;
}
};
}
@Override
public boolean isApplicable(IJavaProject project) {
return springBootVersionGreaterOrEqual(2, 1, 0).test(project);
}
@Override

View File

@@ -56,10 +56,16 @@
"defaultSeverity": "WARNING"
},
{
"code": "JAVA_BEAN_NOT_REGISTERED_IN_AOT",
"code": "JAVA_BEAN_POST_PROCESSOR_IGNORED_IN_AOT",
"label": "'BeanPostProcessor' behaviour is ignored in AOT",
"description": "'BeanPostProcessor' behaviour is ignored in Spring 6 AOT",
"defaultSeverity": "WARNING"
},
{
"code": "JAVA_BEAN_NOT_REGISTERED_IN_AOT",
"label": "Not registered as a Bean",
"description": "Not registered as Bean",
"defaultSeverity": "WARNING"
}
]
},

View File

@@ -336,7 +336,7 @@
"ERROR"
]
},
"spring-boot.ls.problem.boot3.JAVA_BEAN_NOT_REGISTERED_IN_AOT": {
"spring-boot.ls.problem.boot3.JAVA_BEAN_POST_PROCESSOR_IGNORED_IN_AOT": {
"type": "string",
"default": "WARNING",
"description": "'BeanPostProcessor' behaviour is ignored in Spring 6 AOT",
@@ -347,6 +347,18 @@
"HINT",
"ERROR"
]
},
"spring-boot.ls.problem.boot3.JAVA_BEAN_NOT_REGISTERED_IN_AOT": {
"type": "string",
"default": "WARNING",
"description": "Not registered as Bean",
"enum": [
"IGNORE",
"INFO",
"WARNING",
"HINT",
"ERROR"
]
}
}
},