Mark not registered bean for AOT

This commit is contained in:
aboyko
2022-10-04 15:13:09 -04:00
parent 2ff5850896
commit 4db1297ac8
24 changed files with 235 additions and 80 deletions

View File

@@ -16,6 +16,7 @@ import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J.MethodDeclaration;
import org.openrewrite.marker.Range;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemCategory;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity;
@@ -44,14 +45,14 @@ public class HelloMethodRenameProblemDescriptor implements RecipeSpringJavaProbl
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor() {
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<>() {
@Override
public MethodDeclaration visitMethodDeclaration(MethodDeclaration method, ExecutionContext p) {
MethodDeclaration m = super.visitMethodDeclaration(method, p);
if ("hello".equals(method.getSimpleName())) {
FixAssistMarker marker = new FixAssistMarker(Tree.randomId()).withRecipeId(getRecipeId()).withScope(m.getMarkers().findFirst(Range.class).get());
FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), getId()).withRecipeId(getRecipeId()).withScope(m.getMarkers().findFirst(Range.class).get());
m = m.withName(m.getName().withMarkers(m.getName().getMarkers().add(marker)));
}
return m;

View File

@@ -12,17 +12,22 @@ package org.springframework.ide.vscode.commons.rewrite.config;
import org.openrewrite.ExecutionContext;
import org.openrewrite.java.JavaVisitor;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.commons.java.IJavaProject;
public interface RecipeCodeActionDescriptor {
default String getId() {
return getClass().getName();
}
String getRecipeId();
String getLabel(RecipeScope s);
RecipeScope[] getScopes();
JavaVisitor<ExecutionContext> getMarkerVisitor();
JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext);
boolean isApplicable(IJavaProject project);

View File

@@ -16,11 +16,14 @@ public class FixAssistMarker implements Marker {
private String recipeId;
private String descriptorId;
private Map<String, Object> parameters = Collections.emptyMap();
public FixAssistMarker(UUID id) {
public FixAssistMarker(UUID id, String descriptorId) {
super();
this.id = id;
this.descriptorId = descriptorId;
}
@Override
@@ -62,9 +65,13 @@ public class FixAssistMarker implements Marker {
return parameters;
}
public String getDescriptorId() {
return descriptorId;
}
@Override
public int hashCode() {
return Objects.hash(id);
return Objects.hash(descriptorId, id, parameters, recipeId, scope);
}
@Override
@@ -76,7 +83,10 @@ public class FixAssistMarker implements Marker {
if (getClass() != obj.getClass())
return false;
FixAssistMarker other = (FixAssistMarker) obj;
return Objects.equals(id, other.id);
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);
}
}

View File

@@ -182,6 +182,8 @@ public class BootLanguageServerInitializer implements InitializingBean {
server.getWorkspaceService().getFileObserver().onFilesChanged(FILES_TO_WATCH_GLOB, this::handleFiles);
server.getWorkspaceService().getFileObserver().onFilesCreated(FILES_TO_WATCH_GLOB, this::handleFiles);
springIndexer.onUpdate(v -> reconcile());
}
private void reconcile() {

View File

@@ -29,6 +29,7 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -62,6 +63,7 @@ import org.springframework.ide.vscode.commons.languageserver.java.FutureProjectF
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver.Listener;
import org.springframework.ide.vscode.commons.languageserver.util.ListenerList;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleWorkspaceService;
@@ -97,8 +99,8 @@ public class SpringSymbolIndex implements InitializingBean {
private final ExecutorService updateQueue = Executors.newSingleThreadExecutor();
private SpringIndexer[] indexers;
private ListenerList<Void> listeners = new ListenerList<Void>();
private static final Logger log = LoggerFactory.getLogger(SpringSymbolIndex.class);
private final Listener projectListener = new Listener() {
@@ -310,7 +312,9 @@ public class SpringSymbolIndex implements InitializingBean {
futures[i] = CompletableFuture.runAsync(initializeItem, this.updateQueue);
}
return CompletableFuture.allOf(futures);
CompletableFuture<Void> future = CompletableFuture.allOf(futures);
future.thenAccept(v -> listeners.fire(v));
return future;
}
} else {
return deleteProject(project);
@@ -388,7 +392,9 @@ public class SpringSymbolIndex implements InitializingBean {
}
}
return CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()]));
CompletableFuture<Void> future = CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()]));
future.thenAccept(v -> listeners.fire(v));
return future;
}
}
@@ -445,7 +451,9 @@ public class SpringSymbolIndex implements InitializingBean {
}
}
}
return CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()]));
CompletableFuture<Void> future = CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()]));
future.thenAccept(v -> listeners.fire(v));
return future;
}
}
@@ -512,7 +520,9 @@ public class SpringSymbolIndex implements InitializingBean {
futures.add(CompletableFuture.runAsync(deleteItems, this.updateQueue));
}
return CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()]));
CompletableFuture<Void> future = CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()]));
future.thenAccept(v -> listeners.fire(v));
return future;
}
catch (Exception e) {
log.error("", e);
@@ -869,4 +879,8 @@ public class SpringSymbolIndex implements InitializingBean {
}
}
public void onUpdate(Consumer<Void> listener) {
listeners.add(listener);
}
}

View File

@@ -25,7 +25,9 @@ public enum Boot3JavaProblemType implements ProblemType {
JAVA_CONCRETE_BEAN_TYPE(WARNING, "Bean definition should have precise type for Spring 6 AOT", "Not precise bean defintion type"),
JAVA_BEAN_NOT_REGISTERED_IN_AOT(WARNING, "'BeanPostProcessor' behaviour is ignored in Spring 6 AOT", "'BeanPostProcessor' behaviour is ignored in AOT");
JAVA_BEAN_POST_PROCESSOR_IGNORED_IN_AOT(WARNING, "'BeanPostProcessor' behaviour is ignored in Spring 6 AOT", "'BeanPostProcessor' behaviour is ignored in AOT"),
JAVA_BEAN_NOT_REGISTERED_IN_AOT(WARNING, "Not registered as Bean", "Not registered as a Bean");
private final ProblemSeverity defaultSeverity;
private String description;

View File

@@ -18,13 +18,19 @@ import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
public class BeansSymbolAddOnInformation implements SymbolAddOnInformation {
private final String beanID;
private final String beanType;
public BeansSymbolAddOnInformation(String beanID) {
public BeansSymbolAddOnInformation(String beanID, String beanType) {
this.beanID = beanID;
this.beanType = beanType;
}
public String getBeanID() {
return beanID;
}
public String getBeanType() {
return beanType;
}
}

View File

@@ -63,16 +63,16 @@ public class BeansSymbolProvider extends AbstractSymbolProvider {
if (isMethodAbstract(node)) return;
boolean isFunction = isFunctionBean(node);
String beanType = getBeanType(node);
ITypeBinding beanType = getBeanType(node);
String markerString = getAnnotations(node);
for (Tuple2<String, DocumentRegion> nameAndRegion : getBeanNames(node, doc)) {
try {
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(
new WorkspaceSymbol(
beanLabel(isFunction, nameAndRegion.getT1(), beanType, "@Bean" + markerString),
beanLabel(isFunction, nameAndRegion.getT1(), beanType.getName(), "@Bean" + markerString),
SymbolKind.Interface,
Either.forLeft(new Location(doc.getUri(), doc.toRange(nameAndRegion.getT2())))),
new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(nameAndRegion.getT1())}
new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(nameAndRegion.getT1(), beanType.getQualifiedName())}
);
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
@@ -86,16 +86,16 @@ public class BeansSymbolProvider extends AbstractSymbolProvider {
@Override
protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
// this checks function beans that are defined as implementations of Function interfaces
Tuple3<String, String, DocumentRegion> functionBean = FunctionUtils.getFunctionBean(typeDeclaration, doc);
Tuple3<String, ITypeBinding, DocumentRegion> functionBean = FunctionUtils.getFunctionBean(typeDeclaration, doc);
if (functionBean != null) {
try {
WorkspaceSymbol symbol = new WorkspaceSymbol(
beanLabel(true, functionBean.getT1(), functionBean.getT2(), null),
beanLabel(true, functionBean.getT1(), functionBean.getT2().getName(), null),
SymbolKind.Interface,
Either.forLeft(new Location(doc.getUri(), doc.toRange(functionBean.getT3()))));
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(),
new EnhancedSymbolInformation(symbol, new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(functionBean.getT1())})));
new EnhancedSymbolInformation(symbol, new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(functionBean.getT1(), functionBean.getT2().getQualifiedName())})));
} catch (BadLocationException e) {
log.error("", e);
@@ -153,12 +153,11 @@ public class BeansSymbolProvider extends AbstractSymbolProvider {
return literals.build();
}
protected String getBeanType(Annotation node) {
protected ITypeBinding getBeanType(Annotation node) {
ASTNode parent = node.getParent();
if (parent instanceof MethodDeclaration) {
MethodDeclaration method = (MethodDeclaration) parent;
String returnType = method.getReturnType2().resolveBinding().getName();
return returnType;
return method.getReturnType2().resolveBinding();
}
return null;
}

View File

@@ -59,13 +59,13 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
.map(ITypeBinding::getName)
.collect(Collectors.toList());
String beanName = getBeanName(node);
String beanType = getBeanType(node);
ITypeBinding beanType = getBeanType(node);
WorkspaceSymbol symbol = new WorkspaceSymbol(
beanLabel("+", annotationTypeName, metaAnnotationNames, beanName, beanType), SymbolKind.Interface,
beanLabel("+", annotationTypeName, metaAnnotationNames, beanName, beanType.getName()), SymbolKind.Interface,
Either.forLeft(new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()))));
SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(beanName)};
SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(beanName, beanType.getQualifiedName())};
return new EnhancedSymbolInformation(symbol, addon);
}
@@ -108,12 +108,11 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
return null;
}
private String getBeanType(Annotation node) {
private ITypeBinding getBeanType(Annotation node) {
ASTNode parent = node.getParent();
if (parent instanceof TypeDeclaration) {
TypeDeclaration type = (TypeDeclaration) parent;
String returnType = type.resolveBinding().getName();
return returnType;
return type.resolveBinding();
}
return null;
}

View File

@@ -43,15 +43,15 @@ public class DataRepositorySymbolProvider extends AbstractSymbolProvider {
@Override
protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
// this checks spring data repository beans that are defined as extensions of the repository interface
Tuple4<String, String, String, DocumentRegion> repositoryBean = getRepositoryBean(typeDeclaration, doc);
Tuple4<String, ITypeBinding, String, DocumentRegion> repositoryBean = getRepositoryBean(typeDeclaration, doc);
if (repositoryBean != null) {
try {
WorkspaceSymbol symbol = new WorkspaceSymbol(
beanLabel(true, repositoryBean.getT1(), repositoryBean.getT2(), repositoryBean.getT3()),
beanLabel(true, repositoryBean.getT1(), repositoryBean.getT2().getName(), repositoryBean.getT3()),
SymbolKind.Interface,
Either.forLeft(new Location(doc.getUri(), doc.toRange(repositoryBean.getT4()))));
SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(repositoryBean.getT1())};
SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(repositoryBean.getT1(), repositoryBean.getT2().getQualifiedName())};
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, addon);
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
@@ -76,7 +76,7 @@ public class DataRepositorySymbolProvider extends AbstractSymbolProvider {
return symbolLabel.toString();
}
private static Tuple4<String, String, String, DocumentRegion> getRepositoryBean(TypeDeclaration typeDeclaration, TextDocument doc) {
private static Tuple4<String, ITypeBinding, String, DocumentRegion> getRepositoryBean(TypeDeclaration typeDeclaration, TextDocument doc) {
ITypeBinding resolvedType = typeDeclaration.resolveBinding();
if (resolvedType != null) {
@@ -87,7 +87,7 @@ public class DataRepositorySymbolProvider extends AbstractSymbolProvider {
}
}
private static Tuple4<String, String, String, DocumentRegion> getRepositoryBean(TypeDeclaration typeDeclaration, TextDocument doc,
private static Tuple4<String, ITypeBinding, String, DocumentRegion> getRepositoryBean(TypeDeclaration typeDeclaration, TextDocument doc,
ITypeBinding resolvedType) {
ITypeBinding[] interfaces = resolvedType.getInterfaces();
@@ -102,7 +102,6 @@ public class DataRepositorySymbolProvider extends AbstractSymbolProvider {
if (Constants.REPOSITORY_TYPE.equals(simplifiedType)) {
String beanName = getBeanName(typeDeclaration);
String beanType = resolvedInterface.getName();
String domainType = null;
if (resolvedInterface.isParameterizedType()) {
@@ -113,10 +112,10 @@ public class DataRepositorySymbolProvider extends AbstractSymbolProvider {
}
DocumentRegion region = ASTUtils.nodeRegion(doc, typeDeclaration.getName());
return Tuples.of(beanName, beanType, domainType, region);
return Tuples.of(beanName, resolvedInterface, domainType, region);
}
else {
Tuple4<String, String, String, DocumentRegion> result = getRepositoryBean(typeDeclaration, doc, resolvedInterface);
Tuple4<String, ITypeBinding, String, DocumentRegion> result = getRepositoryBean(typeDeclaration, doc, resolvedInterface);
if (result != null) {
return result;
}

View File

@@ -16,9 +16,10 @@ import org.springframework.ide.vscode.boot.java.rewrite.codeaction.AutowiredFiel
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.BeanPostProcessingIgnoreInAotProblem;
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;
import org.springframework.ide.vscode.boot.java.rewrite.reconcile.NotRegisteredBeansProblem;
import org.springframework.ide.vscode.boot.java.rewrite.reconcile.PreciseBeanTypeProblem;
import org.springframework.ide.vscode.boot.java.rewrite.reconcile.UnnecessarySpringExtensionProblem;
import org.springframework.ide.vscode.commons.rewrite.config.CodeActionRepository;
@@ -44,7 +45,8 @@ public class BootCodeActionRepository extends CodeActionRepository {
new NoAutowiredOnConstructorProblem(),
new UnnecessarySpringExtensionProblem(),
new PreciseBeanTypeProblem(),
new BeanPostProcessingIgnoreInAotProblem()
new BeanPostProcessingIgnoreInAotProblem(),
new NotRegisteredBeansProblem()
);
}

View File

@@ -156,7 +156,7 @@ public class RewriteCodeActionHandler implements JavaCodeActionHandler {
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.getRecipeId());
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))

View File

@@ -49,12 +49,14 @@ import org.openrewrite.TreeVisitor;
import org.openrewrite.Validated;
import org.openrewrite.config.RecipeDescriptor;
import org.openrewrite.config.YamlResourceLoader;
import org.openrewrite.internal.RecipeIntrospectionUtils;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.openrewrite.maven.MavenParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.ide.vscode.boot.app.BootJavaConfig;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
@@ -77,7 +79,7 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
public class RewriteRecipeRepository {
public class RewriteRecipeRepository implements ApplicationContextAware {
private static final String CMD_REWRITE_RELOAD = "sts/rewrite/reload";
private static final String CMD_REWRITE_EXECUTE = "sts/rewrite/execute";
@@ -101,6 +103,8 @@ public class RewriteRecipeRepository {
final private ListenerList<Void> loadListeners;
private ApplicationContext applicationContext;
private CompletableFuture<Void> loaded;
private Set<String> scanFiles = Collections.emptySet();
@@ -235,7 +239,7 @@ public class RewriteRecipeRepository {
public RecipeSpringJavaProblemDescriptor getProblemRecipeDescriptor(String id) {
for (RecipeSpringJavaProblemDescriptor d : javaProblemDescriptors) {
if (id.equals(d.getRecipeId())) {
if (id.equals(d.getId())) {
return d;
}
}
@@ -244,7 +248,7 @@ public class RewriteRecipeRepository {
public RecipeCodeActionDescriptor getCodeActionRecipeDescriptor(String id) {
for (RecipeCodeActionDescriptor d : codeActionDescriptors) {
if (id.equals(d.getRecipeId())) {
if (id.equals(d.getId())) {
return d;
}
}
@@ -272,13 +276,9 @@ public class RewriteRecipeRepository {
public CompilationUnit mark(List<? extends RecipeCodeActionDescriptor> descriptors, CompilationUnit compilationUnit) {
CompilationUnit cu = compilationUnit;
for (RecipeCodeActionDescriptor d : descriptors) {
Recipe recipe = getRecipe(d.getRecipeId()).orElse(null);
if (recipe != null) {
TreeVisitor<?, ExecutionContext> isApplicableVisitor = RecipeIntrospectionUtils.recipeSingleSourceApplicableTest(recipe);
TreeVisitor<?, ExecutionContext> markVisitor = d.getMarkerVisitor();
if (markVisitor != null && (isApplicableVisitor == null || isApplicableVisitor.visit(cu, new InMemoryExecutionContext(e -> log.error("", e))) != cu)) {
cu = (CompilationUnit) markVisitor.visit(cu, new InMemoryExecutionContext(e -> log.error("", e)));
}
TreeVisitor<?, ExecutionContext> markVisitor = d.getMarkerVisitor(applicationContext);
if (markVisitor != null) {
cu = (CompilationUnit) markVisitor.visit(cu, new InMemoryExecutionContext(e -> log.error("", e)));
}
}
return cu;
@@ -447,6 +447,11 @@ public class RewriteRecipeRepository {
public void onRecipesLoaded(Consumer<Void> l) {
loadListeners.add(l);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
// private static Recipe convert(Recipe r, RecipeDescriptor d) {
// try {

View File

@@ -101,21 +101,21 @@ public class RewriteReconciler implements JavaReconciler {
if (astNode != null) {
Range range = astNode.getMarkers().findFirst(Range.class).orElse(null);
if (range != null) {
RecipeSpringJavaProblemDescriptor recipeFixDescriptor = recipeRepo.getProblemRecipeDescriptor(m.getRecipeId());
if (recipeFixDescriptor != null && recipeFixDescriptor.getScopes() != null && recipeRepo.getRecipe(recipeFixDescriptor.getRecipeId()).isPresent()) {
return List.of(createProblemFromScope(doc, recipeFixDescriptor, m, range));
RecipeSpringJavaProblemDescriptor recipeFixDescriptor = recipeRepo.getProblemRecipeDescriptor(m.getDescriptorId());
if (recipeFixDescriptor != null) {
return List.of(createProblem(doc, recipeFixDescriptor, m, range));
}
}
}
return Collections.emptyList();
}
private ReconcileProblemImpl createProblemFromScope(IDocument doc, RecipeSpringJavaProblemDescriptor recipeFixDescriptor,
private ReconcileProblemImpl createProblem(IDocument doc, RecipeSpringJavaProblemDescriptor recipeFixDescriptor,
FixAssistMarker m, Range range) {
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) {
if (quickfixType != null && m.getRecipeId() != null && recipeRepo.getRecipe(recipeFixDescriptor.getRecipeId()).isPresent()) {
for (RecipeScope s : recipeFixDescriptor.getScopes()) {
problem.addQuickfix(new QuickfixData<>(
quickfixType,

View File

@@ -30,6 +30,7 @@ import org.openrewrite.java.tree.J.VariableDeclarations;
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;
@@ -59,7 +60,7 @@ public class AutowiredFieldIntoConstructorParameterCodeAction implements RecipeC
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor() {
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<>() {
@Override
@@ -75,7 +76,7 @@ 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();
FixAssistMarker marker = new FixAssistMarker(Tree.randomId())
FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), getId())
.withRecipeId(getRecipeId())
.withScope(classDeclaration.getMarkers().findFirst(Range.class).get())
.withParameters(Map.of("classFqName", fqType.getFullyQualifiedName(), "fieldName", fieldName));

View File

@@ -19,6 +19,7 @@ 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;
@@ -49,7 +50,7 @@ public class BeanMethodsNotPublicCodeAction implements RecipeCodeActionDescripto
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor() {
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<ExecutionContext>() {
@Override
@@ -59,7 +60,7 @@ public class BeanMethodsNotPublicCodeAction implements RecipeCodeActionDescripto
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())
FixAssistMarker fixAssistMarker = new FixAssistMarker(Tree.randomId(), getId())
.withRecipeId(ID)
.withScope(m.getMarkers().findFirst(Range.class).get());
m = m.withModifiers(ListUtils.map(m.getModifiers(), modifier -> {

View File

@@ -19,6 +19,7 @@ import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J;
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;
@@ -46,13 +47,13 @@ public class NoRequestMappingAnnotationCodeAction implements RecipeCodeActionDes
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor() {
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<ExecutionContext>() {
@Override
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) {
FixAssistMarker fixAssistMarker = new FixAssistMarker(Tree.randomId())
FixAssistMarker fixAssistMarker = new FixAssistMarker(Tree.randomId(), getId())
.withRecipeId(getRecipeId())
.withScope(a.getMarkers().findFirst(Range.class).get());
a = a.withMarkers(a.getMarkers().add(fixAssistMarker));

View File

@@ -25,6 +25,7 @@ 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;
@@ -70,7 +71,7 @@ public class UnnecessarySpringExtensionCodeAction implements RecipeCodeActionDes
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor() {
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<>() {
@Override
@@ -83,7 +84,7 @@ public class UnnecessarySpringExtensionCodeAction implements RecipeCodeActionDes
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()).withRecipeId(ID).withScope(range)));
return a.withMarkers(a.getMarkers().add(new FixAssistMarker(Tree.randomId(), getId()).withRecipeId(ID).withScope(range)));
}
return a;
}));

View File

@@ -22,6 +22,7 @@ import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J.ClassDeclaration;
import org.openrewrite.java.tree.J.MethodDeclaration;
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;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
@@ -51,7 +52,7 @@ public class BeanPostProcessingIgnoreInAotProblem implements RecipeSpringJavaPro
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor() {
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<ExecutionContext>() {
@Override
@@ -62,7 +63,7 @@ public class BeanPostProcessingIgnoreInAotProblem implements RecipeSpringJavaPro
.filter(MethodDeclaration.class::isInstance).map(MethodDeclaration.class::cast)
.filter(BeanPostProcessingIgnoreInAot::isApplicableMethod)
.collect(Collectors.toList());
FixAssistMarker marker = new FixAssistMarker(Tree.randomId())
FixAssistMarker marker = new FixAssistMarker(Tree.randomId(), getId())
.withRecipeId(getRecipeId())
.withScope(classDecl.getMarkers().findFirst(Range.class).orElse(null));
if (methods.isEmpty()) {
@@ -89,7 +90,7 @@ public class BeanPostProcessingIgnoreInAotProblem implements RecipeSpringJavaPro
@Override
public ProblemType getProblemType() {
return Boot3JavaProblemType.JAVA_BEAN_NOT_REGISTERED_IN_AOT;
return Boot3JavaProblemType.JAVA_BEAN_POST_PROCESSOR_IGNORED_IN_AOT;
}
}

View File

@@ -24,6 +24,7 @@ import org.openrewrite.java.tree.JavaType.FullyQualified;
import org.openrewrite.marker.Range;
import org.openrewrite.java.tree.Statement;
import org.openrewrite.java.tree.TypeUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
import org.springframework.ide.vscode.commons.java.IJavaProject;
@@ -53,7 +54,7 @@ public class NoAutowiredOnConstructorProblem implements RecipeSpringJavaProblemD
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor() {
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<ExecutionContext>() {
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext context) {
J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, context);
@@ -76,7 +77,7 @@ public class NoAutowiredOnConstructorProblem implements RecipeSpringJavaProblemD
return s;
}
MethodDeclaration constructor = (MethodDeclaration) s;
FixAssistMarker fixAssistMarker = new FixAssistMarker(Tree.randomId())
FixAssistMarker fixAssistMarker = new FixAssistMarker(Tree.randomId(), getId())
.withRecipeId(ID)
.withScope(getCursor().firstEnclosing(ClassDeclaration.class).getMarkers().findFirst(Range.class).get());
constructor = constructor.withLeadingAnnotations(ListUtils.map(constructor.getLeadingAnnotations(), a -> {

View File

@@ -0,0 +1,104 @@
package org.springframework.ide.vscode.boot.java.rewrite.reconcile;
import static org.springframework.ide.vscode.commons.java.SpringProjectUtil.springBootVersionGreaterOrEqual;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.lsp4j.WorkspaceSymbol;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Tree;
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.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;
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation;
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>() {
@Override
public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, ExecutionContext p) {
ClassDeclaration c = super.visitClassDeclaration(classDecl, p);
FullyQualified type = c.getType();
if (type != null) {
String beanClassName = type.getFullyQualifiedName();
boolean applicable = AOT_BEANS.stream().filter(fqName -> TypeUtils.isAssignableTo(fqName, type)).findFirst().isPresent();
if (applicable) {
SpringSymbolIndex index = applicationContext.getBean(SpringSymbolIndex.class);
List<WorkspaceSymbol> beanSymbols = index.getSymbols(data -> {
SymbolAddOnInformation[] additionalInformation = data.getAdditionalInformation();
if (additionalInformation != null) {
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());
}
}
}
return false;
}).limit(1).collect(Collectors.toList());
if (beanSymbols.isEmpty()) {
return c = c.withName(c.getName().withMarkers(c.getName().getMarkers().add(new FixAssistMarker(Tree.randomId(), getId()))));
}
}
}
return c;
}
};
}
@Override
public boolean isApplicable(IJavaProject project) {
return springBootVersionGreaterOrEqual(3, 0, 0).test(project);
}
@Override
public ProblemType getProblemType() {
return Boot3JavaProblemType.JAVA_BEAN_NOT_REGISTERED_IN_AOT;
}
}

View File

@@ -22,6 +22,7 @@ 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.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.boot.java.Boot3JavaProblemType;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
@@ -51,7 +52,7 @@ public class PreciseBeanTypeProblem implements RecipeSpringJavaProblemDescriptor
}
@Override
public JavaVisitor<ExecutionContext> getMarkerVisitor() {
public JavaVisitor<ExecutionContext> getMarkerVisitor(ApplicationContext applicationContext) {
return new JavaIsoVisitor<>() {
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext executionContext) {
@@ -62,7 +63,7 @@ public class PreciseBeanTypeProblem implements RecipeSpringJavaProblemDescriptor
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()).withScope(m.getMarkers().findFirst(Range.class).get()).withRecipeId(getRecipeId()))));
new FixAssistMarker(Tree.randomId(), getId()).withScope(m.getMarkers().findFirst(Range.class).get()).withRecipeId(getRecipeId()))));
}
}
}

View File

@@ -34,7 +34,7 @@ public class FunctionUtils {
public static final String FUNCTION_CONSUMER_TYPE = Consumer.class.getName();
public static final String FUNCTION_SUPPLIER_TYPE = Supplier.class.getName();
public static Tuple3<String, String, DocumentRegion> getFunctionBean(TypeDeclaration typeDeclaration, TextDocument doc) {
public static Tuple3<String, ITypeBinding, DocumentRegion> getFunctionBean(TypeDeclaration typeDeclaration, TextDocument doc) {
ITypeBinding resolvedType = typeDeclaration.resolveBinding();
if (resolvedType != null && !resolvedType.isInterface() && !isAbstractClass(typeDeclaration, resolvedType)) {
@@ -45,7 +45,7 @@ public class FunctionUtils {
}
}
private static Tuple3<String, String, DocumentRegion> getFunctionBean(TypeDeclaration typeDeclaration, TextDocument doc,
private static Tuple3<String, ITypeBinding, DocumentRegion> getFunctionBean(TypeDeclaration typeDeclaration, TextDocument doc,
ITypeBinding resolvedType) {
ITypeBinding[] interfaces = resolvedType.getInterfaces();
@@ -61,13 +61,12 @@ public class FunctionUtils {
if (FUNCTION_FUNCTION_TYPE.equals(simplifiedType) || FUNCTION_CONSUMER_TYPE.equals(simplifiedType)
|| FUNCTION_SUPPLIER_TYPE.equals(simplifiedType)) {
String beanName = getBeanName(typeDeclaration);
String beanType = resolvedInterface.getName();
DocumentRegion region = ASTUtils.nodeRegion(doc, typeDeclaration.getName());
return Tuples.of(beanName, beanType, region);
return Tuples.of(beanName, resolvedInterface, region);
}
else {
Tuple3<String, String, DocumentRegion> result = getFunctionBean(typeDeclaration, doc, resolvedInterface);
Tuple3<String, ITypeBinding, DocumentRegion> result = getFunctionBean(typeDeclaration, doc, resolvedInterface);
if (result != null) {
return result;
}

View File

@@ -47,6 +47,7 @@ public class SpringIndexerXMLNamespaceHandlerBeans implements SpringIndexerXMLNa
int symbolEnd = 0;
String beanClass = null;
String fqBeanClass = null;
List<DOMAttr> attributes = node.getAttributeNodes();
for (DOMAttr attribute : attributes) {
@@ -59,8 +60,8 @@ public class SpringIndexerXMLNamespaceHandlerBeans implements SpringIndexerXMLNa
symbolEnd = attribute.getEnd();
}
else if (name != null && name.equals("class")) {
String value = attribute.getValue();
beanClass = value.substring(value.lastIndexOf(".") + 1);
fqBeanClass = attribute.getValue();
beanClass = fqBeanClass.substring(fqBeanClass.lastIndexOf(".") + 1);
if (symbolStart == 0 && symbolEnd == 0) {
symbolStart = attribute.getStart();
@@ -89,7 +90,7 @@ public class SpringIndexerXMLNamespaceHandlerBeans implements SpringIndexerXMLNa
}
WorkspaceSymbol symbol = new WorkspaceSymbol("@+ '" + beanID + "' " + beanClass, SymbolKind.Interface, Either.forLeft(new Location(docURI, range)));
SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(beanID)};
SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(beanID, fqBeanClass)};
EnhancedSymbolInformation fullSymbol = new EnhancedSymbolInformation(symbol, addon);