From 84a8937b31fe8c843ec16e5f065ee10535edc3ff Mon Sep 17 00:00:00 2001 From: Kris De Volder Date: Thu, 26 Oct 2017 12:17:33 -0700 Subject: [PATCH] Add index of beans by dependency to beans model Also, replace model implementation with immutable / builder style data structures. --- .../autowired/AutowiredHoverProvider.java | 10 +- .../java/beans/ComponentHoverProvider.java | 10 +- .../vscode/boot/java/utils/SpringIndexer.java | 8 -- .../boot/app/cli/livebean/LiveBeansModel.java | 95 ++++++++++++------- .../boot/app/cli/LiveBeansModelTest.java | 13 +-- .../boot/app/cli/SpringBootAppTest.java | 2 +- 6 files changed, 80 insertions(+), 58 deletions(-) diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java index 36e3aa6d8..301f6557d 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java @@ -111,8 +111,8 @@ public class AutowiredHoverProvider implements HoverProvider { try { String type = findDeclaredType(annotation); if (type != null && beansModel != null) { - LiveBean[] beansOfType = beansModel.getBeansOfType(type); - if (beansOfType.length > 0) { + List beansOfType = beansModel.getBeansOfType(type); + if (!beansOfType.isEmpty()) { Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength()); return hoverRange; } @@ -128,9 +128,9 @@ public class AutowiredHoverProvider implements HoverProvider { public void addLiveHoverContent(Annotation annotation, TextDocument doc, LiveBeansModel beansModel, SpringBootAppProvider bootApp, List> hoverContent) { String type = findDeclaredType(annotation); if (type != null && beansModel != null) { - LiveBean[] beansOfType = beansModel.getBeansOfType(type); + List beansOfType = beansModel.getBeansOfType(type); - if (beansOfType.length > 0) { + if (!beansOfType.isEmpty()) { String processId = bootApp.getProcessID(); String processName = bootApp.getProcessName(); @@ -142,7 +142,7 @@ public class AutowiredHoverProvider implements HoverProvider { hoverContent.add(Either.forLeft("injected beans:")); for (String dependency : dependencies) { - LiveBean[] dependencyBeans = beansModel.getBeansOfName(dependency); + List dependencyBeans = beansModel.getBeansOfName(dependency); for (LiveBean dependencyBean : dependencyBeans) { hoverContent.add(Either.forLeft("- '" + dependencyBean.getId() + "' - from: " + dependencyBean.getResource())); } diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentHoverProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentHoverProvider.java index 4852b1d0d..d5dec76da 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentHoverProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentHoverProvider.java @@ -126,9 +126,9 @@ public class ComponentHoverProvider implements HoverProvider { TypeDeclaration type = findDeclaredType(annotation); if (type != null && beansModel != null) { String typeName = type.resolveBinding().getQualifiedName(); - LiveBean[] beansOfType = beansModel.getBeansOfType(typeName); + List beansOfType = beansModel.getBeansOfType(typeName); - if (beansOfType.length > 0) { + if (!beansOfType.isEmpty()) { MethodDeclaration constructor = findConstructor(type); if (constructor != null && !hasAutowiredAnnotation(constructor)) { Range hoverRange = doc.toRange(constructor.getName().getStartPosition(), constructor.getName().getLength()); @@ -161,9 +161,9 @@ public class ComponentHoverProvider implements HoverProvider { public void addLiveHoverContent(TypeDeclaration declaringType, TextDocument doc, LiveBeansModel beansModel, SpringBootAppProvider bootApp, List> hoverContent) { String type = declaringType.resolveBinding().getQualifiedName(); if (type != null && beansModel != null) { - LiveBean[] beansOfType = beansModel.getBeansOfType(type); + List beansOfType = beansModel.getBeansOfType(type); - if (beansOfType.length > 0) { + if (!beansOfType.isEmpty()) { String processId = bootApp.getProcessID(); String processName = bootApp.getProcessName(); @@ -175,7 +175,7 @@ public class ComponentHoverProvider implements HoverProvider { hoverContent.add(Either.forLeft("injected beans:")); for (String dependency : dependencies) { - LiveBean[] dependencyBeans = beansModel.getBeansOfName(dependency); + List dependencyBeans = beansModel.getBeansOfName(dependency); for (LiveBean dependencyBean : dependencyBeans) { hoverContent.add(Either.forLeft("- '" + dependencyBean.getId() + "' - from: " + dependencyBean.getResource())); } diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java index c9c7c89b6..9189b8f99 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java @@ -264,16 +264,12 @@ public class SpringIndexer { private void scanFiles(File directory) { try { - System.out.println("scan directory..."); - Map, List> projects = Files.walk(directory.toPath()) .filter(path -> path.getFileName().toString().endsWith(".java")) .filter(Files::isRegularFile) .map(path -> path.toAbsolutePath().toString()) .collect(Collectors.groupingBy((javaFile) -> projectFinder.find(new TextDocumentIdentifier(new File(javaFile).toURI().toString())))); - System.out.println("scan directory done!!!"); - projects.forEach((maybeProject, files) -> maybeProject.ifPresent(project -> scanProject(project, files.toArray(new String[0])))); } catch (Exception e) { @@ -283,14 +279,10 @@ public class SpringIndexer { private void scanProject(IJavaProject project, String[] files) { try { - System.out.println("create parser... " + project.getElementName()); ASTParser parser = ASTParser.newParser(AST.JLS8); String[] classpathEntries = getClasspathEntries(project); - System.out.println("create parser done!!!"); - System.out.println("parse files... " + project.getElementName()); scanFiles(parser, files, classpathEntries); - System.out.println("parse files done!!!"); } catch (Exception e) { e.printStackTrace(); diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/livebean/LiveBeansModel.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/livebean/LiveBeansModel.java index 5ea7cbf83..5b7e62fd8 100644 --- a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/livebean/LiveBeansModel.java +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/livebean/LiveBeansModel.java @@ -13,8 +13,6 @@ package org.springframework.ide.vscode.commons.boot.app.cli.livebean; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.stream.Stream; import org.json.JSONArray; @@ -22,11 +20,51 @@ import org.json.JSONObject; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.StringUtil; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; + /** * @author Martin Lippert + * @author Kris De Volder */ public class LiveBeansModel { + public static class Builder { + private final ImmutableListMultimap.Builder beansViaName = ImmutableListMultimap.builder(); + private final ImmutableListMultimap.Builder beansViaType = ImmutableListMultimap.builder(); + private final ImmutableListMultimap.Builder beansViaDependency = ImmutableListMultimap.builder(); + + public LiveBeansModel build() { + return new LiveBeansModel(beansViaName.build(), beansViaType.build(), beansViaDependency.build()); + } + + public void add(LiveBean bean) { + String type = bean.getType(); + if (type != null) { + beansViaType.put(type, bean); + } + + String name = bean.getId(); + if (name != null) { + beansViaName.put(name, bean); + } + + String[] deps = bean.getDependencies(); + if (deps!=null) { + for (String dep : deps) { + beansViaDependency.put(dep, bean); + } + } + } + + } + + public static LiveBeansModel.Builder builder() { + return new Builder(); + } + interface Parser { LiveBeansModel parse(String json) throws Exception; } @@ -34,7 +72,7 @@ public class LiveBeansModel { private static class Boot15Parser implements Parser { @Override public LiveBeansModel parse(String json) throws Exception { - LiveBeansModel model = new LiveBeansModel(); + Builder model = LiveBeansModel.builder(); JSONArray mainArray = new JSONArray(json); for (int i = 0; i < mainArray.length(); i++) { JSONObject appContext = mainArray.getJSONObject(i); @@ -53,7 +91,7 @@ public class LiveBeansModel { } } } - return model; + return model.build(); } private LiveBean parseBean(JSONObject beansJSON) { String id = beansJSON.optString("bean"); @@ -81,7 +119,7 @@ public class LiveBeansModel { private static class Boot20Parser implements Parser { @Override public LiveBeansModel parse(String json) throws Exception { - LiveBeansModel model = new LiveBeansModel(); + Builder model = LiveBeansModel.builder(); JSONObject mainObject = new JSONObject(json); JSONObject beansObject = mainObject.getJSONObject("beans"); for (String id : beansObject.keySet()) { @@ -92,7 +130,7 @@ public class LiveBeansModel { model.add(bean); } } - return model; + return model.build(); } private LiveBean parseBean(String id, JSONObject beansJSON) { @@ -141,45 +179,36 @@ public class LiveBeansModel { for (Exception e : exceptions) { Log.log(e); } - return new LiveBeansModel(); // allways return at least an empty model. + return LiveBeansModel.builder().build(); // allways return at least an empty model. } - private final ConcurrentMap> beansViaType; - private final ConcurrentMap> beansViaName; + private final ImmutableListMultimap beansViaType; + private final ImmutableListMultimap beansViaName; + private final ImmutableListMultimap beansViaDependency; - protected LiveBeansModel() { - this.beansViaType = new ConcurrentHashMap<>(); - this.beansViaName = new ConcurrentHashMap<>(); + protected LiveBeansModel( + ImmutableListMultimap beansViaName, + ImmutableListMultimap beansViaType, + ImmutableListMultimap beansViaDependency) { + this.beansViaName = beansViaName; + this.beansViaType = beansViaType; + this.beansViaDependency = beansViaDependency; } - public LiveBean[] getBeansOfType(String fullyQualifiedType) { - List result = beansViaType.get(fullyQualifiedType); - return result != null ? result.toArray(new LiveBean[result.size()]) : new LiveBean[0]; + public List getBeansOfType(String fullyQualifiedType) { + return beansViaType.get(fullyQualifiedType); } - public LiveBean[] getBeansOfName(String beanName) { - List result = beansViaName.get(beanName); - return result != null ? result.toArray(new LiveBean[result.size()]) : new LiveBean[0]; + public List getBeansOfName(String beanName) { + return beansViaName.get(beanName); } - protected void add(LiveBean bean) { - String type = bean.getType(); - if (type != null) { - beansViaType.computeIfAbsent(type, (t) -> new ArrayList<>()).add(bean); - } - - String name = bean.getId(); - if (name != null) { - beansViaName.computeIfAbsent(name, (n) -> new ArrayList<>()).add(bean); - } - } - - public Stream getAllBeans() { - return beansViaName.values().stream().flatMap(Collection::stream); + public List getBeansDependingOn(String beanName) { + return beansViaDependency.get(beanName); } public boolean isEmpty() { - return !getAllBeans().findAny().isPresent(); + return beansViaName.isEmpty(); //Assumes every bean has a name. } } diff --git a/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/LiveBeansModelTest.java b/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/LiveBeansModelTest.java index e7372bd27..3b25f233d 100644 --- a/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/LiveBeansModelTest.java +++ b/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/LiveBeansModelTest.java @@ -13,6 +13,7 @@ package org.springframework.ide.vscode.commons.boot.app.cli; import static org.junit.Assert.assertEquals; import java.io.InputStream; +import java.util.List; import org.apache.commons.io.IOUtils; import org.junit.Test; @@ -29,7 +30,7 @@ public class LiveBeansModelTest { String json = IOUtils.toString(getResourceAsStream("/live-beans-models/simple-live-beans-model.json")); LiveBeansModel model = LiveBeansModel.parse(json); - LiveBean[] bean = model.getBeansOfType("org.test.DependencyA"); + LiveBean[] bean = model.getBeansOfType("org.test.DependencyA").toArray(new LiveBean[0]); assertEquals(1, bean.length); assertEquals("dependencyA", bean[0].getId()); assertEquals("singleton", bean[0].getScope()); @@ -38,7 +39,7 @@ public class LiveBeansModelTest { assertEquals(0, bean[0].getAliases().length); assertEquals(0, bean[0].getDependencies().length); - bean = model.getBeansOfName("dependencyB"); + bean = model.getBeansOfName("dependencyB").toArray(new LiveBean[0]); assertEquals(1, bean.length); assertEquals("dependencyB", bean[0].getId()); assertEquals("singleton", bean[0].getScope()); @@ -53,8 +54,8 @@ public class LiveBeansModelTest { String json = IOUtils.toString(getResourceAsStream("/live-beans-models/empty-live-beans-model.json")); LiveBeansModel model = LiveBeansModel.parse(json); - LiveBean[] bean = model.getBeansOfType("org.test.DependencyA"); - assertEquals(0, bean.length); + List bean = model.getBeansOfType("org.test.DependencyA"); + assertEquals(0, bean.size()); } @Test @@ -62,8 +63,8 @@ public class LiveBeansModelTest { String json = IOUtils.toString(getResourceAsStream("/live-beans-models/totally-empty-live-beans-model.json")); LiveBeansModel model = LiveBeansModel.parse(json); - LiveBean[] bean = model.getBeansOfType("org.test.DependencyA"); - assertEquals(0, bean.length); + List bean = model.getBeansOfType("org.test.DependencyA"); + assertEquals(0, bean.size()); } private InputStream getResourceAsStream(String string) { diff --git a/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootAppTest.java b/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootAppTest.java index 294b28c91..4047c55c1 100644 --- a/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootAppTest.java +++ b/headless-services/commons/commons-boot-app-cli/src/test/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootAppTest.java @@ -169,7 +169,7 @@ public class SpringBootAppTest { try { ACondition.waitFor(TIMEOUT, () -> { LiveBeansModel beansModel = testApp.getBeans(); - assertTrue(beansModel.getAllBeans().findAny().isPresent()); + assertFalse(beansModel.isEmpty()); // System.out.println("beans = "+beans); }); } catch (Throwable e) {