Skip to content

Commit 2548d85

Browse files
committed
GH-1638: avoid exception is version tag contains spaces (instead of a real version or just nothing)
1 parent 3b56ba9 commit 2548d85

File tree

3 files changed

+150
-26
lines changed

3 files changed

+150
-26
lines changed

headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/Optionals.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2017 Pivotal, Inc.
2+
* Copyright (c) 2017, 2025 Pivotal, Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -11,6 +11,7 @@
1111
package org.springframework.ide.vscode.commons.util;
1212

1313
import java.util.Optional;
14+
import java.util.function.Function;
1415

1516
import com.google.common.base.Supplier;
1617

@@ -26,4 +27,14 @@ public static <T> Optional<T> tryInOrder(Supplier<Optional<T>>... optionals) {
2627
}
2728
return Optional.empty();
2829
}
30+
31+
public static <A, T> Optional<T> ofThrowable(Function<A, T> supplier, A value) {
32+
try {
33+
return Optional.ofNullable(supplier.apply(value));
34+
}
35+
catch (Exception e) {
36+
return Optional.empty();
37+
}
38+
}
39+
2940
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.springframework.ide.vscode.commons.languageserver.util.InlayHintHandler;
4848
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
4949
import org.springframework.ide.vscode.commons.util.BadLocationException;
50+
import org.springframework.ide.vscode.commons.util.Optionals;
5051
import org.springframework.ide.vscode.commons.util.text.TextDocument;
5152

5253
public class PomInlayHintHandler implements InlayHintHandler {
@@ -132,14 +133,20 @@ public List<InlayHint> handle(TextDocument doc, Range range, CancelChecker cance
132133
hint.setLabel(List.of(label));
133134
return hint;
134135
}, (d, e) -> {
136+
135137
Optional<String> parentArtifactIdOpt = findChildElement(e, 0, "parent", "artifactId")
136138
.flatMap(PomInlayHintHandler::getNodeValue);
139+
137140
if (parentArtifactIdOpt.isPresent() && "spring-boot-starter-parent".equals(parentArtifactIdOpt.get())) {
141+
138142
Optional<DOMElement> parentVersionOpt = findChildElement(e, 0, "parent", "version");
139143
if (parentVersionOpt.isPresent()) {
140144
DOMElement parentVersion = parentVersionOpt.get();
141145
// Get the current version in the POM in case file is not saved
142-
Optional<Version> parentVersionValueOpt = getNodeValue(parentVersion).flatMap(s -> Optional.ofNullable(Version.parse(s)));
146+
147+
Optional<Version> parentVersionValueOpt = getNodeValue(parentVersion)
148+
.flatMap(value -> Optionals.ofThrowable((s) -> Version.parse(s), value));
149+
143150
if (parentVersionValueOpt.isPresent() && parentVersionValueOpt.get().compareTo(latestPatch) < 0) {
144151
try {
145152
return List.of(d.toPosition(parentVersion.getEndTagCloseOffset() + 1));

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

Lines changed: 130 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -75,30 +75,23 @@ void inlayProvided() throws Exception {
7575
SpringProjectsProvider projectProvider = mock(SpringProjectsProvider.class);
7676
when(projectProvider.getProject(SpringProjectUtil.SPRING_BOOT)).thenReturn(resolvedProject);
7777

78-
PomInlayHintHandler inlayHanlder = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
78+
PomInlayHintHandler inlayHandler = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
7979

80-
List<InlayHint> hints = inlayHanlder.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
80+
List<InlayHint> hints = inlayHandler.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
8181

8282
assertEquals(1, hints.size());
8383

8484
InlayHint hint = hints.get(0);
85-
8685
assertEquals(new Position(27, 15), hint.getPosition());
87-
8886
assertTrue(hint.getLabel().isRight());
89-
9087
assertEquals(1, hint.getLabel().getRight().size());
9188

9289
InlayHintLabelPart labelPart = hint.getLabel().getRight().get(0);
93-
9490
assertEquals("Add Spring Boot Starters...", labelPart.getValue());
9591

9692
Command cmd = labelPart.getCommand();
97-
9893
assertNotNull(cmd);
99-
10094
assertEquals("spring.initializr.addStarters", cmd.getCommand());
101-
10295
}
10396

10497
@Test
@@ -127,12 +120,10 @@ void inlayNotProvidedOutOfOssSupport() throws Exception {
127120
SpringProjectsProvider projectProvider = mock(SpringProjectsProvider.class);
128121
when(projectProvider.getProject(SpringProjectUtil.SPRING_BOOT)).thenReturn(resolvedProject);
129122

130-
PomInlayHintHandler inlayHanlder = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
131-
132-
List<InlayHint> hints = inlayHanlder.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
123+
PomInlayHintHandler inlayHandler = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
133124

125+
List<InlayHint> hints = inlayHandler.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
134126
assertEquals(0, hints.size());
135-
136127
}
137128

138129
@Test
@@ -165,32 +156,148 @@ void upgradePatchVersionInlay() throws Exception {
165156
SpringProjectsProvider projectProvider = mock(SpringProjectsProvider.class);
166157
when(projectProvider.getProject(SpringProjectUtil.SPRING_BOOT)).thenReturn(resolvedProject);
167158

168-
PomInlayHintHandler inlayHanlder = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
169-
170-
List<InlayHint> hints = inlayHanlder.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
159+
PomInlayHintHandler inlayHandler = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
171160

161+
List<InlayHint> hints = inlayHandler.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
172162
assertEquals(1, hints.size());
173163

174164
InlayHint hint = hints.get(0);
175-
176165
assertEquals(new Position(17, 34), hint.getPosition());
177-
178166
assertTrue(hint.getLabel().isRight());
179-
180167
assertEquals(1, hint.getLabel().getRight().size());
181168

182169
InlayHintLabelPart labelPart = hint.getLabel().getRight().get(0);
183-
184170
assertEquals("Upgrade to the Latest Patch", labelPart.getValue());
185171

186172
Command cmd = labelPart.getCommand();
187173

188174
assertNotNull(cmd);
189-
190175
assertEquals("sts/upgrade/spring-boot", cmd.getCommand());
191176
assertEquals(jp.getLocationUri().toASCIIString(), cmd.getArguments().get(0));
192177
assertEquals("1.5.10", cmd.getArguments().get(1));
178+
}
179+
180+
@Test
181+
void noInlayHintOnEmptyVersionTag() throws Exception {
182+
MavenJavaProject jp = projects.mavenProject("empty-boot-15-web-app");
193183

184+
String docUri = jp.getProjectBuild().getBuildFile().toASCIIString();
185+
186+
String pomFileContent = Files.readString(Paths.get(jp.getProjectBuild().getBuildFile()));
187+
pomFileContent = docUri.replace("1.5.8.RELEASE", "");
188+
189+
TextDocument doc = new TextDocument(docUri, LanguageId.XML, 0, pomFileContent);
190+
191+
JavaProjectFinder projectFinder = mock(JavaProjectFinder.class);
192+
when(projectFinder.find(any())).thenReturn(Optional.of(jp));
193+
194+
SimpleTextDocumentService documents = mock(SimpleTextDocumentService.class);
195+
when(documents.getLatestSnapshot(anyString())).thenReturn(doc);
196+
197+
SimpleLanguageServer server = mock(SimpleLanguageServer.class);
198+
when(server.getTextDocumentService()).thenReturn(documents);
199+
200+
ResolvedSpringProject resolvedProject = mock(ResolvedSpringProject.class);
201+
when(resolvedProject.getGenerations()).thenReturn(null);
202+
when(resolvedProject.getSlug()).thenReturn(SpringProjectUtil.SPRING_BOOT);
203+
when(resolvedProject.getReleases()).thenReturn(List.of(
204+
Version.parse("1.5.6"),
205+
Version.parse("1.5.7"),
206+
Version.parse("1.5.8"),
207+
Version.parse("1.5.9"),
208+
Version.parse("1.5.10"),
209+
Version.parse("2.0.0")
210+
));
211+
212+
SpringProjectsProvider projectProvider = mock(SpringProjectsProvider.class);
213+
when(projectProvider.getProject(SpringProjectUtil.SPRING_BOOT)).thenReturn(resolvedProject);
214+
215+
PomInlayHintHandler inlayHandler = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
216+
217+
List<InlayHint> hints = inlayHandler.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
218+
assertEquals(0, hints.size());
219+
}
220+
221+
@Test
222+
void noInlayHintOnEmptyVersionWithSpacesTag() throws Exception {
223+
MavenJavaProject jp = projects.mavenProject("empty-boot-15-web-app");
224+
225+
String docUri = jp.getProjectBuild().getBuildFile().toASCIIString();
226+
227+
String pomFileContent = Files.readString(Paths.get(jp.getProjectBuild().getBuildFile()));
228+
pomFileContent = pomFileContent.replace("1.5.8.RELEASE", " ");
229+
230+
TextDocument doc = new TextDocument(docUri, LanguageId.XML, 0, pomFileContent);
231+
232+
JavaProjectFinder projectFinder = mock(JavaProjectFinder.class);
233+
when(projectFinder.find(any())).thenReturn(Optional.of(jp));
234+
235+
SimpleTextDocumentService documents = mock(SimpleTextDocumentService.class);
236+
when(documents.getLatestSnapshot(anyString())).thenReturn(doc);
237+
238+
SimpleLanguageServer server = mock(SimpleLanguageServer.class);
239+
when(server.getTextDocumentService()).thenReturn(documents);
240+
241+
ResolvedSpringProject resolvedProject = mock(ResolvedSpringProject.class);
242+
when(resolvedProject.getGenerations()).thenReturn(null);
243+
when(resolvedProject.getSlug()).thenReturn(SpringProjectUtil.SPRING_BOOT);
244+
when(resolvedProject.getReleases()).thenReturn(List.of(
245+
Version.parse("1.5.6"),
246+
Version.parse("1.5.7"),
247+
Version.parse("1.5.8"),
248+
Version.parse("1.5.9"),
249+
Version.parse("1.5.10"),
250+
Version.parse("2.0.0")
251+
));
252+
253+
SpringProjectsProvider projectProvider = mock(SpringProjectsProvider.class);
254+
when(projectProvider.getProject(SpringProjectUtil.SPRING_BOOT)).thenReturn(resolvedProject);
255+
256+
PomInlayHintHandler inlayHandler = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
257+
258+
List<InlayHint> hints = inlayHandler.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
259+
assertEquals(0, hints.size());
260+
}
261+
262+
@Test
263+
void noInlayHintOnVersionTagWithNonParseableValue() throws Exception {
264+
MavenJavaProject jp = projects.mavenProject("empty-boot-15-web-app");
265+
266+
String docUri = jp.getProjectBuild().getBuildFile().toASCIIString();
267+
268+
String pomFileContent = Files.readString(Paths.get(jp.getProjectBuild().getBuildFile()));
269+
pomFileContent = pomFileContent.replace("1.5.8.RELEASE", "foo");
270+
271+
TextDocument doc = new TextDocument(docUri, LanguageId.XML, 0, pomFileContent);
272+
273+
JavaProjectFinder projectFinder = mock(JavaProjectFinder.class);
274+
when(projectFinder.find(any())).thenReturn(Optional.of(jp));
275+
276+
SimpleTextDocumentService documents = mock(SimpleTextDocumentService.class);
277+
when(documents.getLatestSnapshot(anyString())).thenReturn(doc);
278+
279+
SimpleLanguageServer server = mock(SimpleLanguageServer.class);
280+
when(server.getTextDocumentService()).thenReturn(documents);
281+
282+
ResolvedSpringProject resolvedProject = mock(ResolvedSpringProject.class);
283+
when(resolvedProject.getGenerations()).thenReturn(null);
284+
when(resolvedProject.getSlug()).thenReturn(SpringProjectUtil.SPRING_BOOT);
285+
when(resolvedProject.getReleases()).thenReturn(List.of(
286+
Version.parse("1.5.6"),
287+
Version.parse("1.5.7"),
288+
Version.parse("1.5.8"),
289+
Version.parse("1.5.9"),
290+
Version.parse("1.5.10"),
291+
Version.parse("2.0.0")
292+
));
293+
294+
SpringProjectsProvider projectProvider = mock(SpringProjectsProvider.class);
295+
when(projectProvider.getProject(SpringProjectUtil.SPRING_BOOT)).thenReturn(resolvedProject);
296+
297+
PomInlayHintHandler inlayHandler = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
298+
299+
List<InlayHint> hints = inlayHandler.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
300+
assertEquals(0, hints.size());
194301
}
195302

196303
@Test
@@ -221,10 +328,9 @@ void upgradePatchVersionInlay_AlreadyOnLatestPatch() throws Exception {
221328
SpringProjectsProvider projectProvider = mock(SpringProjectsProvider.class);
222329
when(projectProvider.getProject(SpringProjectUtil.SPRING_BOOT)).thenReturn(resolvedProject);
223330

224-
PomInlayHintHandler inlayHanlder = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
225-
226-
List<InlayHint> hints = inlayHanlder.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
331+
PomInlayHintHandler inlayHandler = new PomInlayHintHandler(server, projectFinder, ProjectObserver.NULL, projectProvider);
227332

333+
List<InlayHint> hints = inlayHandler.handle(doc, doc.toRange(0, doc.getLength()), mock(CancelChecker.class));
228334
assertEquals(0, hints.size());
229335
}
230336

0 commit comments

Comments
 (0)