Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,79 @@ compileJavacc {
]
}

// Post-process the generated CCJSqlParserTokenManager.java to split large static
// array initializers into separate methods, preventing the <clinit> method from
// exceeding the JVM's 64KB bytecode limit (which breaks ASM-based tools like sbt-assembly).
tasks.register('splitTokenManagerStaticInit') {
dependsOn(compileJavacc)

def tokenManagerFile = layout.buildDirectory.file(
"generated/javacc/net/sf/jsqlparser/parser/CCJSqlParserTokenManager.java"
)

inputs.file(tokenManagerFile)
outputs.file(tokenManagerFile)

doLast {
def file = tokenManagerFile.get().asFile
if (!file.exists()) {
throw new GradleException("CCJSqlParserTokenManager.java not found at ${file}")
}
def content = file.text

// Pattern matches static final array field declarations with inline initialization.
// We extract large ones and move their initialization into separate methods.
def fieldsToExtract = [
// [regex-safe field name, array type for method return]
['stringLiterals', 'int[]'],
['jjstrLiteralImages', 'String[]'],
['jjmatchKinds', 'int[]'],
['jjnewLexState', 'int[]'],
]

fieldsToExtract.each { entry ->
def fieldName = entry[0]
def arrayType = entry[1]

// Match: <modifiers> <type> <fieldName> = { ... };
// The field declaration may use 'public' or 'private' and 'static final'
def pattern = ~"(?s)((?:public|private)\\s+static\\s+final\\s+${java.util.regex.Pattern.quote(arrayType)}\\s+${fieldName}\\s*=\\s*)\\{(.*?)\\};"
def matcher = pattern.matcher(content)
if (matcher.find()) {
def prefix = matcher.group(1)
def body = matcher.group(2)
def methodName = "_init_${fieldName}"
def replacement = "${prefix}${methodName}();\n" +
" private static ${arrayType} ${methodName}() { return new ${arrayType} {${body}}; }"
content = matcher.replaceFirst(java.util.regex.Matcher.quoteReplacement(replacement))
logger.lifecycle("splitTokenManagerStaticInit: extracted ${fieldName} initialization into ${methodName}()")
}
}

// Handle int[][] arrays separately (jjcompositeState, jjnextStateSet)
def arrayArrayFields = ['jjcompositeState', 'jjnextStateSet']
arrayArrayFields.each { fieldName ->
def pattern = ~"(?s)(private\\s+static\\s+final\\s+int\\[\\]\\[\\]\\s+${fieldName}\\s*=\\s*)\\{(.*?)\\};"
def matcher = pattern.matcher(content)
if (matcher.find()) {
def prefix = matcher.group(1)
def body = matcher.group(2)
def methodName = "_init_${fieldName}"
def replacement = "${prefix}${methodName}();\n" +
" private static int[][] ${methodName}() { return new int[][] {${body}}; }"
content = matcher.replaceFirst(java.util.regex.Matcher.quoteReplacement(replacement))
logger.lifecycle("splitTokenManagerStaticInit: extracted ${fieldName} initialization into ${methodName}()")
}
}

file.text = content
}
}

tasks.withType(JavaCompile).configureEach {
dependsOn('splitTokenManagerStaticInit')
}

java {
withSourcesJar()
withJavadocJar()
Expand Down