GH-1040: customized gson deserialization of beans in order to invoke constructor instead of gson object creation magic - to benefit from empty injection point optimization code
This commit is contained in:
@@ -31,7 +31,13 @@ public class Bean {
|
||||
this.type = type;
|
||||
this.location = location;
|
||||
|
||||
this.injectionPoints = injectionPoints;
|
||||
if (injectionPoints != null && injectionPoints.length == 0) {
|
||||
this.injectionPoints = DefaultValues.EMPTY_INJECTION_POINTS;
|
||||
}
|
||||
else {
|
||||
this.injectionPoints = injectionPoints;
|
||||
}
|
||||
|
||||
this.supertypes = new HashSet<>(Arrays.asList(supertypes));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*******************************************************************************
|
||||
* 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.commons.protocol.spring;
|
||||
|
||||
public class DefaultValues {
|
||||
|
||||
public static InjectionPoint[] EMPTY_INJECTION_POINTS = new InjectionPoint[0];
|
||||
|
||||
}
|
||||
@@ -47,6 +47,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.jdt.imports.ImportRewrite;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.DefaultValues;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.InjectionPoint;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.CollectorUtil;
|
||||
@@ -60,8 +61,6 @@ public class ASTUtils {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ASTUtils.class);
|
||||
|
||||
public static InjectionPoint[] EMPTY_INJECTION_POINTS = new InjectionPoint[0];
|
||||
|
||||
public static DocumentRegion nameRegion(TextDocument doc, Annotation annotation) {
|
||||
int start = annotation.getTypeName().getStartPosition();
|
||||
int end = start + annotation.getTypeName().getLength();
|
||||
@@ -405,7 +404,7 @@ public class ASTUtils {
|
||||
}
|
||||
}
|
||||
|
||||
return result.size() > 0 ? result.toArray(new InjectionPoint[result.size()]) : EMPTY_INJECTION_POINTS;
|
||||
return result.size() > 0 ? result.toArray(new InjectionPoint[result.size()]) : DefaultValues.EMPTY_INJECTION_POINTS;
|
||||
}
|
||||
|
||||
public static InjectionPoint[] findInjectionPoints(TypeDeclaration type, TextDocument doc) throws BadLocationException {
|
||||
@@ -454,7 +453,7 @@ public class ASTUtils {
|
||||
}
|
||||
}
|
||||
|
||||
return result.size() > 0 ? result.toArray(new InjectionPoint[result.size()]) : EMPTY_INJECTION_POINTS;
|
||||
return result.size() > 0 ? result.toArray(new InjectionPoint[result.size()]) : DefaultValues.EMPTY_INJECTION_POINTS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -30,9 +30,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.boot.java.handlers.SymbolAddOnInformation;
|
||||
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;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
@@ -293,8 +296,11 @@ public class SymbolCacheOnDisc implements SymbolCache {
|
||||
}
|
||||
}
|
||||
|
||||
private Gson createGson() {
|
||||
return new GsonBuilder().registerTypeAdapter(SymbolAddOnInformation.class, new SymbolAddOnInformationAdapter()).create();
|
||||
public static Gson createGson() {
|
||||
return new GsonBuilder()
|
||||
.registerTypeAdapter(SymbolAddOnInformation.class, new SymbolAddOnInformationAdapter())
|
||||
.registerTypeAdapter(Bean.class, new BeanJsonAdapter())
|
||||
.create();
|
||||
}
|
||||
|
||||
|
||||
@@ -355,4 +361,29 @@ public class SymbolCacheOnDisc implements SymbolCache {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gson adapter to store subtype information for symbol addon informations
|
||||
*/
|
||||
private static class BeanJsonAdapter implements 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");
|
||||
String[] supertypes = context.deserialize(supertypesObject, String[].class);
|
||||
|
||||
return new Bean(beanName, beanType, location, injectionPoints, supertypes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
@@ -24,9 +25,13 @@ import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SymbolCacheOnDisc;
|
||||
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 com.google.gson.Gson;
|
||||
|
||||
public class SpringMetamodelIndexTest {
|
||||
|
||||
private InjectionPoint[] emptyInjectionPoints = new InjectionPoint[0];
|
||||
@@ -209,5 +214,57 @@ public class SpringMetamodelIndexTest {
|
||||
assertFalse(beansList.contains(bean2));
|
||||
assertTrue(beansList.contains(bean3));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOverallSerializeDeserializeBeans() {
|
||||
InjectionPoint point1 = new InjectionPoint("point1", "point1-type", locationForDoc2);
|
||||
InjectionPoint point2 = new InjectionPoint("point2", "point2-type", locationForDoc1);
|
||||
|
||||
Bean bean1 = new Bean("beanName1", "beanType", locationForDoc1, new InjectionPoint[] {point1, point2}, new String[] {"supertype1", "supertype2"});
|
||||
String serialized = bean1.toString();
|
||||
|
||||
Gson gson = SymbolCacheOnDisc.createGson();
|
||||
Bean deserializedBean = gson.fromJson(serialized, Bean.class);
|
||||
|
||||
assertEquals("beanName1", deserializedBean.getName());
|
||||
assertEquals("beanType", deserializedBean.getType());
|
||||
assertEquals(locationForDoc1, deserializedBean.getLocation());
|
||||
|
||||
InjectionPoint[] points = deserializedBean.getInjectionPoints();
|
||||
assertEquals(2, points.length);
|
||||
|
||||
assertEquals("point1", points[0].getName());
|
||||
assertEquals("point1-type", points[0].getType());
|
||||
assertEquals(locationForDoc2, points[0].getLocation());
|
||||
|
||||
assertEquals("point2", points[1].getName());
|
||||
assertEquals("point2-type", points[1].getType());
|
||||
assertEquals(locationForDoc1, points[1].getLocation());
|
||||
|
||||
assertTrue(deserializedBean.isTypeCompatibleWith("supertype1"));
|
||||
assertTrue(deserializedBean.isTypeCompatibleWith("supertype2"));
|
||||
assertFalse(deserializedBean.isTypeCompatibleWith("java.lang.String"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmptyInjectionPointsOptimizationWithSerializeDeserializeBeans() {
|
||||
Bean bean1 = new Bean("beanName1", "beanType", locationForDoc1, emptyInjectionPoints, emptySupertypes);
|
||||
String serialized = bean1.toString();
|
||||
|
||||
Gson gson = SymbolCacheOnDisc.createGson();
|
||||
Bean deserializedBean = gson.fromJson(serialized, Bean.class);
|
||||
|
||||
assertEquals("beanName1", deserializedBean.getName());
|
||||
assertEquals("beanType", deserializedBean.getType());
|
||||
assertEquals(locationForDoc1, deserializedBean.getLocation());
|
||||
|
||||
assertSame(DefaultValues.EMPTY_INJECTION_POINTS, deserializedBean.getInjectionPoints());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmptyInjectionPointsOptimization() {
|
||||
Bean bean1 = new Bean("beanName1", "beanType", locationForDoc1, emptyInjectionPoints, emptySupertypes);
|
||||
assertSame(DefaultValues.EMPTY_INJECTION_POINTS, bean1.getInjectionPoints());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,9 +33,9 @@ import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
|
||||
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
|
||||
import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
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.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
@@ -137,7 +137,7 @@ public class SpringMetamodelIndexerBeansTest {
|
||||
|
||||
InjectionPoint[] injectionPoints = beans[0].getInjectionPoints();
|
||||
assertEquals(0, injectionPoints.length);
|
||||
assertSame(ASTUtils.EMPTY_INJECTION_POINTS, injectionPoints);
|
||||
assertSame(DefaultValues.EMPTY_INJECTION_POINTS, injectionPoints);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -213,7 +213,7 @@ public class SpringMetamodelIndexerBeansTest {
|
||||
|
||||
InjectionPoint[] injectionPoints = beans[0].getInjectionPoints();
|
||||
assertEquals(0, injectionPoints.length);
|
||||
assertSame(ASTUtils.EMPTY_INJECTION_POINTS, injectionPoints);
|
||||
assertSame(DefaultValues.EMPTY_INJECTION_POINTS, injectionPoints);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user