diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java index d6d22a2ef..a18e5cabb 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java @@ -170,37 +170,44 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { public void addSymbols(IJavaProject project, EnhancedSymbolInformation[] enhancedSymbols, Bean[] beanDefinitions) { - // organize symbols by doc URI - Map> symbolsPerDoc = new HashMap<>(); - for (EnhancedSymbolInformation symbol : enhancedSymbols) { - Either location = symbol.getSymbol().getLocation(); - String docURI = location.isLeft() ? location.getLeft().getUri() : location.getRight().getUri(); - - symbolsPerDoc.computeIfAbsent(docURI, k -> new ArrayList<>()).add(symbol); - } + if (enhancedSymbols != null) { - // add symbols per doc - for (Map.Entry> entry : symbolsPerDoc.entrySet()) { - String docURI = entry.getKey(); - List symbols = entry.getValue(); - - SpringSymbolIndex.this.addSymbolsByDoc(project, docURI, (EnhancedSymbolInformation[]) symbols.toArray(new EnhancedSymbolInformation[symbols.size()])); + // organize symbols by doc URI + Map> symbolsPerDoc = new HashMap<>(); + for (EnhancedSymbolInformation symbol : enhancedSymbols) { + Either location = symbol.getSymbol().getLocation(); + String docURI = location.isLeft() ? location.getLeft().getUri() : location.getRight().getUri(); + + symbolsPerDoc.computeIfAbsent(docURI, k -> new ArrayList<>()).add(symbol); + } + + // add symbols per doc + for (Map.Entry> entry : symbolsPerDoc.entrySet()) { + String docURI = entry.getKey(); + List symbols = entry.getValue(); + + SpringSymbolIndex.this.addSymbolsByDoc(project, docURI, (EnhancedSymbolInformation[]) symbols.toArray(new EnhancedSymbolInformation[symbols.size()])); + } } - // organize beans per doc URI - Map> beansPerDoc = new HashMap<>(); - for (Bean bean : beanDefinitions) { - String docURI = bean.getLocation().getUri(); - beansPerDoc.computeIfAbsent(docURI, k -> new ArrayList<>()).add(bean); + if (beanDefinitions != null) { + + // organize beans per doc URI + Map> beansPerDoc = new HashMap<>(); + for (Bean bean : beanDefinitions) { + String docURI = bean.getLocation().getUri(); + beansPerDoc.computeIfAbsent(docURI, k -> new ArrayList<>()).add(bean); + } + + // add beans per doc URI + for (Map.Entry> entry : beansPerDoc.entrySet()) { + String docURI = entry.getKey(); + List beans = entry.getValue(); + + springIndex.updateBeans(project.getElementName(), docURI, (Bean[]) beans.toArray(new Bean[beans.size()])); + } } - // add beans per doc URI - for (Map.Entry> entry : beansPerDoc.entrySet()) { - String docURI = entry.getKey(); - List beans = entry.getValue(); - - springIndex.updateBeans(project.getElementName(), docURI, (Bean[]) beans.toArray(new Bean[beans.size()])); - } } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/AbstractIndexCacheable.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/AbstractIndexCacheable.java new file mode 100644 index 000000000..b4c442179 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/AbstractIndexCacheable.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.index.cache; + +public abstract class AbstractIndexCacheable implements IndexCacheable { + + private final String docURI; + + public AbstractIndexCacheable(String docURI) { + this.docURI = docURI; + } + + @Override + public String getDocURI() { + return this.docURI; + } + + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCache.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCache.java index 6795f871e..138066e01 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCache.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCache.java @@ -14,7 +14,6 @@ import java.util.List; import java.util.Set; import org.apache.commons.lang3.tuple.Pair; -import org.springframework.ide.vscode.boot.java.utils.CachedSymbol; import com.google.common.collect.Multimap; @@ -23,17 +22,17 @@ import com.google.common.collect.Multimap; */ public interface IndexCache { - void store(IndexCacheKey cacheKey, String[] files, List generatedSymbols, Multimap dependencies); - Pair> retrieve(IndexCacheKey cacheKey, String[] files); + void store(IndexCacheKey cacheKey, String[] files, List generatedSymbols, Multimap dependencies, Class type); + Pair> retrieve(IndexCacheKey cacheKey, String[] files, Class type); - void update(IndexCacheKey cacheKey, String file, long lastModified, List generatedSymbols, Set dependencies); - void update(IndexCacheKey cacheKey, String[] files, long[] lastModified, List generatedSymbols, Multimap dependencies); + void update(IndexCacheKey cacheKey, String file, long lastModified, List generatedSymbols, Set dependencies, Class type); + void update(IndexCacheKey cacheKey, String[] files, long[] lastModified, List generatedSymbols, Multimap dependencies, Class type); void remove(IndexCacheKey cacheKey); - void removeFile(IndexCacheKey symbolCacheKey, String file); + void removeFile(IndexCacheKey symbolCacheKey, String file, Class type); - default CachedSymbol[] retrieveSymbols(IndexCacheKey cacheKey, String[] files) { - Pair> r = retrieve(cacheKey, files); + default T[] retrieveSymbols(IndexCacheKey cacheKey, String[] files, Class type) { + Pair> r = retrieve(cacheKey, files, type); return r!=null ? r.getLeft() : null; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheOnDisc.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheOnDisc.java index c10b0ce2e..ab6b7263a 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheOnDisc.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheOnDisc.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 2021 Pivotal, Inc. + * Copyright (c) 2019, 2023 Pivotal, 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 @@ -14,6 +14,7 @@ import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.lang.reflect.Array; import java.lang.reflect.Type; import java.nio.file.Files; import java.util.Arrays; @@ -34,7 +35,6 @@ import org.eclipse.lsp4j.Location; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; -import org.springframework.ide.vscode.boot.java.utils.CachedSymbol; import org.springframework.ide.vscode.commons.protocol.spring.Bean; import org.springframework.ide.vscode.commons.protocol.spring.InjectionPoint; import org.springframework.ide.vscode.commons.util.UriUtil; @@ -53,6 +53,7 @@ import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; +import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; /** @@ -61,7 +62,7 @@ import com.google.gson.stream.JsonReader; public class IndexCacheOnDisc implements IndexCache { private final File cacheDirectory; - private final Map stores; + private final Map> stores; private static final Logger log = LoggerFactory.getLogger(IndexCacheOnDisc.class); @@ -79,10 +80,11 @@ public class IndexCacheOnDisc implements IndexCache { } @Override - public void store(IndexCacheKey cacheKey, String[] files, List generatedSymbols, Multimap dependencies) { - if (dependencies==null) { + public void store(IndexCacheKey cacheKey, String[] files, List elements, Multimap dependencies, Class type) { + if (dependencies == null) { dependencies = ImmutableMultimap.of(); } + SortedMap timestampedFiles = new TreeMap<>(); timestampedFiles = Arrays.stream(files) @@ -95,18 +97,19 @@ public class IndexCacheOnDisc implements IndexCache { } }, (v1,v2) -> { throw new RuntimeException(String.format("Duplicate key for values %s and %s", v1, v2));}, TreeMap::new)); - save(cacheKey, generatedSymbols, timestampedFiles, dependencies.asMap()); + save(cacheKey, elements, timestampedFiles, dependencies.asMap(), type); } + @SuppressWarnings("unchecked") @Override - public Pair> retrieve(IndexCacheKey cacheKey, String[] files) { + public Pair> retrieve(IndexCacheKey cacheKey, String[] files, Class type) { File cacheStore = new File(cacheDirectory, cacheKey.toString() + ".json"); if (cacheStore.exists()) { Gson gson = createGson(); try (JsonReader reader = new JsonReader(new FileReader(cacheStore))) { - CacheStore store = gson.fromJson(reader, CacheStore.class); + IndexCacheStore store = gson.fromJson(reader, IndexCacheStore.class); SortedMap timestampedFiles = Arrays.stream(files) .filter(file -> new File(file).exists()) @@ -121,16 +124,19 @@ public class IndexCacheOnDisc implements IndexCache { if (isFileMatch(timestampedFiles, store.getTimestampedFiles())) { this.stores.put(cacheKey, store); - List symbols = store.getSymbols(); + List symbols = store.getSymbols(); + Map> storedDependencies = store.getDependencies(); Multimap dependencies = MultimapBuilder.hashKeys().hashSetValues().build(); + if (storedDependencies!=null && !storedDependencies.isEmpty()) { for (Entry> entry : storedDependencies.entrySet()) { dependencies.replaceValues(entry.getKey(), entry.getValue()); } } + return Pair.of( - (CachedSymbol[]) symbols.toArray(new CachedSymbol[symbols.size()]), + (T[]) symbols.toArray((T[]) Array.newInstance(type, symbols.size())), MultimapBuilder.hashKeys().hashSetValues().build(dependencies) ); } @@ -143,20 +149,22 @@ public class IndexCacheOnDisc implements IndexCache { } @Override - public void removeFile(IndexCacheKey cacheKey, String file) { - CacheStore cacheStore = this.stores.get(cacheKey); + public void removeFile(IndexCacheKey cacheKey, String file, Class type) { + @SuppressWarnings("unchecked") + IndexCacheStore cacheStore = (IndexCacheStore) this.stores.get(cacheKey); + if (cacheStore != null) { String docURI = UriUtil.toUri(new File(file)).toASCIIString(); SortedMap timestampedFiles = new TreeMap<>(cacheStore.getTimestampedFiles()); timestampedFiles.remove(file); - List cachedSymbols = cacheStore.getSymbols().stream() + List cachedSymbols = cacheStore.getSymbols().stream() .filter(cachedSymbol -> !cachedSymbol.getDocURI().equals(docURI)) .collect(Collectors.toList()); Map> changedDeps = new HashMap<>(cacheStore.getDependencies()); changedDeps.remove(file); - save(cacheKey, cachedSymbols, timestampedFiles, changedDeps); + save(cacheKey, cachedSymbols, timestampedFiles, changedDeps, type); } } @@ -170,12 +178,14 @@ public class IndexCacheOnDisc implements IndexCache { } @Override - public void update(IndexCacheKey cacheKey, String file, long lastModified, List generatedSymbols, Set dependencies) { + public void update(IndexCacheKey cacheKey, String file, long lastModified, + List generatedSymbols, Set dependencies, Class type) { if (dependencies == null) { dependencies = ImmutableSet.of(); } - CacheStore cacheStore = this.stores.get(cacheKey); + @SuppressWarnings("unchecked") + IndexCacheStore cacheStore = (IndexCacheStore) this.stores.get(cacheKey); if (cacheStore != null) { String docURI = UriUtil.toUri(new File(file)).toASCIIString(); @@ -183,7 +193,7 @@ public class IndexCacheOnDisc implements IndexCache { SortedMap timestampedFiles = new TreeMap<>(cacheStore.getTimestampedFiles()); timestampedFiles.put(file, lastModified); - List cachedSymbols = cacheStore.getSymbols().stream() + List cachedSymbols = cacheStore.getSymbols().stream() .filter(cachedSymbol -> !cachedSymbol.getDocURI().equals(docURI)) .collect(Collectors.toList()); @@ -195,17 +205,20 @@ public class IndexCacheOnDisc implements IndexCache { } else { changedDependencies.put(file, ImmutableSet.copyOf(dependencies)); } - save(cacheKey, cachedSymbols, timestampedFiles, changedDependencies); + + save(cacheKey, cachedSymbols, timestampedFiles, changedDependencies, type); } } @Override - public void update(IndexCacheKey cacheKey, String[] files, long[] lastModified, List generatedSymbols, Multimap dependencies) { + public void update(IndexCacheKey cacheKey, String[] files, long[] lastModified, + List generatedSymbols, Multimap dependencies, Class type) { if (dependencies == null) { dependencies = ImmutableMultimap.of(); } - CacheStore cacheStore = this.stores.get(cacheKey); + @SuppressWarnings("unchecked") + IndexCacheStore cacheStore = (IndexCacheStore) this.stores.get(cacheKey); if (cacheStore != null) { SortedMap timestampedFiles = new TreeMap<>(cacheStore.getTimestampedFiles()); @@ -231,19 +244,19 @@ public class IndexCacheOnDisc implements IndexCache { } // update cache internal list of cached symbols (by removing old ones and adding all new ones) - List cachedSymbols = cacheStore.getSymbols().stream() + List cachedSymbols = cacheStore.getSymbols().stream() .filter(cachedSymbol -> !allDocURIs.contains(cachedSymbol.getDocURI())) .collect(Collectors.toList()); cachedSymbols.addAll(generatedSymbols); // store the complete cache content of this project to disc - save(cacheKey, cachedSymbols, timestampedFiles, changedDependencies); + save(cacheKey, cachedSymbols, timestampedFiles, changedDependencies, type); } } @Override public long getModificationTimestamp(IndexCacheKey cacheKey, String file) { - CacheStore cacheStore = this.stores.get(cacheKey); + IndexCacheStore cacheStore = this.stores.get(cacheKey); if (cacheStore != null) { Long result = cacheStore.getTimestampedFiles().get(file); @@ -255,9 +268,9 @@ public class IndexCacheOnDisc implements IndexCache { return 0; } - private void save(IndexCacheKey cacheKey, List generatedSymbols, - SortedMap timestampedFiles, Map> dependencies) { - CacheStore store = new CacheStore(timestampedFiles, generatedSymbols, dependencies); + private void save(IndexCacheKey cacheKey, List elements, SortedMap timestampedFiles, + Map> dependencies, Class type) { + IndexCacheStore store = new IndexCacheStore(timestampedFiles, elements, dependencies, type); this.stores.put(cacheKey, store); try (FileWriter writer = new FileWriter(new File(cacheDirectory, cacheKey.toString() + ".json"))) @@ -301,6 +314,7 @@ public class IndexCacheOnDisc implements IndexCache { return new GsonBuilder() .registerTypeAdapter(SymbolAddOnInformation.class, new SymbolAddOnInformationAdapter()) .registerTypeAdapter(Bean.class, new BeanJsonAdapter()) + .registerTypeAdapter(IndexCacheStore.class, new IndexCacheStoreAdapter()) .create(); } @@ -308,31 +322,68 @@ public class IndexCacheOnDisc implements IndexCache { /** * internal storage structure */ - private static class CacheStore { + private static class IndexCacheStore { + + @SuppressWarnings("unused") + private final String elementType; private final SortedMap timestampedFiles; - private final List symbols; + private final List elements; private final Map> dependencies; - public CacheStore(SortedMap timestampedFiles, List symbols, Map> dependencies) { - super(); + public IndexCacheStore(SortedMap timestampedFiles, List elements, Map> dependencies, Class elementType) { this.timestampedFiles = timestampedFiles; - this.symbols = symbols; + this.elements = elements; this.dependencies = dependencies; + this.elementType = elementType.getName(); } public Map> getDependencies() { return dependencies; } - public List getSymbols() { - return symbols; + public List getSymbols() { + return elements; } public SortedMap getTimestampedFiles() { return timestampedFiles; } + + } + + private static class IndexCacheStoreAdapter implements JsonDeserializer> { + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public IndexCacheStore deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + JsonObject parsedObject = json.getAsJsonObject(); + + String className = parsedObject.get("elementType").getAsString(); + + try { + Class elementType = Class.forName(className); + + JsonElement elementsObject = parsedObject.get("elements"); + Type elementListType = TypeToken.getParameterized(List.class, elementType).getType(); + List elements = context.deserialize(elementsObject, elementListType); + + JsonElement timestampedFilesObject = parsedObject.get("timestampedFiles"); + Type timestampsMapType = TypeToken.getParameterized(SortedMap.class, String.class, Long.class).getType(); + SortedMap timestampedFiles = context.deserialize(timestampedFilesObject, timestampsMapType); + + JsonElement dependenciesObject = parsedObject.get("dependencies"); + Map dependencies = context.deserialize(dependenciesObject, HashMap.class); + + return new IndexCacheStore(timestampedFiles, elements, dependencies, elementType); + + } catch (ClassNotFoundException e) { + throw new JsonParseException("cannot parse data from index cache with element type: " + className, e); + } + + } + } /** diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheVoid.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheVoid.java index 729650fdc..373205ff6 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheVoid.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheVoid.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2020 Pivotal, Inc. + * Copyright (c) 2019, 2023 Pivotal, 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 @@ -14,7 +14,6 @@ import java.util.List; import java.util.Set; import org.apache.commons.lang3.tuple.Pair; -import org.springframework.ide.vscode.boot.java.utils.CachedSymbol; import com.google.common.collect.Multimap; @@ -24,20 +23,20 @@ import com.google.common.collect.Multimap; public class IndexCacheVoid implements IndexCache { @Override - public void store(IndexCacheKey cacheKey, String[] files, List generatedSymbols, Multimap dependencies) { + public void store(IndexCacheKey cacheKey, String[] files, List generatedSymbols, Multimap dependencies, Class type) { } @Override - public Pair> retrieve(IndexCacheKey cacheKey, String[] files) { + public Pair> retrieve(IndexCacheKey cacheKey, String[] files, Class type) { return null; } @Override - public void update(IndexCacheKey cacheKey, String file, long lastModified, List generatedSymbols, Set dependencies) { + public void update(IndexCacheKey cacheKey, String file, long lastModified, List generatedSymbols, Set dependencies, Class type) { } @Override - public void update(IndexCacheKey cacheKey, String[] file, long[] lastModified, List generatedSymbols, Multimap dependencies) { + public void update(IndexCacheKey cacheKey, String[] files, long[] lastModified, List generatedSymbols, Multimap dependencies, Class type) { } @Override @@ -45,7 +44,7 @@ public class IndexCacheVoid implements IndexCache { } @Override - public void removeFile(IndexCacheKey symbolCacheKey, String file) { + public void removeFile(IndexCacheKey symbolCacheKey, String file, Class type) { } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheable.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheable.java new file mode 100644 index 000000000..3a828f307 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheable.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.index.cache; + +public interface IndexCacheable { + + String getDocURI(); +} 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 ddd6aaa55..d5aa32a67 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 @@ -101,7 +101,8 @@ public class BeansSymbolProvider extends AbstractSymbolProvider { Bean beanDefinition = new Bean(nameAndRegion.getT1(), beanType.getQualifiedName(), location, injectionPoints, (String[]) supertypes.toArray(new String[supertypes.size()]), annotations); - context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol, beanDefinition)); + context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); + context.getBeans().add(new CachedBean(context.getDocURI(), beanDefinition)); } catch (BadLocationException e) { log.error("", e); @@ -121,7 +122,7 @@ public class BeansSymbolProvider extends AbstractSymbolProvider { 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(), functionBean.getT2().getQualifiedName())}), null)); + new EnhancedSymbolInformation(symbol, new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(functionBean.getT1(), functionBean.getT2().getQualifiedName())}))); } 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/CachedBean.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/CachedBean.java new file mode 100644 index 000000000..e1e6a83e6 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/CachedBean.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.beans; + +import org.springframework.ide.vscode.boot.index.cache.AbstractIndexCacheable; +import org.springframework.ide.vscode.commons.protocol.spring.Bean; + +public class CachedBean extends AbstractIndexCacheable { + + private final Bean bean; + + public CachedBean(String docURI, Bean bean) { + super(docURI); + this.bean = bean; + } + + public Bean getBean() { + return this.bean; + } + +} 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 bade1be5c..f3df493fd 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2022 Pivotal, Inc. + * Copyright (c) 2017, 2023 Pivotal, 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,7 +28,6 @@ import org.eclipse.lsp4j.jsonrpc.messages.Tuple.Two; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.java.Annotations; -import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies; import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; @@ -56,7 +55,8 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider { EnhancedSymbolInformation enhancedSymbol = result.getFirst(); Bean beanDefinition = result.getSecond(); - context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol, beanDefinition)); + context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); + context.getBeans().add(new CachedBean(context.getDocURI(), beanDefinition)); } } catch (Exception e) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java index 3afb985d8..fd0e2f949 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2019 Pivotal, Inc. + * Copyright (c) 2018, 2023 Pivotal, 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 @@ -23,6 +23,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.java.beans.BeanUtils; import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation; +import org.springframework.ide.vscode.boot.java.beans.CachedBean; import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; @@ -74,7 +75,8 @@ public class DataRepositorySymbolProvider extends AbstractSymbolProvider { String concreteRepoType = concreteBeanTypeBindung.getQualifiedName(); Bean beanDefinition = new Bean(beanName, concreteRepoType, location, injectionPoints, (String[]) supertypes.toArray(new String[supertypes.size()]), new String[0]); - context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol, beanDefinition)); + context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); + context.getBeans().add(new CachedBean(context.getDocURI(), beanDefinition)); } catch (BadLocationException e) { log.error("error creating data repository symbol for a specific range", e); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CachedDiagnostics.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CachedDiagnostics.java new file mode 100644 index 000000000..76f512635 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CachedDiagnostics.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.reconcilers; + +import org.springframework.ide.vscode.boot.index.cache.AbstractIndexCacheable; + +public class CachedDiagnostics extends AbstractIndexCacheable { + + public CachedDiagnostics(String docURI) { + super(docURI); + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java index 9b2e6402d..deaa82489 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java @@ -63,7 +63,7 @@ public class RequestMappingSymbolProvider extends AbstractSymbolProvider { return resultPath.startsWith("/") ? resultPath : "/" + resultPath; })) .map(p -> RouteUtils.createRouteSymbol(location, p, methods, contentTypes, acceptTypes, null)) - .forEach((enhancedSymbol) -> context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol, null))); + .forEach((enhancedSymbol) -> context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol))); } catch (Exception e) { e.printStackTrace(); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxRouterSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxRouterSymbolProvider.java index 484d999b2..143be479a 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxRouterSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/WebfluxRouterSymbolProvider.java @@ -112,7 +112,7 @@ public class WebfluxRouterSymbolProvider extends AbstractSymbolProvider { EnhancedSymbolInformation enhancedSymbol = RouteUtils.createRouteSymbol(location, path, getElementStrings(httpMethods), getElementStrings(contentTypes), getElementStrings(acceptTypes), addon); - context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol, null)); + context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); } catch (BadLocationException e) { e.printStackTrace(); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CachedSymbol.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CachedSymbol.java index 41adfd726..db88ee71e 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CachedSymbol.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CachedSymbol.java @@ -10,43 +10,31 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.utils; +import org.springframework.ide.vscode.boot.index.cache.AbstractIndexCacheable; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; -import org.springframework.ide.vscode.commons.protocol.spring.Bean; -public class CachedSymbol { +public class CachedSymbol extends AbstractIndexCacheable { - private final String docURI; private final long lastModified; private final EnhancedSymbolInformation enhancedSymbol; - private final Bean bean; - public CachedSymbol(String docURI, long lastModified, EnhancedSymbolInformation enhancedSymbol, Bean bean) { - this.docURI = docURI; + public CachedSymbol(String docURI, long lastModified, EnhancedSymbolInformation enhancedSymbol) { + super(docURI); this.lastModified = lastModified; this.enhancedSymbol = enhancedSymbol; - this.bean = bean; } public EnhancedSymbolInformation getEnhancedSymbol() { return enhancedSymbol; } - public Bean getBean() { - return bean; - } - - public String getDocURI() { - return docURI; - } - public long getLastModified() { return lastModified; } @Override public String toString() { - return "CachedSymbol [docURI=" + docURI + ", enhancedSymbol=" + enhancedSymbol + "]"; + return "CachedSymbol [docURI=" + getDocURI() + ", enhancedSymbol=" + enhancedSymbol + "]"; } - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/RestrictedDefaultSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/RestrictedDefaultSymbolProvider.java index 432e404fa..aedd2ccea 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/RestrictedDefaultSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/RestrictedDefaultSymbolProvider.java @@ -40,7 +40,7 @@ public class RestrictedDefaultSymbolProvider extends AbstractSymbolProvider { if (!isCombinedWithAnnotation(node, Annotations.BEAN)) { try { EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(DefaultSymbolProvider.provideDefaultSymbol(node, doc), null); - context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol, null)); + context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); } catch (Exception e) { log.warn(e.getMessage()); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringFactoriesIndexer.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringFactoriesIndexer.java index fa66d0813..986e053d2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringFactoriesIndexer.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringFactoriesIndexer.java @@ -170,7 +170,7 @@ public class SpringFactoriesIndexer implements SpringIndexer { IndexCacheKey cacheKey = getCacheKey(project); - CachedSymbol[] symbols = this.cache.retrieveSymbols(cacheKey, filesStr); + CachedSymbol[] symbols = this.cache.retrieveSymbols(cacheKey, filesStr, CachedSymbol.class); if (symbols == null) { List generatedSymbols = new ArrayList(); @@ -178,7 +178,7 @@ public class SpringFactoriesIndexer implements SpringIndexer { generatedSymbols.addAll(scanFile(file)); } - this.cache.store(cacheKey, filesStr, generatedSymbols, null); + this.cache.store(cacheKey, filesStr, generatedSymbols, null, CachedSymbol.class); symbols = (CachedSymbol[]) generatedSymbols.toArray(new CachedSymbol[generatedSymbols.size()]); } @@ -188,8 +188,7 @@ public class SpringFactoriesIndexer implements SpringIndexer { if (symbols != null) { EnhancedSymbolInformation[] enhancedSymbols = Arrays.stream(symbols).map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new); - Bean[] beans = Arrays.stream(symbols).filter(cachedSymbol -> cachedSymbol.getBean() != null).map(cachedSymbol -> cachedSymbol.getBean()).toArray(Bean[]::new); - symbolHandler.addSymbols(project, enhancedSymbols, beans); + symbolHandler.addSymbols(project, enhancedSymbols, null); } long endTime = System.currentTimeMillis(); @@ -205,7 +204,7 @@ public class SpringFactoriesIndexer implements SpringIndexer { long lastModified = Files.getLastModifiedTime(file).toMillis(); String docUri = file.toUri().toASCIIString(); for (EnhancedSymbolInformation s : computeSymbols(docUri, content)) { - builder.add(new CachedSymbol(docUri, lastModified, s, null)); + builder.add(new CachedSymbol(docUri, lastModified, s)); } return builder.build(); } catch (IOException e) { @@ -256,11 +255,10 @@ public class SpringFactoriesIndexer implements SpringIndexer { IndexCacheKey cacheKey = getCacheKey(project); String file = new File(new URI(docURI)).getAbsolutePath(); - this.cache.update(cacheKey, file, updatedDoc.getLastModified(), generatedSymbols, null); + this.cache.update(cacheKey, file, updatedDoc.getLastModified(), generatedSymbols, null, CachedSymbol.class); EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new); - Bean[] beans = generatedSymbols.stream().filter(cachedSymbol -> cachedSymbol.getBean() != null).map(cachedSymbol -> cachedSymbol.getBean()).toArray(Bean[]::new); - symbolHandler.addSymbols(project, docURI, symbols, beans); + symbolHandler.addSymbols(project, docURI, symbols, null); } } @@ -275,7 +273,7 @@ public class SpringFactoriesIndexer implements SpringIndexer { updateFile(project, d, Files.readString(path)); } else { String file = new File(new URI(d.getDocURI())).getAbsolutePath(); - cache.removeFile(key, file); + cache.removeFile(key, file, CachedSymbol.class); } } } @@ -286,7 +284,7 @@ public class SpringFactoriesIndexer implements SpringIndexer { IndexCacheKey key = getCacheKey(project); for (String docUri : docURIs) { String file = new File(new URI(docUri)).getAbsolutePath(); - cache.removeFile(key, file); + cache.removeFile(key, file, CachedSymbol.class); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java index 8d24a6e63..229b1c24f 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2022 Pivotal, Inc. + * Copyright (c) 2017, 2023 Pivotal, 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 @@ -52,6 +52,7 @@ import org.springframework.ide.vscode.boot.index.cache.IndexCache; import org.springframework.ide.vscode.boot.index.cache.IndexCacheKey; import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies; import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareLookup; +import org.springframework.ide.vscode.boot.java.beans.CachedBean; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider; import org.springframework.ide.vscode.commons.java.IClasspath; @@ -80,6 +81,9 @@ public class SpringIndexerJava implements SpringIndexer { // we need to change the generation - this will result in a re-indexing due to no up-to-date cache data being found private static final String GENERATION = "GEN-3"; + private static final String SYMBOL_KEY = "symbols"; + private static final String BEANS_KEY = "beans"; + private final SymbolHandler symbolHandler; private final AnnotationHierarchyAwareLookup symbolProviders; private final IndexCache cache; @@ -126,17 +130,24 @@ public class SpringIndexerJava implements SpringIndexer { @Override public void removeProject(IJavaProject project) throws Exception { - IndexCacheKey cacheKey = getCacheKey(project); - this.cache.remove(cacheKey); + IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); + + this.cache.remove(symbolsCacheKey); + this.cache.remove(beansCacheKey); } @Override public void updateFile(IJavaProject project, DocumentDescriptor updatedDoc, String content) throws Exception { - IndexCacheKey cacheKey = getCacheKey(project); - if (updatedDoc != null && shouldProcessDocument(project, updatedDoc.getDocURI()) - && isCacheOutdated(cacheKey, updatedDoc.getDocURI(), updatedDoc.getLastModified())) { - this.symbolHandler.removeSymbols(project, updatedDoc.getDocURI()); - scanFile(project, updatedDoc, content); + IndexCacheKey symbolCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); + + if (updatedDoc != null && shouldProcessDocument(project, updatedDoc.getDocURI())) { + if (isCacheOutdated(symbolCacheKey, updatedDoc.getDocURI(), updatedDoc.getLastModified()) + || isCacheOutdated(beansCacheKey, updatedDoc.getDocURI(), updatedDoc.getLastModified())) { + this.symbolHandler.removeSymbols(project, updatedDoc.getDocURI()); + scanFile(project, updatedDoc, content); + } } } @@ -155,18 +166,23 @@ public class SpringIndexerJava implements SpringIndexer { @Override public void removeFiles(IJavaProject project, String[] docURIs) throws Exception { - IndexCacheKey cacheKey = getCacheKey(project); + IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); for (String docURI : docURIs) { String file = new File(new URI(docURI)).getAbsolutePath(); - this.cache.removeFile(cacheKey, file); + this.cache.removeFile(symbolsCacheKey, file, CachedSymbol.class); + this.cache.removeFile(beansCacheKey, file, CachedSymbol.class); } } private DocumentDescriptor[] filterDocuments(IJavaProject project, DocumentDescriptor[] updatedDocs) { - IndexCacheKey cacheKey = getCacheKey(project); + IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); + return Arrays.stream(updatedDocs).filter(doc -> shouldProcessDocument(project, doc.getDocURI())) - .filter(doc -> isCacheOutdated(cacheKey, doc.getDocURI(), doc.getLastModified())).toArray(DocumentDescriptor[]::new); + .filter(doc -> isCacheOutdated(symbolsCacheKey, doc.getDocURI(), doc.getLastModified()) + || isCacheOutdated(beansCacheKey, doc.getDocURI(), doc.getLastModified())).toArray(DocumentDescriptor[]::new); } private boolean shouldProcessDocument(IJavaProject project, String docURI) { @@ -218,19 +234,25 @@ public class SpringIndexerJava implements SpringIndexer { if (cu != null) { List generatedSymbols = new ArrayList(); + List generatedBeans = new ArrayList(); + AtomicReference docRef = new AtomicReference<>(); String file = UriUtil.toFileString(docURI); SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, file, - lastModified, docRef, content, generatedSymbols, SCAN_PASS.ONE, new ArrayList<>()); + lastModified, docRef, content, generatedSymbols, generatedBeans, SCAN_PASS.ONE, new ArrayList<>()); scanAST(context); - IndexCacheKey cacheKey = getCacheKey(project); - this.cache.update(cacheKey, file, lastModified, generatedSymbols, context.getDependencies()); + IndexCacheKey symbolCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); + + this.cache.update(symbolCacheKey, file, lastModified, generatedSymbols, context.getDependencies(), CachedSymbol.class); + this.cache.update(beansCacheKey, file, lastModified, generatedBeans, context.getDependencies(), CachedBean.class); // dependencyTracker.dump(); EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new); - Bean[] beans = generatedSymbols.stream().filter(cachedSymbol -> cachedSymbol.getBean() != null).map(cachedSymbol -> cachedSymbol.getBean()).toArray(Bean[]::new); + Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new); + symbolHandler.addSymbols(project, docURI, symbols, beans); Set scannedFiles = new HashSet<>(); @@ -253,10 +275,12 @@ public class SpringIndexerJava implements SpringIndexer { if (cu != null) { List generatedSymbols = new ArrayList(); + List generatedBeans = new ArrayList(); + AtomicReference docRef = new AtomicReference<>(); String file = UriUtil.toFileString(docURI); SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, file, - 0, docRef, content, generatedSymbols, SCAN_PASS.ONE, new ArrayList<>()); + 0, docRef, content, generatedSymbols, generatedBeans, SCAN_PASS.ONE, new ArrayList<>()); scanAST(context); @@ -289,6 +313,8 @@ public class SpringIndexerJava implements SpringIndexer { } List generatedSymbols = new ArrayList(); + List generatedBeans = new ArrayList(); + Multimap dependencies = MultimapBuilder.hashKeys().hashSetValues().build(); FileASTRequestor requestor = new FileASTRequestor() { @@ -303,7 +329,7 @@ public class SpringIndexerJava implements SpringIndexer { AtomicReference docRef = new AtomicReference<>(); SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, sourceFilePath, - lastModified, docRef, null, generatedSymbols, SCAN_PASS.ONE, new ArrayList<>()); + lastModified, docRef, null, generatedSymbols, generatedBeans, SCAN_PASS.ONE, new ArrayList<>()); scanAST(context); @@ -317,11 +343,14 @@ public class SpringIndexerJava implements SpringIndexer { parser.createASTs(javaFiles, null, new String[0], requestor, null); EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new); - Bean[] beans = generatedSymbols.stream().filter(cachedSymbol -> cachedSymbol.getBean() != null).map(cachedSymbol -> cachedSymbol.getBean()).toArray(Bean[]::new); + Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new); symbolHandler.addSymbols(project, symbols, beans); - IndexCacheKey cacheKey = getCacheKey(project); - this.cache.update(cacheKey, javaFiles, lastModified, generatedSymbols, dependencies); + IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); + + this.cache.update(symbolsCacheKey, javaFiles, lastModified, generatedSymbols, dependencies, CachedSymbol.class); + this.cache.update(beansCacheKey, javaFiles, lastModified, generatedBeans, dependencies, CachedBean.class); return scannedTypes; } @@ -358,45 +387,55 @@ public class SpringIndexerJava implements SpringIndexer { } private void scanFiles(IJavaProject project, String[] javaFiles) throws Exception { - IndexCacheKey cacheKey = getCacheKey(project); - Pair> cached = this.cache.retrieve(cacheKey, javaFiles); + IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); + + Pair> cachedSymbols = this.cache.retrieve(symbolsCacheKey, javaFiles, CachedSymbol.class); + Pair> cachedBeans = this.cache.retrieve(beansCacheKey, javaFiles, CachedBean.class); CachedSymbol[] symbols; - if (cached == null) { + CachedBean[] beans; + + if (cachedSymbols == null || cachedBeans == null) { List generatedSymbols = new ArrayList(); + List generatedBeans = new ArrayList(); log.info("scan java files, AST parse, pass 1 for files: {}", javaFiles.length); - String[] pass2Files = scanFiles(project, javaFiles, generatedSymbols, SCAN_PASS.ONE); + String[] pass2Files = scanFiles(project, javaFiles, generatedSymbols, generatedBeans, SCAN_PASS.ONE); if (pass2Files.length > 0) { log.info("scan java files, AST parse, pass 2 for files: {}", javaFiles.length); - scanFiles(project, pass2Files, generatedSymbols, SCAN_PASS.TWO); + scanFiles(project, pass2Files, generatedSymbols, generatedBeans, SCAN_PASS.TWO); } log.info("scan java files done, number of symbols created: " + generatedSymbols.size()); - this.cache.store(cacheKey, javaFiles, generatedSymbols, dependencyTracker.getAllDependencies()); + this.cache.store(symbolsCacheKey, javaFiles, generatedSymbols, dependencyTracker.getAllDependencies(), CachedSymbol.class); + this.cache.store(beansCacheKey, javaFiles, generatedBeans, dependencyTracker.getAllDependencies(), CachedBean.class); // dependencyTracker.dump(); symbols = (CachedSymbol[]) generatedSymbols.toArray(new CachedSymbol[generatedSymbols.size()]); + beans = (CachedBean[]) generatedBeans.toArray(new CachedBean[generatedBeans.size()]); } else { - symbols = cached.getLeft(); + symbols = cachedSymbols.getLeft(); + beans = cachedBeans.getLeft(); + log.info("scan java files used cached data: {} - no. of cached symbols retrieved: {}", project.getElementName(), symbols.length); - this.dependencyTracker.restore(cached.getRight()); - log.info("scan java files restored cached dependency data: {} - no. of cached dependencies: {}", cached.getRight().size()); + this.dependencyTracker.restore(cachedSymbols.getRight()); + log.info("scan java files restored cached dependency data: {} - no. of cached dependencies: {}", cachedSymbols.getRight().size()); } - if (symbols != null) { + if (symbols != null && beans != null) { EnhancedSymbolInformation[] enhancedSymbols = Arrays.stream(symbols).map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new); - Bean[] beans = Arrays.stream(symbols).filter(cachedSymbol -> cachedSymbol.getBean() != null).map(cachedSymbol -> cachedSymbol.getBean()).toArray(Bean[]::new); - symbolHandler.addSymbols(project, enhancedSymbols, beans); + Bean[] allBeans = Arrays.stream(beans).filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new); + symbolHandler.addSymbols(project, enhancedSymbols, allBeans); } } - private String[] scanFiles(IJavaProject project, String[] javaFiles, List generatedSymbols, SCAN_PASS pass) + private String[] scanFiles(IJavaProject project, String[] javaFiles, List generatedSymbols, List generatedBeans, SCAN_PASS pass) throws Exception { ASTParser parser = createParser(project, SCAN_PASS.ONE.equals(pass)); List nextPassFiles = new ArrayList<>(); @@ -410,7 +449,7 @@ public class SpringIndexerJava implements SpringIndexer { AtomicReference docRef = new AtomicReference<>(); SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, sourceFilePath, - lastModified, docRef, null, generatedSymbols, pass, nextPassFiles); + lastModified, docRef, null, generatedSymbols, generatedBeans, pass, nextPassFiles); scanAST(context); } @@ -523,7 +562,7 @@ public class SpringIndexerJava implements SpringIndexer { WorkspaceSymbol symbol = provideDefaultSymbol(node, context); if (symbol != null) { EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null); - context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol, null)); + context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); } } } @@ -608,7 +647,7 @@ public class SpringIndexerJava implements SpringIndexer { .toArray(String[]::new); } - private IndexCacheKey getCacheKey(IJavaProject project) { + private IndexCacheKey getCacheKey(IJavaProject project, String elementType) { IClasspath classpath = project.getClasspath(); Stream classpathEntries = IClasspathUtil.getAllBinaryRoots(classpath).stream(); @@ -617,7 +656,7 @@ public class SpringIndexerJava implements SpringIndexer { .map(file -> file.getAbsolutePath() + "#" + file.lastModified()) .collect(Collectors.joining(",")); - return new IndexCacheKey(project.getElementName() + "-java-", DigestUtils.md5Hex(GENERATION + "-" + classpathIdentifier).toUpperCase()); + return new IndexCacheKey(project.getElementName() + "-java-" + elementType + "-", DigestUtils.md5Hex(GENERATION + "-" + classpathIdentifier).toUpperCase()); } public void setScanTestJavaSources(boolean scanTestJavaSources) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJavaContext.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJavaContext.java index 74bf5621f..3af97dae6 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJavaContext.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJavaContext.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2020 Pivotal, Inc. + * Copyright (c) 2017, 2023 Pivotal, 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 @@ -17,8 +17,10 @@ import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ITypeBinding; +import org.springframework.ide.vscode.boot.java.beans.CachedBean; import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJava.SCAN_PASS; import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.protocol.spring.Bean; import org.springframework.ide.vscode.commons.util.text.TextDocument; /** @@ -34,6 +36,7 @@ public class SpringIndexerJavaContext { private final AtomicReference docRef; private final String content; private final List generatedSymbols; + private final List beans; private final SCAN_PASS pass; private final List nextPassFiles; @@ -48,7 +51,8 @@ public class SpringIndexerJavaContext { long lastModified, AtomicReference docRef, String content, - List generatedSymbols, + List generatedSymbols, + List beans, SCAN_PASS pass, List nextPassFiles ) { @@ -61,6 +65,7 @@ public class SpringIndexerJavaContext { this.docRef = docRef; this.content = content; this.generatedSymbols = generatedSymbols; + this.beans = beans; this.pass = pass; this.nextPassFiles = nextPassFiles; } @@ -96,6 +101,10 @@ public class SpringIndexerJavaContext { public List getGeneratedSymbols() { return generatedSymbols; } + + public List getBeans() { + return beans; + } public SCAN_PASS getPass() { return pass; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java index 19d25fd4a..98370eaf8 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2022 Pivotal, Inc. + * Copyright (c) 2019, 2023 Pivotal, 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 @@ -33,6 +33,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.index.cache.IndexCache; import org.springframework.ide.vscode.boot.index.cache.IndexCacheKey; +import org.springframework.ide.vscode.boot.java.beans.CachedBean; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.java.IClasspathUtil; @@ -48,6 +49,9 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; public class SpringIndexerXML implements SpringIndexer { private static final Logger log = LoggerFactory.getLogger(SpringIndexerJava.class); + + private static final String SYMBOL_KEY = "symbols"; + private static final String BEANS_KEY = "beans"; private final SymbolHandler symbolHandler; private final Map namespaceHandler; @@ -106,28 +110,34 @@ public class SpringIndexerXML implements SpringIndexer { log.info("scan xml files for symbols for project: " + project.getElementName() + " - no. of files: " + files.length); - IndexCacheKey cacheKey = getCacheKey(project); + IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); - CachedSymbol[] symbols = this.cache.retrieveSymbols(cacheKey, files); - if (symbols == null) { + CachedSymbol[] symbols = this.cache.retrieveSymbols(symbolsCacheKey, files, CachedSymbol.class); + CachedBean[] beans = this.cache.retrieveSymbols(beansCacheKey, files, CachedBean.class); + + if (symbols == null || beans == null) { List generatedSymbols = new ArrayList(); + List generatedBeans = new ArrayList(); for (String file : files) { - scanFile(project, file, generatedSymbols); + scanFile(project, file, generatedSymbols, generatedBeans); } - this.cache.store(cacheKey, files, generatedSymbols, null); + this.cache.store(symbolsCacheKey, files, generatedSymbols, null, CachedSymbol.class); + this.cache.store(beansCacheKey, files, generatedBeans, null, CachedBean.class); symbols = (CachedSymbol[]) generatedSymbols.toArray(new CachedSymbol[generatedSymbols.size()]); + beans = (CachedBean[]) generatedBeans.toArray(new CachedBean[generatedBeans.size()]); } else { log.info("scan xml files used cached data: " + project.getElementName() + " - no. of cached symbols retrieved: " + symbols.length); } - if (symbols != null) { + if (symbols != null && beans != null) { EnhancedSymbolInformation[] enhancedSymbols = Arrays.stream(symbols).map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new); - Bean[] beans = Arrays.stream(symbols).filter(cachedSymbol -> cachedSymbol.getBean() != null).map(cachedSymbol -> cachedSymbol.getBean()).toArray(Bean[]::new); - symbolHandler.addSymbols(project, enhancedSymbols, beans); + Bean[] allBeans = Arrays.stream(beans).filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new); + symbolHandler.addSymbols(project, enhancedSymbols, allBeans); } long endTime = System.currentTimeMillis(); @@ -137,8 +147,11 @@ public class SpringIndexerXML implements SpringIndexer { @Override public void removeProject(IJavaProject project) throws Exception { - IndexCacheKey cacheKey = getCacheKey(project); - this.cache.remove(cacheKey); + IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); + + this.cache.remove(symbolsCacheKey); + this.cache.remove(beansCacheKey); } @Override @@ -147,16 +160,21 @@ public class SpringIndexerXML implements SpringIndexer { this.symbolHandler.removeSymbols(project, updatedDoc.getDocURI()); List generatedSymbols = new ArrayList(); + List generatedBeans = new ArrayList(); + String docURI = updatedDoc.getDocURI(); - scanFile(project, content, docURI, updatedDoc.getLastModified(), generatedSymbols); + scanFile(project, content, docURI, updatedDoc.getLastModified(), generatedSymbols, generatedBeans); + + IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); - IndexCacheKey cacheKey = getCacheKey(project); String file = new File(new URI(docURI)).getAbsolutePath(); - this.cache.update(cacheKey, file, updatedDoc.getLastModified(), generatedSymbols, null); + this.cache.update(symbolsCacheKey, file, updatedDoc.getLastModified(), generatedSymbols, null, CachedSymbol.class); + this.cache.update(beansCacheKey, file, updatedDoc.getLastModified(), generatedBeans, null, CachedBean.class); EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new); - Bean[] beans = generatedSymbols.stream().filter(cachedSymbol -> cachedSymbol.getBean() != null).map(cachedSymbol -> cachedSymbol.getBean()).toArray(Bean[]::new); + Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new); symbolHandler.addSymbols(project, docURI, symbols, beans); } @@ -172,29 +190,36 @@ public class SpringIndexerXML implements SpringIndexer { String content = new String(Files.readAllBytes(path)); List generatedSymbols = new ArrayList(); - scanFile(project, content, docURI, updatedDoc.getLastModified(), generatedSymbols); + List generatedBeans = new ArrayList(); + scanFile(project, content, docURI, updatedDoc.getLastModified(), generatedSymbols, generatedBeans); - IndexCacheKey cacheKey = getCacheKey(project); + IndexCacheKey symbolCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); + String file = new File(new URI(docURI)).getAbsolutePath(); - this.cache.update(cacheKey, file, updatedDoc.getLastModified(), generatedSymbols, null); + this.cache.update(symbolCacheKey, file, updatedDoc.getLastModified(), generatedSymbols, null, CachedSymbol.class); + this.cache.update(beansCacheKey, file, updatedDoc.getLastModified(), generatedBeans, null, CachedBean.class); EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new); - Bean[] beans = generatedSymbols.stream().filter(cachedSymbol -> cachedSymbol.getBean() != null).map(cachedSymbol -> cachedSymbol.getBean()).toArray(Bean[]::new); + Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new); symbolHandler.addSymbols(project, docURI, symbols, beans); } } @Override public void removeFiles(IJavaProject project, String[] docURIs) throws Exception { - IndexCacheKey cacheKey = getCacheKey(project); + IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); + IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); for (String docURI : docURIs) { String file = new File(new URI(docURI)).getAbsolutePath(); - this.cache.removeFile(cacheKey, file); + + this.cache.removeFile(symbolsCacheKey, file, CachedSymbol.class); + this.cache.removeFile(beansCacheKey, file, CachedBean.class); } } - private void scanFile(IJavaProject project, String fileName, List generatedSymbols) { + private void scanFile(IJavaProject project, String fileName, List generatedSymbols, List generatedBeans) { log.debug("starting to parse XML file for Spring symbol indexing: {}", fileName); try { @@ -204,29 +229,32 @@ public class SpringIndexerXML implements SpringIndexer { String docURI = UriUtil.toUri(file).toASCIIString(); String fileContent = FileUtils.readFileToString(file); - scanFile(project, fileContent, docURI, lastModified, generatedSymbols); + scanFile(project, fileContent, docURI, lastModified, generatedSymbols, generatedBeans); } catch (Exception e) { log.error("error parsing XML file: ", e); } } - private void scanFile(IJavaProject project, String fileContent, String docURI, long lastModified, List generatedSymbols) throws Exception { + private void scanFile(IJavaProject project, String fileContent, String docURI, long lastModified, List generatedSymbols, + List generatedBeans) throws Exception { DOMParser parser = DOMParser.getInstance(); DOMDocument document = parser.parse(fileContent, "", null); AtomicReference docRef = new AtomicReference<>(); - scanNode(document, project, docURI, lastModified, docRef, fileContent, generatedSymbols); + scanNode(document, project, docURI, lastModified, docRef, fileContent, generatedSymbols, generatedBeans); } - private void scanNode(DOMNode node, IJavaProject project, String docURI, long lastModified, AtomicReference docRef, String content, List generatedSymbols) throws Exception { + private void scanNode(DOMNode node, IJavaProject project, String docURI, long lastModified, AtomicReference docRef, String content, + List generatedSymbols, List generatedBeans) throws Exception { + String namespaceURI = node.getNamespaceURI(); if (namespaceURI != null && this.namespaceHandler.containsKey(namespaceURI)) { SpringIndexerXMLNamespaceHandler namespaceHandler = this.namespaceHandler.get(namespaceURI); TextDocument document = DocumentUtils.getTempTextDocument(docURI, docRef, content); - namespaceHandler.processNode(node, project, docURI, lastModified, document, generatedSymbols); + namespaceHandler.processNode(node, project, docURI, lastModified, document, generatedSymbols, generatedBeans); } @@ -240,7 +268,7 @@ public class SpringIndexerXML implements SpringIndexer { List children = node.getChildren(); for (DOMNode child : children) { - scanNode(child, project, docURI, lastModified, docRef, content, generatedSymbols); + scanNode(child, project, docURI, lastModified, docRef, content, generatedSymbols, generatedBeans); } @@ -269,7 +297,7 @@ public class SpringIndexerXML implements SpringIndexer { return xmlFiles; } - private IndexCacheKey getCacheKey(IJavaProject project) { + private IndexCacheKey getCacheKey(IJavaProject project, String elementType) { IClasspath classpath = project.getClasspath(); Stream classpathEntries = IClasspathUtil.getAllBinaryRoots(classpath).stream(); @@ -278,7 +306,7 @@ public class SpringIndexerXML implements SpringIndexer { .map(file -> file.getAbsolutePath() + "#" + file.lastModified()) .collect(Collectors.joining(",")); - return new IndexCacheKey(project.getElementName() + "-xml-", DigestUtils.md5Hex(classpathIdentifier).toUpperCase()); + return new IndexCacheKey(project.getElementName() + "-xml-" + elementType + "-", DigestUtils.md5Hex(classpathIdentifier).toUpperCase()); } private void clearIndex() { @@ -318,7 +346,9 @@ public class SpringIndexerXML implements SpringIndexer { throws Exception { if (content != null) { List generatedSymbols = new ArrayList<>(); - scanFile(project, content, docURI, 0, generatedSymbols); + List generatedBeans = new ArrayList<>(); + + scanFile(project, content, docURI, 0, generatedSymbols, generatedBeans); return generatedSymbols.stream().map(s -> s.getEnhancedSymbol()).collect(Collectors.toList()); } return Collections.emptyList(); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandler.java index ce61dd77e..a9e6fcb7f 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2020 Pivotal, Inc. + * Copyright (c) 2019, 2023 Pivotal, 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 @@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java.utils; import java.util.List; import org.eclipse.lemminx.dom.DOMNode; +import org.springframework.ide.vscode.boot.java.beans.CachedBean; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -21,6 +22,7 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; */ public interface SpringIndexerXMLNamespaceHandler { - void processNode(DOMNode node, IJavaProject project, String docURI, long lastModifiued, TextDocument document, List generatedSymbols) throws Exception; + void processNode(DOMNode node, IJavaProject project, String docURI, long lastModifiued, TextDocument document, + List generatedSymbols, List generatedBeans) throws Exception; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java index 3a95d5e8e..87ea20704 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2020 Pivotal, Inc. + * Copyright (c) 2019, 2023 Pivotal, 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 @@ -22,6 +22,7 @@ import org.eclipse.lsp4j.WorkspaceSymbol; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.springframework.ide.vscode.boot.java.beans.BeanUtils; import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation; +import org.springframework.ide.vscode.boot.java.beans.CachedBean; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; import org.springframework.ide.vscode.commons.java.IJavaProject; @@ -34,14 +35,16 @@ import org.springframework.lang.NonNull; public class SpringIndexerXMLNamespaceHandlerBeans implements SpringIndexerXMLNamespaceHandler { @Override - public void processNode(DOMNode node, IJavaProject project, String docURI, long lastModified, TextDocument document, List generatedSymbols) throws Exception { + public void processNode(DOMNode node, IJavaProject project, String docURI, long lastModified, TextDocument document, + List generatedSymbols, List generatedBeans) throws Exception { String localName = node.getLocalName(); if (localName != null && "bean".equals(localName)) { - createBeanSymbol(node, project, docURI, lastModified, document, generatedSymbols); + createBeanSymbol(node, project, docURI, lastModified, document, generatedSymbols, generatedBeans); } } - private void createBeanSymbol(DOMNode node, IJavaProject project, String docURI, long lastModified, TextDocument document, List generatedSymbols) throws Exception { + private void createBeanSymbol(DOMNode node, IJavaProject project, String docURI, long lastModified, TextDocument document, + List generatedSymbols, List generatedBeans) throws Exception { String beanID = null; int symbolStart = 0; int symbolEnd = 0; @@ -94,8 +97,10 @@ public class SpringIndexerXMLNamespaceHandlerBeans implements SpringIndexerXMLNa EnhancedSymbolInformation fullSymbol = new EnhancedSymbolInformation(symbol, addon); - CachedSymbol cachedSymbol = new CachedSymbol(docURI, lastModified, fullSymbol, null); + CachedSymbol cachedSymbol = new CachedSymbol(docURI, lastModified, fullSymbol); generatedSymbols.add(cachedSymbol); + + // TODO: bean index } } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/cache/test/IndexCacheOnDiscTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/cache/test/IndexCacheOnDiscTest.java index b5935bde1..4becc8d1b 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/cache/test/IndexCacheOnDiscTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/cache/test/IndexCacheOnDiscTest.java @@ -36,6 +36,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.ide.vscode.boot.index.cache.AbstractIndexCacheable; import org.springframework.ide.vscode.boot.index.cache.IndexCacheKey; import org.springframework.ide.vscode.boot.index.cache.IndexCacheOnDisc; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; @@ -67,7 +68,7 @@ public class IndexCacheOnDiscTest { @Test void testEmptyCache() throws Exception { - Pair> result = cache.retrieve(new IndexCacheKey("something", "0"), new String[0]); + Pair> result = cache.retrieve(new IndexCacheKey("something", "0"), new String[0], CachedSymbol.class); assertNull(result); } @@ -87,15 +88,15 @@ public class IndexCacheOnDiscTest { List generatedSymbols = new ArrayList<>(); WorkspaceSymbol symbol = new WorkspaceSymbol("symbol1", SymbolKind.Field, Either.forLeft(new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))))); EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null); - generatedSymbols.add(new CachedSymbol("", timeFile1.toMillis(), enhancedSymbol, null)); + generatedSymbols.add(new CachedSymbol("", timeFile1.toMillis(), enhancedSymbol)); cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, ImmutableMultimap.of( file1.toString(), "file1dep1", file2.toString(), "file2dep1", file2.toString(), "file2dep2" - )); + ), CachedSymbol.class); - Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), files); + Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), files, CachedSymbol.class); CachedSymbol[] cachedSymbols = result.getLeft(); assertNotNull(cachedSymbols); @@ -113,8 +114,6 @@ public class IndexCacheOnDiscTest { assertEquals(timeFile1.toMillis(), cache.getModificationTimestamp(new IndexCacheKey("somekey", "1"), file1.toString())); assertEquals(0, cache.getModificationTimestamp(new IndexCacheKey("somekey", "1"), "random-non-existing-file")); - - assertNull(cachedSymbols[0].getBean()); } @Test @@ -133,11 +132,11 @@ public class IndexCacheOnDiscTest { List generatedSymbols = new ArrayList<>(); WorkspaceSymbol symbol = new WorkspaceSymbol("symbol1", SymbolKind.Field, Either.forLeft(new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))))); EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null); - generatedSymbols.add(new CachedSymbol("", timeFile1.toMillis(), enhancedSymbol, null)); + generatedSymbols.add(new CachedSymbol("", timeFile1.toMillis(), enhancedSymbol)); - cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, null); + cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, null, CachedSymbol.class); - Pair> result = cache.retrieve(new IndexCacheKey("otherkey", "1"), files); + Pair> result = cache.retrieve(new IndexCacheKey("otherkey", "1"), files, CachedSymbol.class); assertNull(result); } @@ -157,16 +156,16 @@ public class IndexCacheOnDiscTest { List generatedSymbols = new ArrayList<>(); WorkspaceSymbol symbol = new WorkspaceSymbol("symbol1", SymbolKind.Field, Either.forLeft(new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))))); EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null); - generatedSymbols.add(new CachedSymbol("", timeFile1.toMillis(), enhancedSymbol, null)); + generatedSymbols.add(new CachedSymbol("", timeFile1.toMillis(), enhancedSymbol)); cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, ImmutableMultimap.of( file1.toString(), "file1dep", file2.toString(), "file2dep" - )); + ), CachedSymbol.class); assertTrue(file1.toFile().setLastModified(timeFile1.toMillis() + 1000)); - Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), files); + Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), files, CachedSymbol.class); assertNull(result); } @@ -181,10 +180,10 @@ public class IndexCacheOnDiscTest { Files.createFile(file3); String[] files = {file1.toString(), file2.toString()}; - cache.store(new IndexCacheKey("somekey", "1"), files, new ArrayList<>(), null); + cache.store(new IndexCacheKey("somekey", "1"), files, new ArrayList<>(), null, CachedSymbol.class); String[] moreFiles = {file1.toString(), file2.toString(), file3.toString()}; - assertNull(cache.retrieve(new IndexCacheKey("somekey", "1"), moreFiles)); + assertNull(cache.retrieve(new IndexCacheKey("somekey", "1"), moreFiles, CachedSymbol.class)); } @Test @@ -198,20 +197,20 @@ public class IndexCacheOnDiscTest { Files.createFile(file3); String[] files = {file1.toString(), file2.toString(), file3.toString()}; - cache.store(new IndexCacheKey("somekey", "1"), files, new ArrayList<>(), null); + cache.store(new IndexCacheKey("somekey", "1"), files, new ArrayList<>(), null, CachedSymbol.class); String[] fewerFiles = {file1.toString(), file2.toString()}; - assertNull(cache.retrieve(new IndexCacheKey("somekey", "1"), fewerFiles)); + assertNull(cache.retrieve(new IndexCacheKey("somekey", "1"), fewerFiles, CachedSymbol.class)); } @Test void testDeleteOldCacheFileIfNewOneIsStored() throws Exception { IndexCacheKey key1 = new IndexCacheKey("somekey", "1"); - cache.store(key1, new String[0], new ArrayList<>(), null); + cache.store(key1, new String[0], new ArrayList<>(), null, CachedSymbol.class); assertTrue(Files.exists(tempDir.resolve(Paths.get(key1.toString() + ".json")))); IndexCacheKey key2 = new IndexCacheKey("somekey", "2"); - cache.store(key2, new String[0], new ArrayList<>(), null); + cache.store(key2, new String[0], new ArrayList<>(), null, CachedSymbol.class); assertTrue(Files.exists(tempDir.resolve(Paths.get(key2.toString() + ".json")))); assertFalse(Files.exists(tempDir.resolve(Paths.get(key1.toString() + ".json")))); } @@ -231,11 +230,11 @@ public class IndexCacheOnDiscTest { WebfluxElementsInformation addon = new WebfluxElementsInformation(new Range(new Position(4, 4), new Position(5, 5)), new Range(new Position(6, 6), new Position(7, 7))); EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, new SymbolAddOnInformation[]{addon}); - generatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol, null)); + generatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol)); - cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, null); + cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, null, CachedSymbol.class); - CachedSymbol[] cachedSymbols = cache.retrieveSymbols(new IndexCacheKey("somekey", "1"), files); + CachedSymbol[] cachedSymbols = cache.retrieveSymbols(new IndexCacheKey("somekey", "1"), files, CachedSymbol.class); assertNotNull(cachedSymbols); assertEquals(1, cachedSymbols.length); @@ -268,9 +267,9 @@ public class IndexCacheOnDiscTest { List generatedSymbols1 = new ArrayList<>(); WorkspaceSymbol symbol1 = new WorkspaceSymbol("symbol1", SymbolKind.Field, Either.forLeft(new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))))); EnhancedSymbolInformation enhancedSymbol1 = new EnhancedSymbolInformation(symbol1, null); - generatedSymbols1.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1, null)); + generatedSymbols1.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1)); - cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols1, null); + cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols1, null, CachedSymbol.class); List generatedSymbols2 = new ArrayList<>(); symbol1 = new WorkspaceSymbol("symbol1", SymbolKind.Field, Either.forLeft(new Location(doc1URI, new Range(new Position(3, 10), new Position(3, 20))))); @@ -279,13 +278,13 @@ public class IndexCacheOnDiscTest { WorkspaceSymbol symbol2 = new WorkspaceSymbol("symbol2", SymbolKind.Interface, Either.forLeft(new Location(doc1URI, new Range(new Position(5, 5), new Position(5, 10))))); EnhancedSymbolInformation enhancedSymbol2 = new EnhancedSymbolInformation(symbol2, null); - generatedSymbols2.add(new CachedSymbol(doc1URI, timeFile1.toMillis() + 2000, enhancedSymbol1, null)); - generatedSymbols2.add(new CachedSymbol(doc1URI, timeFile1.toMillis() + 2000, enhancedSymbol2, null)); + generatedSymbols2.add(new CachedSymbol(doc1URI, timeFile1.toMillis() + 2000, enhancedSymbol1)); + generatedSymbols2.add(new CachedSymbol(doc1URI, timeFile1.toMillis() + 2000, enhancedSymbol2)); assertTrue(file1.toFile().setLastModified(timeFile1.toMillis() + 2000)); - cache.update(new IndexCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), timeFile1.toMillis() + 2000, generatedSymbols2, null); + cache.update(new IndexCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), timeFile1.toMillis() + 2000, generatedSymbols2, null, CachedSymbol.class); - CachedSymbol[] cachedSymbols = cache.retrieveSymbols(new IndexCacheKey("somekey", "1"), files); + AbstractIndexCacheable[] cachedSymbols = cache.retrieveSymbols(new IndexCacheKey("somekey", "1"), files, CachedSymbol.class); assertNotNull(cachedSymbols); assertEquals(2, cachedSymbols.length); @@ -317,18 +316,18 @@ public class IndexCacheOnDiscTest { List generatedSymbols = new ArrayList<>(); WorkspaceSymbol symbol1 = new WorkspaceSymbol("symbol1", SymbolKind.Field, Either.forLeft(new Location(doc1URI, new Range(new Position(3, 10), new Position(3, 20))))); EnhancedSymbolInformation enhancedSymbol1 = new EnhancedSymbolInformation(symbol1, null); - generatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1, null)); + generatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1)); WorkspaceSymbol symbol2 = new WorkspaceSymbol("symbol2", SymbolKind.Field, Either.forLeft(new Location(doc2URI, new Range(new Position(3, 10), new Position(3, 20))))); EnhancedSymbolInformation enhancedSymbol2 = new EnhancedSymbolInformation(symbol2, null); - generatedSymbols.add(new CachedSymbol(doc2URI, timeFile2.toMillis(), enhancedSymbol2, null)); + generatedSymbols.add(new CachedSymbol(doc2URI, timeFile2.toMillis(), enhancedSymbol2)); WorkspaceSymbol symbol3 = new WorkspaceSymbol("symbol3", SymbolKind.Field, Either.forLeft(new Location(doc3URI, new Range(new Position(3, 10), new Position(3, 20))))); EnhancedSymbolInformation enhancedSymbol3 = new EnhancedSymbolInformation(symbol3, null); - generatedSymbols.add(new CachedSymbol(doc3URI, timeFile3.toMillis(), enhancedSymbol3, null)); + generatedSymbols.add(new CachedSymbol(doc3URI, timeFile3.toMillis(), enhancedSymbol3)); // store original version of the symbols to the cache - cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, null); + cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, null, CachedSymbol.class); // create updated and new symbols @@ -340,23 +339,23 @@ public class IndexCacheOnDiscTest { WorkspaceSymbol newSymbol1 = new WorkspaceSymbol("symbol1-new", SymbolKind.Interface, Either.forLeft(new Location(doc1URI, new Range(new Position(5, 5), new Position(5, 10))))); EnhancedSymbolInformation newEnhancedSymbol1 = new EnhancedSymbolInformation(newSymbol1, null); - updatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis() + 2000, updatedEnhancedSymbol1, null)); - updatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis() + 2000, newEnhancedSymbol1, null)); + updatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis() + 2000, updatedEnhancedSymbol1)); + updatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis() + 2000, newEnhancedSymbol1)); assertTrue(file1.toFile().setLastModified(timeFile1.toMillis() + 2000)); WorkspaceSymbol updatedSymbol2 = new WorkspaceSymbol("symbol2-updated", SymbolKind.Field, Either.forLeft(new Location(doc2URI, new Range(new Position(3, 10), new Position(3, 20))))); EnhancedSymbolInformation updatedEnhancedSymbol2 = new EnhancedSymbolInformation(updatedSymbol2, null); - updatedSymbols.add(new CachedSymbol(doc2URI, timeFile2.toMillis() + 3000, updatedEnhancedSymbol2, null)); + updatedSymbols.add(new CachedSymbol(doc2URI, timeFile2.toMillis() + 3000, updatedEnhancedSymbol2)); assertTrue(file2.toFile().setLastModified(timeFile2.toMillis() + 3000)); String[] updatedFiles = new String[]{file1.toAbsolutePath().toString(), file2.toAbsolutePath().toString()}; long[] updatedModificationTimestamps = new long[]{timeFile1.toMillis() + 2000, timeFile2.toMillis() + 3000}; // update multiple files in the cache - cache.update(new IndexCacheKey("somekey", "1"), updatedFiles, updatedModificationTimestamps, updatedSymbols, null); + cache.update(new IndexCacheKey("somekey", "1"), updatedFiles, updatedModificationTimestamps, updatedSymbols, null, CachedSymbol.class); // double check whether all changes got stored and retrieved correctly - CachedSymbol[] cachedSymbols = cache.retrieveSymbols(new IndexCacheKey("somekey", "1"), files); + CachedSymbol[] cachedSymbols = cache.retrieveSymbols(new IndexCacheKey("somekey", "1"), files, CachedSymbol.class); assertNotNull(cachedSymbols); assertEquals(4, cachedSymbols.length); @@ -395,13 +394,13 @@ public class IndexCacheOnDiscTest { List generatedSymbols = ImmutableList.of(); Multimap dependencies = ImmutableMultimap.of(file1.toString(), "dep1"); - cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, dependencies); + cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, dependencies, CachedSymbol.class); assertTrue(file1.toFile().setLastModified(timeFile1.toMillis() + 2000)); Set dependencies2 = ImmutableSet.of("dep1", "dep2"); - cache.update(new IndexCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), timeFile1.toMillis() + 2000, generatedSymbols, dependencies2); + cache.update(new IndexCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), timeFile1.toMillis() + 2000, generatedSymbols, dependencies2, CachedSymbol.class); - Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), files); + Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), files, CachedSymbol.class); assertNotNull(result); assertEquals(ImmutableSet.of("dep1", "dep2"), result.getRight().get(file1.toString())); } @@ -420,16 +419,16 @@ public class IndexCacheOnDiscTest { List generatedSymbols1 = new ArrayList<>(); WorkspaceSymbol symbol1 = new WorkspaceSymbol("symbol1", SymbolKind.Field, Either.forLeft(new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))))); EnhancedSymbolInformation enhancedSymbol1 = new EnhancedSymbolInformation(symbol1, null); - generatedSymbols1.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1, null)); + generatedSymbols1.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1)); - cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols1, null); + cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols1, null, CachedSymbol.class); List generatedSymbols2 = new ArrayList<>(); assertTrue(file1.toFile().setLastModified(timeFile1.toMillis() + 2000)); - cache.update(new IndexCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), timeFile1.toMillis() + 2000, generatedSymbols2, null); + cache.update(new IndexCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), timeFile1.toMillis() + 2000, generatedSymbols2, null, CachedSymbol.class); - CachedSymbol[] cachedSymbols = cache.retrieveSymbols(new IndexCacheKey("somekey", "1"), files); + AbstractIndexCacheable[] cachedSymbols = cache.retrieveSymbols(new IndexCacheKey("somekey", "1"), files, CachedSymbol.class); assertNotNull(cachedSymbols); assertEquals(0, cachedSymbols.length); } @@ -450,15 +449,15 @@ public class IndexCacheOnDiscTest { file1.toString(), "dep2" ); - cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols1, dependencies1); + cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols1, dependencies1, CachedSymbol.class); List generatedSymbols2 = new ArrayList<>(); assertTrue(file1.toFile().setLastModified(timeFile1.toMillis() + 2000)); Set dependencies2 = ImmutableSet.of("dep2"); - cache.update(new IndexCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), timeFile1.toMillis() + 2000, generatedSymbols2, dependencies2); + cache.update(new IndexCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), timeFile1.toMillis() + 2000, generatedSymbols2, dependencies2, CachedSymbol.class); - Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), files); + Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), files, CachedSymbol.class); assertNotNull(result); assertEquals(ImmutableSet.of("dep2"), result.getRight().get(file1.toString())); } @@ -481,19 +480,19 @@ public class IndexCacheOnDiscTest { List generatedSymbols1 = new ArrayList<>(); WorkspaceSymbol symbol1 = new WorkspaceSymbol("symbol1", SymbolKind.Field, Either.forLeft(new Location(doc1URI, new Range(new Position(3, 10), new Position(3, 20))))); EnhancedSymbolInformation enhancedSymbol1 = new EnhancedSymbolInformation(symbol1, null); - generatedSymbols1.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1, null)); + generatedSymbols1.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1)); - cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols1, null); + cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols1, null, CachedSymbol.class); List generatedSymbols2 = new ArrayList<>(); WorkspaceSymbol symbol2 = new WorkspaceSymbol("symbol2", SymbolKind.Interface, Either.forLeft(new Location(doc2URI, new Range(new Position(5, 5), new Position(5, 10))))); EnhancedSymbolInformation enhancedSymbol2 = new EnhancedSymbolInformation(symbol2, null); - generatedSymbols2.add(new CachedSymbol(doc2URI, timeFile2.toMillis(), enhancedSymbol2, null)); + generatedSymbols2.add(new CachedSymbol(doc2URI, timeFile2.toMillis(), enhancedSymbol2)); - cache.update(new IndexCacheKey("somekey", "1"), file2.toString(), timeFile2.toMillis(), generatedSymbols2, null); + cache.update(new IndexCacheKey("somekey", "1"), file2.toString(), timeFile2.toMillis(), generatedSymbols2, null, CachedSymbol.class); - CachedSymbol[] cachedSymbols = cache.retrieveSymbols(new IndexCacheKey("somekey", "1"), new String[]{file1.toString(), file2.toString()}); + AbstractIndexCacheable[] cachedSymbols = cache.retrieveSymbols(new IndexCacheKey("somekey", "1"), new String[]{file1.toString(), file2.toString()}, CachedSymbol.class); assertNotNull(cachedSymbols); assertEquals(2, cachedSymbols.length); } @@ -513,12 +512,12 @@ public class IndexCacheOnDiscTest { Multimap dependencies1 = ImmutableMultimap.of( file1.toString(), "dep1" ); - cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols1, dependencies1); + cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols1, dependencies1, CachedSymbol.class); Set dependencies2 = ImmutableSet.of("dep2"); - cache.update(new IndexCacheKey("somekey", "1"), file2.toString(), timeFile2.toMillis(), generatedSymbols1, dependencies2); + cache.update(new IndexCacheKey("somekey", "1"), file2.toString(), timeFile2.toMillis(), generatedSymbols1, dependencies2, CachedSymbol.class); - Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), new String[]{file1.toString(), file2.toString()}); + Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), new String[]{file1.toString(), file2.toString()}, CachedSymbol.class); assertNotNull(result); assertEquals(ImmutableSet.of("dep2"), result.getRight().get(file2.toString())); assertEquals(ImmutableSet.of("dep1"), result.getRight().get(file1.toString())); @@ -527,7 +526,7 @@ public class IndexCacheOnDiscTest { @Test void testProjectDeleted() throws Exception { IndexCacheKey key1 = new IndexCacheKey("somekey", "1"); - cache.store(key1, new String[0], new ArrayList<>(), null); + cache.store(key1, new String[0], new ArrayList<>(), null, CachedSymbol.class); assertTrue(Files.exists(tempDir.resolve(Paths.get(key1.toString() + ".json")))); cache.remove(key1); @@ -557,18 +556,18 @@ public class IndexCacheOnDiscTest { WorkspaceSymbol symbol2 = new WorkspaceSymbol("symbol2", SymbolKind.Field, Either.forLeft(new Location(doc2URI, new Range(new Position(5, 10), new Position(5, 20))))); EnhancedSymbolInformation enhancedSymbol2 = new EnhancedSymbolInformation(symbol2, null); - generatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1, null)); - generatedSymbols.add(new CachedSymbol(doc2URI, timeFile2.toMillis(), enhancedSymbol2, null)); + generatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1)); + generatedSymbols.add(new CachedSymbol(doc2URI, timeFile2.toMillis(), enhancedSymbol2)); Multimap dependencies = ImmutableMultimap.of( file1.toString(), "dep1", file2.toString(), "dep2" ); - cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, dependencies); - cache.removeFile(new IndexCacheKey("somekey", "1"), file1.toAbsolutePath().toString()); + cache.store(new IndexCacheKey("somekey", "1"), files, generatedSymbols, dependencies, CachedSymbol.class); + cache.removeFile(new IndexCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), CachedSymbol.class); files = new String[]{file2.toAbsolutePath().toString()}; - Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), files); + Pair> result = cache.retrieve(new IndexCacheKey("somekey", "1"), files, CachedSymbol.class); CachedSymbol[] cachedSymbols = result.getLeft(); assertNotNull(result); assertEquals(1, cachedSymbols.length); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/cache/test/IndexCacheTimestampsOnly.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/cache/test/IndexCacheTimestampsOnly.java index 44ccd2b75..36cba40d0 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/cache/test/IndexCacheTimestampsOnly.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/cache/test/IndexCacheTimestampsOnly.java @@ -25,7 +25,7 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; import org.springframework.ide.vscode.boot.index.cache.IndexCache; import org.springframework.ide.vscode.boot.index.cache.IndexCacheKey; -import org.springframework.ide.vscode.boot.java.utils.CachedSymbol; +import org.springframework.ide.vscode.boot.index.cache.IndexCacheable; import com.google.common.collect.Multimap; @@ -41,7 +41,7 @@ public class IndexCacheTimestampsOnly implements IndexCache { } @Override - public void store(IndexCacheKey cacheKey, String[] files, List generatedSymbols, Multimap dependencies) { + public void store(IndexCacheKey cacheKey, String[] files, List generatedSymbols, Multimap dependencies, Class type) { SortedMap timestampedFiles = new TreeMap<>(); timestampedFiles = Arrays.stream(files) @@ -58,18 +58,18 @@ public class IndexCacheTimestampsOnly implements IndexCache { } @Override - public Pair> retrieve(IndexCacheKey cacheKey, String[] files) { + public Pair> retrieve(IndexCacheKey cacheKey, String[] files, Class type) { return null; } @Override - public void update(IndexCacheKey cacheKey, String file, long lastModified, List generatedSymbols, Set dependencies) { + public void update(IndexCacheKey cacheKey, String file, long lastModified, List generatedSymbols, Set dependencies, Class type) { Map timestampMap = timestampCache.get(cacheKey); timestampMap.put(file, lastModified); } @Override - public void update(IndexCacheKey cacheKey, String[] files, long[] lastModified, List generatedSymbols, Multimap dependencies) { + public void update(IndexCacheKey cacheKey, String[] files, long[] lastModified, List generatedSymbols, Multimap dependencies, Class type) { Map timestampMap = timestampCache.get(cacheKey); for (int i = 0; i < files.length; i++) { @@ -82,7 +82,7 @@ public class IndexCacheTimestampsOnly implements IndexCache { } @Override - public void removeFile(IndexCacheKey symbolCacheKey, String file) { + public void removeFile(IndexCacheKey symbolCacheKey, String file, Class type) { } @Override