Skip to content

Commit 8f6b5a6

Browse files
committed
GH-1473: fixing deserialization of index cache issue with duplicated type name attribute
Fixes GH-1473
1 parent 6698801 commit 8f6b5a6

File tree

7 files changed

+73
-20
lines changed

7 files changed

+73
-20
lines changed

headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/spring/Bean.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,5 +98,9 @@ public String toString() {
9898
Gson gson = new Gson();
9999
return gson.toJson(this);
100100
}
101+
102+
public Set<String> getSupertypes() {
103+
return supertypes;
104+
}
101105

102106
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheOnDisc.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656

5757
/**
5858
* @author Martin Lippert
59+
*
60+
* @deprecated Use IndexCacheOnDiscDeltaBased - this class is no longer maintained and up-to-date with the latest index changes
5961
*/
6062
public class IndexCacheOnDisc implements IndexCache {
6163

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/cache/IndexCacheOnDiscDeltaBased.java

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -367,17 +367,6 @@ private <T extends IndexCacheable> Pair<IndexCacheStore<T>, Integer> retrieveSto
367367

368368

369369

370-
public static Gson createGson() {
371-
return new GsonBuilder()
372-
.registerTypeAdapter(DeltaStorage.class, new DeltaStorageAdapter())
373-
.registerTypeAdapter(Bean.class, new BeanJsonAdapter())
374-
.registerTypeAdapter(InjectionPoint.class, new InjectionPointJsonAdapter())
375-
.registerTypeAdapter(IndexCacheStore.class, new IndexCacheStoreAdapter())
376-
.registerTypeAdapter(SpringIndexElement.class, new SpringIndexElementAdapter())
377-
.create();
378-
}
379-
380-
381370
/**
382371
* just keep a md5 hash internally for identifying files to save memory
383372
*/
@@ -577,6 +566,17 @@ public IndexCacheStore<T> apply(IndexCacheStore<T> store) {
577566
//
578567

579568

569+
public static Gson createGson() {
570+
return new GsonBuilder()
571+
.registerTypeAdapter(DeltaStorage.class, new DeltaStorageAdapter())
572+
.registerTypeAdapter(Bean.class, new BeanJsonAdapter())
573+
.registerTypeAdapter(InjectionPoint.class, new InjectionPointJsonAdapter())
574+
.registerTypeAdapter(IndexCacheStore.class, new IndexCacheStoreAdapter())
575+
.registerTypeAdapter(SpringIndexElement.class, new SpringIndexElementAdapter())
576+
.create();
577+
}
578+
579+
580580
private static class IndexCacheStoreAdapter implements JsonDeserializer<IndexCacheStore<?>> {
581581

582582
@SuppressWarnings({ "rawtypes", "unchecked" })
@@ -635,7 +635,7 @@ public DeltaStorage<?> deserialize(JsonElement json, Type type, JsonDeserializat
635635
}
636636
}
637637

638-
private static class BeanJsonAdapter implements JsonDeserializer<Bean> {
638+
private static class BeanJsonAdapter implements JsonSerializer<Bean>, JsonDeserializer<Bean> {
639639

640640
@Override
641641
public Bean deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
@@ -670,6 +670,30 @@ public Bean deserialize(JsonElement json, Type type, JsonDeserializationContext
670670

671671
return bean;
672672
}
673+
674+
@Override
675+
public JsonElement serialize(Bean src, Type typeOfSrc, JsonSerializationContext context) {
676+
JsonObject bean = new JsonObject();
677+
678+
bean.addProperty("name", src.getName());
679+
bean.addProperty("type", src.getType());
680+
681+
bean.add("location", context.serialize(src.getLocation()));
682+
bean.add("injectionPoints", context.serialize(src.getInjectionPoints()));
683+
684+
bean.add("supertypes", context.serialize(src.getSupertypes()));
685+
bean.add("annotations", context.serialize(src.getAnnotations()));
686+
687+
bean.addProperty("isConfiguration", src.isConfiguration());
688+
689+
Type childrenListType = TypeToken.getParameterized(List.class, SpringIndexElement.class).getType();
690+
bean.add("children", context.serialize(src.getChildren(), childrenListType));
691+
692+
bean.addProperty("_internal_node_type", src.getClass().getName());
693+
694+
return bean;
695+
}
696+
673697
}
674698

675699
private static class InjectionPointJsonAdapter implements JsonDeserializer<InjectionPoint> {
@@ -696,14 +720,14 @@ private static class SpringIndexElementAdapter implements JsonSerializer<SpringI
696720
@Override
697721
public JsonElement serialize(SpringIndexElement element, Type typeOfSrc, JsonSerializationContext context) {
698722
JsonElement elem = context.serialize(element);
699-
elem.getAsJsonObject().addProperty("type", element.getClass().getName());
723+
elem.getAsJsonObject().addProperty("_internal_node_type", element.getClass().getName());
700724
return elem;
701725
}
702726

703727
@Override
704728
public SpringIndexElement deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
705729
JsonObject jsonObject = json.getAsJsonObject();
706-
String typeName = jsonObject.get("type").getAsString();
730+
String typeName = jsonObject.get("_internal_node_type").getAsString();
707731

708732
try {
709733
return context.deserialize(jsonObject, (Class<?>) Class.forName(typeName));

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringFactoriesIndexer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public class SpringFactoriesIndexer implements SpringIndexer {
5757

5858
// whenever the implementation of the indexer changes in a way that the stored data in the cache is no longer valid,
5959
// we need to change the generation - this will result in a re-indexing due to no up-to-date cache data being found
60-
private static final String GENERATION = "GEN-10";
60+
private static final String GENERATION = "GEN-11";
6161

6262
private static final String FILE_PATTERN = "**/META-INF/spring/*.factories";
6363

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public static enum SCAN_PASS {
9292

9393
// whenever the implementation of the indexer changes in a way that the stored data in the cache is no longer valid,
9494
// we need to change the generation - this will result in a re-indexing due to no up-to-date cache data being found
95-
private static final String GENERATION = "GEN-14";
95+
private static final String GENERATION = "GEN-15";
9696
private static final String INDEX_FILES_TASK_ID = "index-java-source-files-task-";
9797

9898
private static final String SYMBOL_KEY = "symbols";

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public class SpringIndexerXML implements SpringIndexer {
5454

5555
// whenever the implementation of the indexer changes in a way that the stored data in the cache is no longer valid,
5656
// we need to change the generation - this will result in a re-indexing due to no up-to-date cache data being found
57-
private static final String GENERATION = "GEN-9";
57+
private static final String GENERATION = "GEN-10";
5858

5959
private static final String SYMBOL_KEY = "symbols";
6060
private static final String BEANS_KEY = "beans";

headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringMetamodelIndexTest.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import static org.junit.jupiter.api.Assertions.assertEquals;
1414
import static org.junit.jupiter.api.Assertions.assertFalse;
1515
import static org.junit.jupiter.api.Assertions.assertNotNull;
16-
import static org.junit.jupiter.api.Assertions.assertNull;
1716
import static org.junit.jupiter.api.Assertions.assertSame;
1817
import static org.junit.jupiter.api.Assertions.assertTrue;
1918

@@ -250,9 +249,9 @@ void testOverallSerializeDeserializeBeans() {
250249
InjectionPoint point2 = new InjectionPoint("point2", "point2-type", locationForDoc1, null);
251250

252251
Bean bean1 = new Bean("beanName1", "beanType", locationForDoc1, new InjectionPoint[] {point1, point2}, Set.of("supertype1", "supertype2"), emptyAnnotations, true);
253-
String serialized = bean1.toString();
254252

255253
Gson gson = IndexCacheOnDiscDeltaBased.createGson();
254+
String serialized = gson.toJson(bean1);
256255
Bean deserializedBean = gson.fromJson(serialized, Bean.class);
257256

258257
assertEquals("beanName1", deserializedBean.getName());
@@ -301,9 +300,9 @@ void testOverallSerializeDeserializeBeans() {
301300
@Test
302301
void testEmptyInjectionPointsOptimizationWithSerializeDeserializeBeans() {
303302
Bean bean1 = new Bean("beanName1", "beanType", locationForDoc1, emptyInjectionPoints, emptySupertypes, emptyAnnotations, false);
304-
String serialized = bean1.toString();
305303

306304
Gson gson = IndexCacheOnDiscDeltaBased.createGson();
305+
String serialized = gson.toJson(bean1);
307306
Bean deserializedBean = gson.fromJson(serialized, Bean.class);
308307

309308
assertEquals("beanName1", deserializedBean.getName());
@@ -446,6 +445,30 @@ void testSpringIndexStructurePolymorphicSerialization() {
446445
void testSerializeDeserializeBeansWithChildElements() {
447446

448447
Gson gson = IndexCacheOnDiscDeltaBased.createGson();
448+
449+
Bean bean1 = new Bean("beanName1", "beanType1", locationForDoc1, emptyInjectionPoints, Set.of("supertype1", "supertype2"), emptyAnnotations, false);
450+
Bean bean2 = new Bean("beanName2", "beanType2", locationForDoc1, emptyInjectionPoints, Set.of("supertype3", "supertype4, supertype5"), emptyAnnotations, false);
451+
452+
Bean bean3 = new Bean("beanName3", "beanType1", locationForDoc1, emptyInjectionPoints, Set.of("supertype1", "supertype2"), emptyAnnotations, false);
453+
Bean bean4 = new Bean("beanName4", "beanType2", locationForDoc1, emptyInjectionPoints, Set.of("supertype3", "supertype4, supertype5"), emptyAnnotations, false);
454+
455+
bean1.addChild(bean2);
456+
bean2.addChild(bean3);
457+
bean3.addChild(bean4);
458+
459+
String serialized = gson.toJson(bean1);
460+
Bean newBean = gson.fromJson(serialized, Bean.class);
461+
462+
assertEquals("beanName1", newBean.getName());
463+
assertEquals("beanName2", ((Bean) newBean.getChildren().get(0)).getName());
464+
assertEquals("beanName3", ((Bean) newBean.getChildren().get(0).getChildren().get(0)).getName());
465+
assertEquals("beanName4", ((Bean) newBean.getChildren().get(0).getChildren().get(0).getChildren().get(0)).getName());
466+
}
467+
468+
@Test
469+
void testSerializeDeserializeIndexElementsWithChildElements() {
470+
471+
Gson gson = IndexCacheOnDiscDeltaBased.createGson();
449472

450473
SubType2 childOfChild = new SubType2();
451474
SubType1 child1 = new SubType1();

0 commit comments

Comments
 (0)