From c653d3cab6fea7d7817ee5c0ac5ad35360fdff66 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Thu, 30 Mar 2023 22:10:17 +0200 Subject: [PATCH] added type compatibility checks for beans --- .../ide/vscode/boot/index/Bean.java | 14 ++++++- .../ide/vscode/boot/index/InjectionPoint.java | 2 +- .../boot/index/SpringMetamodelIndex.java | 6 +-- .../boot/java/beans/BeansSymbolProvider.java | 8 +++- .../java/beans/ComponentSymbolProvider.java | 8 +++- .../ide/vscode/boot/java/utils/ASTUtils.java | 38 +++++++++++++++++++ .../test/SpringMetamodelIndexerBeansTest.java | 19 ++++++++++ .../java/org/test/BeanWithSupertypes.java | 11 ++++++ .../AbstractBeanWithSupertypes.java | 5 +++ ...BaseClassOfAbstractBeanWithSupertypes.java | 5 +++ .../Interface1OfBeanWithSupertypes.java | 5 +++ .../Interface2OfBeanWithSupertypes.java | 5 +++ .../supertypes/InterfaceOfAbstractBean.java | 5 +++ 13 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/BeanWithSupertypes.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/AbstractBeanWithSupertypes.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/BaseClassOfAbstractBeanWithSupertypes.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/Interface1OfBeanWithSupertypes.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/Interface2OfBeanWithSupertypes.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/InterfaceOfAbstractBean.java diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/Bean.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/Bean.java index 077d9bf25..6824f680b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/Bean.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/Bean.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2032 VMware, Inc. + * Copyright (c) 2023 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 @@ -10,6 +10,10 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.index; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + import org.eclipse.lsp4j.Location; public class Bean { @@ -18,13 +22,15 @@ public class Bean { private final String type; private final Location location; private final InjectionPoint[] injectionPoints; + private final Set supertypes; - public Bean(String name, String type, Location location, InjectionPoint[] injectionPoints) { + public Bean(String name, String type, Location location, InjectionPoint[] injectionPoints, String[] supertypes) { this.name = name; this.type = type; this.location = location; this.injectionPoints = injectionPoints; + this.supertypes = new HashSet<>(Arrays.asList(supertypes)); } public String getName() { @@ -42,5 +48,9 @@ public class Bean { public InjectionPoint[] getInjectionPoints() { return injectionPoints; } + + public boolean isTypeCompatibleWith(String type) { + return supertypes.contains(type); + } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/InjectionPoint.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/InjectionPoint.java index 70ea4bf13..796e89247 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/InjectionPoint.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/InjectionPoint.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2032 VMware, Inc. + * Copyright (c) 2023 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 diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java index 10380b55e..12caf3eff 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2032 VMware, Inc. + * Copyright (c) 2023 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 @@ -28,8 +28,8 @@ public class SpringMetamodelIndex { return this.beans.stream().filter(bean -> bean.getName().equals(name)).collect(Collectors.toList()).toArray(new Bean[0]); } - public void registerBean(String name, String type, Location location, InjectionPoint[] injectionPoints) { - Bean bean = new Bean(name, type, location, injectionPoints); + public void registerBean(String name, String type, Location location, InjectionPoint[] injectionPoints, String[] supertypes) { + Bean bean = new Bean(name, type, location, injectionPoints, supertypes); this.beans.add(bean); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java index 019a03376..e92e664d8 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java @@ -12,7 +12,9 @@ package org.springframework.ide.vscode.boot.java.beans; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Annotation; @@ -91,7 +93,11 @@ public class BeansSymbolProvider extends AbstractSymbolProvider { context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); InjectionPoint[] injectionPoints = findInjectionPoints(node, doc); - springIndex.registerBean(nameAndRegion.getT1(), beanType.getQualifiedName(), location, injectionPoints); + + Set supertypes = new HashSet<>(); + ASTUtils.findSupertypes(beanType, supertypes); + + springIndex.registerBean(nameAndRegion.getT1(), beanType.getQualifiedName(), location, injectionPoints, (String[]) supertypes.toArray(new String[supertypes.size()])); } catch (BadLocationException e) { log.error("", e); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java index 0e5323bf8..023ffa97f 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java @@ -12,7 +12,9 @@ package org.springframework.ide.vscode.boot.java.beans; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import org.eclipse.jdt.core.dom.ASTNode; @@ -93,7 +95,11 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider { } InjectionPoint[] injectionPoints = findInjectionPoints(node, doc); - springIndex.registerBean(beanName, beanType.getQualifiedName(), location, injectionPoints); + + Set supertypes = new HashSet<>(); + ASTUtils.findSupertypes(beanType, supertypes); + + springIndex.registerBean(beanName, beanType.getQualifiedName(), location, injectionPoints, (String[]) supertypes.toArray(new String[supertypes.size()])); return new EnhancedSymbolInformation(symbol, addon); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java index c042f5b59..443803735 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java @@ -15,6 +15,7 @@ import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.function.Consumer; import java.util.stream.Stream; @@ -344,4 +345,41 @@ public class ASTUtils { return result; } + public static void findSupertypes(ITypeBinding binding, Set supertypesCollector) { + + // interfaces + ITypeBinding[] interfaces = binding.getInterfaces(); + for (ITypeBinding resolvedInterface : interfaces) { + String simplifiedType = null; + if (resolvedInterface.isParameterizedType()) { + simplifiedType = resolvedInterface.getBinaryName(); + } + else { + simplifiedType = resolvedInterface.getQualifiedName(); + } + + if (simplifiedType != null) { + supertypesCollector.add(simplifiedType); + findSupertypes(resolvedInterface, supertypesCollector); + } + } + + // superclasses + ITypeBinding superclass = binding.getSuperclass(); + if (superclass != null) { + String simplifiedType = null; + if (superclass.isParameterizedType()) { + simplifiedType = superclass.getBinaryName(); + } + else { + simplifiedType = superclass.getQualifiedName(); + } + + if (simplifiedType != null) { + supertypesCollector.add(simplifiedType); + findSupertypes(superclass, supertypesCollector); + } + } + } + } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metamodel/test/SpringMetamodelIndexerBeansTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metamodel/test/SpringMetamodelIndexerBeansTest.java index a23574fa5..9e9adc9d9 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metamodel/test/SpringMetamodelIndexerBeansTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metamodel/test/SpringMetamodelIndexerBeansTest.java @@ -11,7 +11,9 @@ package org.springframework.ide.vscode.boot.metamodel.test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.util.concurrent.CompletableFuture; @@ -202,4 +204,21 @@ public class SpringMetamodelIndexerBeansTest { assertEquals(ip2Location, injectionPoints[1].getLocation()); } + @Test + void testBeansWithSupertypes() { + Bean[] beans = springIndex.getBeans("beanWithSupertypes"); + assertEquals(1, beans.length); + + assertTrue(beans[0].isTypeCompatibleWith("java.lang.Object")); + assertTrue(beans[0].isTypeCompatibleWith("org.test.supertypes.AbstractBeanWithSupertypes")); + assertTrue(beans[0].isTypeCompatibleWith("org.test.supertypes.Interface1OfBeanWithSupertypes")); + assertTrue(beans[0].isTypeCompatibleWith("org.test.supertypes.Interface2OfBeanWithSupertypes")); + assertTrue(beans[0].isTypeCompatibleWith("org.test.supertypes.InterfaceOfAbstractBean")); + assertTrue(beans[0].isTypeCompatibleWith("org.test.supertypes.BaseClassOfAbstractBeanWithSupertypes")); + + assertFalse(beans[0].isTypeCompatibleWith("java.lang.String")); + assertFalse(beans[0].isTypeCompatibleWith("java.util.Comparator")); + + } + } diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/BeanWithSupertypes.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/BeanWithSupertypes.java new file mode 100644 index 000000000..7b9f4d759 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/BeanWithSupertypes.java @@ -0,0 +1,11 @@ +package org.test; + +import org.springframework.stereotype.Component; +import org.test.supertypes.AbstractBeanWithSupertypes; +import org.test.supertypes.Interface1OfBeanWithSupertypes; +import org.test.supertypes.Interface2OfBeanWithSupertypes; + +@Component +public class BeanWithSupertypes extends AbstractBeanWithSupertypes implements Interface1OfBeanWithSupertypes, Interface2OfBeanWithSupertypes { + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/AbstractBeanWithSupertypes.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/AbstractBeanWithSupertypes.java new file mode 100644 index 000000000..47551cd62 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/AbstractBeanWithSupertypes.java @@ -0,0 +1,5 @@ +package org.test.supertypes; + +public abstract class AbstractBeanWithSupertypes extends BaseClassOfAbstractBeanWithSupertypes implements InterfaceOfAbstractBean { + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/BaseClassOfAbstractBeanWithSupertypes.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/BaseClassOfAbstractBeanWithSupertypes.java new file mode 100644 index 000000000..963d8fd55 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/BaseClassOfAbstractBeanWithSupertypes.java @@ -0,0 +1,5 @@ +package org.test.supertypes; + +public class BaseClassOfAbstractBeanWithSupertypes implements Interface1OfBeanWithSupertypes { + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/Interface1OfBeanWithSupertypes.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/Interface1OfBeanWithSupertypes.java new file mode 100644 index 000000000..232cba2b3 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/Interface1OfBeanWithSupertypes.java @@ -0,0 +1,5 @@ +package org.test.supertypes; + +public interface Interface1OfBeanWithSupertypes { + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/Interface2OfBeanWithSupertypes.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/Interface2OfBeanWithSupertypes.java new file mode 100644 index 000000000..0cf02d200 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/Interface2OfBeanWithSupertypes.java @@ -0,0 +1,5 @@ +package org.test.supertypes; + +public interface Interface2OfBeanWithSupertypes { + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/InterfaceOfAbstractBean.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/InterfaceOfAbstractBean.java new file mode 100644 index 000000000..22526b1fc --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-spring-indexing/src/main/java/org/test/supertypes/InterfaceOfAbstractBean.java @@ -0,0 +1,5 @@ +package org.test.supertypes; + +public interface InterfaceOfAbstractBean { + +}