Skip to content

Commit 7b08430

Browse files
committed
feat(parser): expose leading comments via getLeadingComments()
Keep the serial UID from 066f581 so existing serialized models remain readable. Return the original comment token images without line terminators. Signed-off-by: 付典 <fudianchn@gmail.com>
1 parent 066f581 commit 7b08430

4 files changed

Lines changed: 121 additions & 0 deletions

File tree

‎src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@
99
*/
1010
package net.sf.jsqlparser.parser;
1111

12+
import java.util.ArrayList;
13+
import java.util.Collections;
14+
import java.util.List;
1215
import java.util.Set;
1316
import java.util.TreeSet;
1417

1518
public class ASTNodeAccessImpl implements ASTNodeAccess {
1619

20+
private static final long serialVersionUID = 3920262240331742793L;
21+
1722
private transient Node node;
1823

1924
@Override
@@ -26,6 +31,26 @@ public void setASTNode(Node node) {
2631
this.node = node;
2732
}
2833

34+
/**
35+
* The comments preceding this node's first token, in source order, with the original token
36+
* images. Line comments do not include their line terminator; callers must add a line break
37+
* when prepending them to SQL. Empty for nodes built programmatically, which carry no AST.
38+
*/
39+
public List<String> getLeadingComments() {
40+
Node node = getASTNode();
41+
if (node == null) {
42+
return new ArrayList<>();
43+
}
44+
List<String> comments = new ArrayList<>();
45+
for (Token specialToken =
46+
node.jjtGetFirstToken().specialToken; specialToken != null; specialToken =
47+
specialToken.specialToken) {
48+
comments.add(specialToken.image);
49+
}
50+
Collections.reverse(comments);
51+
return comments;
52+
}
53+
2954
public StringBuilder appendTo(StringBuilder builder) {
3055
// don't add spaces around the following punctuation
3156
final Set<String> punctuation = new TreeSet<>(Set.of(".", "[", "]"));
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2019 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.parser;
11+
12+
import static org.junit.jupiter.api.Assertions.assertEquals;
13+
import static org.junit.jupiter.api.Assertions.assertFalse;
14+
15+
import java.util.List;
16+
import net.sf.jsqlparser.JSQLParserException;
17+
import net.sf.jsqlparser.statement.Statements;
18+
import net.sf.jsqlparser.statement.select.PlainSelect;
19+
import net.sf.jsqlparser.statement.select.Select;
20+
import org.junit.jupiter.api.Test;
21+
import org.junit.jupiter.params.ParameterizedTest;
22+
import org.junit.jupiter.params.provider.ValueSource;
23+
24+
public class LeadingCommentsTest {
25+
26+
@Test
27+
public void blockCommentsBeforeStatementInSourceOrder() throws JSQLParserException {
28+
Select select = (Select) CCJSqlParserUtil
29+
.parse("/* keep orderby */ /*+ FULL(t) */ SELECT * FROM mytable");
30+
assertEquals(List.of("/* keep orderby */", "/*+ FULL(t) */"), select.getLeadingComments());
31+
}
32+
33+
@ParameterizedTest
34+
@ValueSource(strings = {"\n", "\r\n", "\r"})
35+
public void lineCommentsExcludeLineTerminators(String lineTerminator)
36+
throws JSQLParserException {
37+
Select select =
38+
(Select) CCJSqlParserUtil.parse("-- paging hint" + lineTerminator + "SELECT 1");
39+
assertEquals(List.of("-- paging hint"), select.getLeadingComments());
40+
}
41+
42+
@Test
43+
public void mixedCommentsRetainExactImagesAndSourceOrder() throws JSQLParserException {
44+
Select select = (Select) CCJSqlParserUtil
45+
.parse("/* a */ -- b\r\n// c\r/* d */ SELECT 1");
46+
assertEquals(List.of("/* a */", "-- b", "// c", "/* d */"), select.getLeadingComments());
47+
}
48+
49+
@Test
50+
public void commentInsideStatementIsNotLeading() throws JSQLParserException {
51+
Select select = (Select) CCJSqlParserUtil.parse("SELECT /* mid comment */ 1");
52+
assertEquals(List.of(), select.getLeadingComments());
53+
}
54+
55+
@Test
56+
public void statementWithoutComments() throws JSQLParserException {
57+
Select select = (Select) CCJSqlParserUtil.parse("SELECT * FROM mytable");
58+
assertEquals(List.of(), select.getLeadingComments());
59+
}
60+
61+
@Test
62+
public void programmaticStatementHasNoLeadingComments() {
63+
assertEquals(List.of(), new PlainSelect().getLeadingComments());
64+
}
65+
66+
@Test
67+
public void toStringDropsLeadingCommentsAsBefore() throws JSQLParserException {
68+
Select select = (Select) CCJSqlParserUtil
69+
.parse("/* keep orderby */ SELECT * FROM mytable");
70+
assertFalse(select.toString().contains("/*"));
71+
}
72+
73+
@Test
74+
public void commentsSplitPerStatement() throws JSQLParserException {
75+
Statements statements = CCJSqlParserUtil
76+
.parseStatements("/* first */ SELECT 1; /* second */ SELECT 2");
77+
assertEquals(List.of("/* first */"), ((Select) statements.get(0)).getLeadingComments());
78+
assertEquals(List.of("/* second */"), ((Select) statements.get(1)).getLeadingComments());
79+
}
80+
}

‎src/test/java/net/sf/jsqlparser/statement/SerializationTest.java‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
import java.io.ByteArrayInputStream;
1313
import java.io.ByteArrayOutputStream;
1414
import java.io.IOException;
15+
import java.io.InputStream;
1516
import java.io.ObjectInputStream;
1617
import java.io.ObjectOutputStream;
1718
import java.math.BigDecimal;
19+
import java.util.List;
1820
import java.util.stream.Stream;
1921
import net.sf.jsqlparser.JSQLParserException;
2022
import net.sf.jsqlparser.expression.SpannerInterleaveIn;
@@ -34,6 +36,20 @@
3436
import org.junit.jupiter.params.provider.ValueSource;
3537

3638
public class SerializationTest {
39+
@Test
40+
void deserializeSelectFromBeforeLeadingCommentsAccessor() throws Exception {
41+
try (InputStream serialized = getClass().getResourceAsStream(
42+
"/net/sf/jsqlparser/parser/plain-select-066f581e.ser")) {
43+
Assertions.assertNotNull(serialized);
44+
try (ObjectInputStream in = new ObjectInputStream(serialized)) {
45+
PlainSelect select =
46+
Assertions.assertInstanceOf(PlainSelect.class, in.readObject());
47+
Assertions.assertNull(select.getASTNode());
48+
Assertions.assertEquals(List.of(), select.getLeadingComments());
49+
}
50+
}
51+
}
52+
3753
@Test
3854
void serializeWithItem() throws JSQLParserException, IOException, ClassNotFoundException {
3955
String sqlStr =
Binary file not shown.

0 commit comments

Comments
 (0)