Index Elements serialization. Structure view initial work
* WIP Signed-off-by: aboyko <alex.boyko@broadcom.com> * `SpringIndexElement` serialization. Initial Structure view in VSCode Signed-off-by: aboyko <alex.boyko@broadcom.com> * Corrections Signed-off-by: aboyko <alex.boyko@broadcom.com> * Serialization polishing Signed-off-by: aboyko <alex.boyko@broadcom.com> * Don't include java.lang.Object in supertypes serialization Signed-off-by: aboyko <alex.boyko@broadcom.com> --------- Signed-off-by: aboyko <alex.boyko@broadcom.com>
This commit is contained in:
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.lsp4j.CodeActionKind;
|
||||
@@ -89,6 +90,7 @@ import org.springframework.ide.vscode.boot.properties.completions.SpringProperti
|
||||
import org.springframework.ide.vscode.boot.xml.SpringXMLCompletionEngine;
|
||||
import org.springframework.ide.vscode.boot.yaml.completions.ApplicationYamlAssistContext;
|
||||
import org.springframework.ide.vscode.boot.yaml.completions.SpringYamlCompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.RuntimeTypeAdapterFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.LanguageServerRunner;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.FutureProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
@@ -98,6 +100,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.LanguageComput
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.ServerCapabilityInitializer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
|
||||
import org.springframework.ide.vscode.commons.util.FileObserver;
|
||||
import org.springframework.ide.vscode.commons.util.LogRedirect;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
@@ -118,6 +121,7 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import reactor.core.publisher.Hooks;
|
||||
@@ -428,4 +432,10 @@ public class BootLanguageServerBootApp {
|
||||
return new ResponseModifier();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Consumer<GsonBuilder> configureGson() {
|
||||
return builder -> builder
|
||||
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(SpringIndexElement.class, "_internal_node_type")
|
||||
.recognizeSubtypes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* Copyright (c) 2024, 2025 Broadcom, 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
|
||||
@@ -12,6 +12,8 @@ package org.springframework.ide.vscode.boot.app;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.commands.SpringIndexCommands;
|
||||
import org.springframework.ide.vscode.boot.java.commands.WorkspaceBootExecutableProjects;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
@@ -22,5 +24,10 @@ public class CommandsConfig {
|
||||
@Bean WorkspaceBootExecutableProjects workspaceBootProjects(SimpleLanguageServer server, JavaProjectFinder projectFinder, SpringSymbolIndex symbolIndex) {
|
||||
return new WorkspaceBootExecutableProjects(server, projectFinder, symbolIndex);
|
||||
}
|
||||
|
||||
@Bean SpringIndexCommands springIndexCommands(SimpleLanguageServer server, JavaProjectFinder projectFinder, SpringMetamodelIndex symbolIndex) {
|
||||
return new SpringIndexCommands(server, symbolIndex, projectFinder);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -38,13 +38,9 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.DefaultValues;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.InjectionPoint;
|
||||
import org.springframework.ide.vscode.commons.RuntimeTypeAdapterFactory;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
|
||||
import org.springframework.ide.vscode.commons.util.UriUtil;
|
||||
|
||||
@@ -569,10 +565,9 @@ public class IndexCacheOnDiscDeltaBased implements IndexCache {
|
||||
public static Gson createGson() {
|
||||
return new GsonBuilder()
|
||||
.registerTypeAdapter(DeltaStorage.class, new DeltaStorageAdapter())
|
||||
.registerTypeAdapter(Bean.class, new BeanJsonAdapter())
|
||||
.registerTypeAdapter(InjectionPoint.class, new InjectionPointJsonAdapter())
|
||||
.registerTypeAdapter(IndexCacheStore.class, new IndexCacheStoreAdapter())
|
||||
.registerTypeAdapter(SpringIndexElement.class, new SpringIndexElementAdapter())
|
||||
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(SpringIndexElement.class, "_internal_node_type")
|
||||
.recognizeSubtypes())
|
||||
.create();
|
||||
}
|
||||
|
||||
@@ -635,111 +630,5 @@ public class IndexCacheOnDiscDeltaBased implements IndexCache {
|
||||
}
|
||||
}
|
||||
|
||||
private static class BeanJsonAdapter implements JsonSerializer<Bean>, JsonDeserializer<Bean> {
|
||||
|
||||
@Override
|
||||
public Bean deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject parsedObject = json.getAsJsonObject();
|
||||
|
||||
String beanName = parsedObject.get("name").getAsString();
|
||||
String beanType = parsedObject.get("type").getAsString();
|
||||
|
||||
JsonElement locationObject = parsedObject.get("location");
|
||||
Location location = context.deserialize(locationObject, Location.class);
|
||||
|
||||
JsonElement injectionPointObject = parsedObject.get("injectionPoints");
|
||||
InjectionPoint[] injectionPoints = context.deserialize(injectionPointObject, InjectionPoint[].class);
|
||||
|
||||
JsonElement supertypesObject = parsedObject.get("supertypes");
|
||||
Set<String> supertypes = context.deserialize(supertypesObject, Set.class);
|
||||
|
||||
JsonElement annotationsObject = parsedObject.get("annotations");
|
||||
AnnotationMetadata[] annotations = annotationsObject == null ? DefaultValues.EMPTY_ANNOTATIONS : context.deserialize(annotationsObject, AnnotationMetadata[].class);
|
||||
|
||||
JsonElement isConfigurationObject = parsedObject.get("isConfiguration");
|
||||
boolean isConfiguration = context.deserialize(isConfigurationObject, boolean.class);
|
||||
|
||||
String symbolLabel = parsedObject.get("symbolLabel").getAsString();
|
||||
|
||||
JsonElement childrenObject = parsedObject.get("children");
|
||||
Type childrenListType = TypeToken.getParameterized(List.class, SpringIndexElement.class).getType();
|
||||
List<SpringIndexElement> children = context.deserialize(childrenObject, childrenListType);
|
||||
|
||||
Bean bean = new Bean(beanName, beanType, location, injectionPoints, supertypes, annotations, isConfiguration, symbolLabel);
|
||||
|
||||
for (SpringIndexElement springIndexElement : children) {
|
||||
bean.addChild(springIndexElement);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Bean src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject bean = new JsonObject();
|
||||
|
||||
bean.addProperty("name", src.getName());
|
||||
bean.addProperty("type", src.getType());
|
||||
|
||||
bean.add("location", context.serialize(src.getLocation()));
|
||||
bean.add("injectionPoints", context.serialize(src.getInjectionPoints()));
|
||||
|
||||
bean.add("supertypes", context.serialize(src.getSupertypes()));
|
||||
bean.add("annotations", context.serialize(src.getAnnotations()));
|
||||
|
||||
bean.addProperty("isConfiguration", src.isConfiguration());
|
||||
bean.addProperty("symbolLabel", src.getSymbolLabel());
|
||||
|
||||
Type childrenListType = TypeToken.getParameterized(List.class, SpringIndexElement.class).getType();
|
||||
bean.add("children", context.serialize(src.getChildren(), childrenListType));
|
||||
|
||||
bean.addProperty("_internal_node_type", src.getClass().getName());
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class InjectionPointJsonAdapter implements JsonDeserializer<InjectionPoint> {
|
||||
|
||||
@Override
|
||||
public InjectionPoint deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject parsedObject = json.getAsJsonObject();
|
||||
|
||||
String injectionPointName = parsedObject.get("name").getAsString();
|
||||
String injectionPointType = parsedObject.get("type").getAsString();
|
||||
|
||||
JsonElement locationObject = parsedObject.get("location");
|
||||
Location location = context.deserialize(locationObject, Location.class);
|
||||
|
||||
JsonElement annotationsObject = parsedObject.get("annotations");
|
||||
AnnotationMetadata[] annotations = annotationsObject == null ? DefaultValues.EMPTY_ANNOTATIONS : context.deserialize(annotationsObject, AnnotationMetadata[].class);
|
||||
|
||||
return new InjectionPoint(injectionPointName, injectionPointType, location, annotations);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SpringIndexElementAdapter implements JsonSerializer<SpringIndexElement>, JsonDeserializer<SpringIndexElement> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(SpringIndexElement element, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonElement elem = context.serialize(element);
|
||||
elem.getAsJsonObject().addProperty("_internal_node_type", element.getClass().getName());
|
||||
return elem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpringIndexElement deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject jsonObject = json.getAsJsonObject();
|
||||
String typeName = jsonObject.get("_internal_node_type").getAsString();
|
||||
|
||||
try {
|
||||
return context.deserialize(jsonObject, (Class<?>) Class.forName(typeName));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new JsonParseException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.springframework.ide.vscode.boot.java.commands;
|
||||
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
|
||||
public class SpringIndexCommands {
|
||||
|
||||
private static final String SPRING_STRUCTURE_CMD = "sts/spring-boot/structure";
|
||||
|
||||
public SpringIndexCommands(SimpleLanguageServer server, SpringMetamodelIndex metamodelIndex, JavaProjectFinder projectFinder) {
|
||||
server.onCommand(SPRING_STRUCTURE_CMD, params -> server.getAsync().invoke(() -> metamodelIndex.getProjects()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -53,10 +53,12 @@ public class JdtCronVisitorUtils {
|
||||
} else if (e instanceof TextBlock tb) {
|
||||
value = tb.getLiteralValue();
|
||||
}
|
||||
value = value.trim();
|
||||
if (value.startsWith("#{") || value.startsWith("${")) {
|
||||
// Either SPEL or Property Holder
|
||||
return false;
|
||||
if (value != null) {
|
||||
value = value.trim();
|
||||
if (value.startsWith("#{") || value.startsWith("${")) {
|
||||
// Either SPEL or Property Holder
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return value != null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user