Skip to content

Commit 188237f

Browse files
committed
Polish and tests
1 parent 312860b commit 188237f

6 files changed

Lines changed: 995 additions & 28 deletions

File tree

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.springframework.ide.vscode.parser.postgresql.PostgreSqlQueryFormatter;
4040
import org.springframework.ide.vscode.boot.java.jdt.refactoring.AddQueryAnnotationRefactoring;
4141
import org.springframework.ide.vscode.boot.java.jdt.refactoring.JdtFixDescriptor;
42+
import org.springframework.ide.vscode.boot.java.jdt.refactoring.JdtRefactorUtils;
4243
import org.springframework.ide.vscode.boot.java.jdt.refactoring.JdtRefactorings;
4344
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
4445
import org.springframework.ide.vscode.commons.java.IJavaProject;
@@ -234,7 +235,7 @@ private static List<AddQueryAnnotationRefactoring.Attribute> createAttributeList
234235
}
235236
}
236237
};
237-
value = "\"\"\"\n" + formattedValue + "\n\"\"\"";
238+
value = "\"\"\"\n" + JdtRefactorUtils.escapeForTextBlock(formattedValue) + "\n\"\"\"";
238239
} else {
239240
value = "\"" + StringEscapeUtils.escapeJava(value).trim() + "\"";
240241
}
@@ -243,5 +244,6 @@ private static List<AddQueryAnnotationRefactoring.Attribute> createAttributeList
243244
}
244245
return result;
245246
}
247+
246248
}
247249

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/jdt/refactoring/AddQueryAnnotationRefactoring.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,16 @@ public void apply(ASTRewrite rewrite, CompilationUnit cu) {
8787
} else if (existing instanceof NormalAnnotation normalAnnotation) {
8888
addMissingAttributes(rewrite, ast, normalAnnotation);
8989
} else if (existing instanceof SingleMemberAnnotation singleMember) {
90-
replaceSingleMemberWithNormal(rewrite, ast, singleMember);
90+
boolean hasNonValueAttributes = attributes.stream().anyMatch(a -> !"value".equals(a.name()));
91+
if (hasNonValueAttributes) {
92+
replaceSingleMemberWithNormal(rewrite, ast, singleMember);
93+
}
9194
} else if (existing instanceof MarkerAnnotation marker && !attributes.isEmpty()) {
9295
rewrite.replace(marker, buildAnnotation(ast, attributes), null);
9396
}
9497

9598
JdtRefactorUtils.addImport(rewrite, ast, cu,
96-
new ClassType(extractPackageName(annotationFqn), extractSimpleName(annotationFqn)));
99+
new ClassType(JdtRefactorUtils.extractPackageName(annotationFqn), JdtRefactorUtils.extractSimpleName(annotationFqn)));
97100
}
98101

99102
private void addMissingAttributes(ASTRewrite rewrite, AST ast, NormalAnnotation annotation) {
@@ -116,7 +119,7 @@ private void replaceSingleMemberWithNormal(ASTRewrite rewrite, AST ast, SingleMe
116119
Expression existingValue = singleMember.getValue();
117120

118121
NormalAnnotation replacement = ast.newNormalAnnotation();
119-
replacement.setTypeName(ast.newSimpleName(extractSimpleName(annotationFqn)));
122+
replacement.setTypeName(ast.newSimpleName(JdtRefactorUtils.extractSimpleName(annotationFqn)));
120123

121124
@SuppressWarnings("unchecked")
122125
List<MemberValuePair> values = replacement.values();
@@ -182,7 +185,7 @@ private boolean matches(MethodDeclaration node) {
182185
}
183186

184187
private Annotation findAnnotation(MethodDeclaration node) {
185-
String simpleName = extractSimpleName(annotationFqn);
188+
String simpleName = JdtRefactorUtils.extractSimpleName(annotationFqn);
186189
for (Object mod : node.modifiers()) {
187190
if (mod instanceof Annotation a) {
188191
String name = a.getTypeName().getFullyQualifiedName();
@@ -196,7 +199,7 @@ private Annotation findAnnotation(MethodDeclaration node) {
196199

197200
@SuppressWarnings("unchecked")
198201
private Annotation buildAnnotation(AST ast, List<Attribute> attrs) {
199-
String simpleName = extractSimpleName(annotationFqn);
202+
String simpleName = JdtRefactorUtils.extractSimpleName(annotationFqn);
200203

201204
if (attrs.size() == 1 && "value".equals(attrs.get(0).name())) {
202205
SingleMemberAnnotation sma = ast.newSingleMemberAnnotation();
@@ -237,14 +240,4 @@ private Expression buildValue(AST ast, Attribute attr) {
237240
return sl;
238241
}
239242

240-
private static String extractSimpleName(String fqn) {
241-
int lastDot = fqn.lastIndexOf('.');
242-
return lastDot >= 0 ? fqn.substring(lastDot + 1) : fqn;
243-
}
244-
245-
private static String extractPackageName(String fqn) {
246-
int lastDot = fqn.lastIndexOf('.');
247-
return lastDot >= 0 ? fqn.substring(0, lastDot) : "";
248-
}
249-
250243
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/jdt/refactoring/JdtRefactorUtils.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,38 @@ else if (jdtEdit instanceof DeleteEdit de) {
159159
}
160160
}
161161

162+
/**
163+
* Returns the simple class name from a fully qualified name.
164+
* For example, {@code "org.example.Foo"} → {@code "Foo"}.
165+
*/
166+
public static String extractSimpleName(String fqn) {
167+
int lastDot = fqn.lastIndexOf('.');
168+
return lastDot >= 0 ? fqn.substring(lastDot + 1) : fqn;
169+
}
170+
171+
/**
172+
* Returns the package name from a fully qualified name.
173+
* For example, {@code "org.example.Foo"} → {@code "org.example"}.
174+
* Returns an empty string for default-package types.
175+
*/
176+
public static String extractPackageName(String fqn) {
177+
int lastDot = fqn.lastIndexOf('.');
178+
return lastDot >= 0 ? fqn.substring(0, lastDot) : "";
179+
}
180+
181+
/**
182+
* Escapes a raw string value so it can be safely embedded inside a Java text
183+
* block literal.
184+
* <p>
185+
* Backslashes must be doubled because Java recognises escape sequences (e.g.
186+
* {@code \'} → {@code '}) inside text blocks, which would silently drop a bare
187+
* {@code \} that appears before a quotable character.
188+
*
189+
* @param value the raw runtime string value to escape
190+
* @return the escaped string, safe to embed between {@code """} delimiters
191+
*/
192+
public static String escapeForTextBlock(String value) {
193+
return value.replace("\\", "\\\\");
194+
}
195+
162196
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/jdt/refactoring/TypeSafePropertyReferenceRefactoring.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ public void apply(ASTRewrite rewrite, CompilationUnit cu) {
187187
*/
188188
private static ExpressionMethodReference buildMethodReference(AST ast, PropertySegment segment) {
189189
ExpressionMethodReference ref = ast.newExpressionMethodReference();
190-
ref.setExpression(ast.newSimpleName(extractSimpleName(segment.domainTypeFqn())));
190+
ref.setExpression(ast.newSimpleName(JdtRefactorUtils.extractSimpleName(segment.domainTypeFqn())));
191191
ref.setName(ast.newSimpleName(segment.methodName()));
192192
return ref;
193193
}
@@ -231,18 +231,8 @@ public boolean visit(StringLiteral node) {
231231
return result[0];
232232
}
233233

234-
private static String extractSimpleName(String fqn) {
235-
int lastDot = fqn.lastIndexOf('.');
236-
return lastDot >= 0 ? fqn.substring(lastDot + 1) : fqn;
237-
}
238-
239-
private static String extractPackageName(String fqn) {
240-
int lastDot = fqn.lastIndexOf('.');
241-
return lastDot >= 0 ? fqn.substring(0, lastDot) : "";
242-
}
243-
244234
private static ClassType classTypeFromFqn(String fqn) {
245-
return new ClassType(extractPackageName(fqn), extractSimpleName(fqn));
235+
return new ClassType(JdtRefactorUtils.extractPackageName(fqn), JdtRefactorUtils.extractSimpleName(fqn));
246236
}
247237

248238
}

0 commit comments

Comments
 (0)