Skip to content
Open
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,82 @@ open class JavaEmitter(
override fun emit(definition: Definition, module: Module, logger: Logger): Emitted =
super<LanguageEmitter>.emit(definition, module, logger).let {
val subPackageName = packageName + definition
val (allImports, processedCode) = processJavaImports(it.result, module.needImports())
val importStatements = buildImportStatements(allImports)
Emitted(
file = subPackageName.toDir() + it.file.sanitizeSymbol(),
result =
"""
|package $subPackageName;
|${if (module.needImports()) import else ""}
|${it.result}
|
|${importStatements.trim()}
|
|${processedCode.trim()}
|
""".trimMargin().trimStart()
)
}

private fun processJavaImports(code: String, needsWirespecImport: Boolean): Pair<List<String>, String> {
// Extract existing imports from the code
val importPattern = Regex("""^\s*import\s+([^;]+);\n""", RegexOption.MULTILINE)
val existingImports = importPattern.findAll(code)
.map { it.groupValues[1].trim() }
.toMutableSet()

// Remove existing import statements from code
var processedCode = importPattern.replace(code, "")

// Add Wirespec import if needed
if (needsWirespecImport) {
existingImports.add("$DEFAULT_SHARED_PACKAGE_STRING.java.Wirespec")
}

// Pattern to match java.util.*, java.io.*, java.time.*, etc. including nested packages
// Matches: java.util.List, java.util.regex.Pattern, java.util.concurrent.CompletableFuture, etc.
// Does not match java.lang.* which is auto-imported
val javaFqnPattern = Regex("""java\.(util|io|time|math|net|nio)(\.[a-z]+)*\.[A-Z][a-zA-Z0-9]*""")

// Find all unique fully qualified names in the code
val javaImports = javaFqnPattern.findAll(processedCode)
.map { it.value }
.toSet()

// Add java imports to existing imports
existingImports.addAll(javaImports)

// Replace each FQN with its simple name
javaImports.forEach { fqn ->
val simpleName = fqn.substringAfterLast('.')
processedCode = processedCode.replace(fqn, simpleName)
}

// Sort imports according to project conventions:
// 1. custom/project imports (alphabetically)
// 2. blank line
// 3. java/javax imports (alphabetically)
val (standardImports, customImports) = existingImports
.sorted()
.partition { it.startsWith("java.") || it.startsWith("javax.") }

val sortedImports = buildList {
addAll(customImports)
if (standardImports.isNotEmpty() && customImports.isNotEmpty()) {
add("") // Blank line separator
}
addAll(standardImports)
}

return sortedImports to processedCode
}

private fun buildImportStatements(imports: List<String>): String {
return if (imports.isEmpty()) {
""
} else {
imports.joinToString("\n") { import ->
if (import.isEmpty()) "" else "import $import;"
}
}
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ class AvroJavaEmitterTest {
)

val ast = AST(nonEmptyListOf(Module(FileUri(""), nonEmptyListOf(type))))
val expected = //language=Java
"""
val expected = """
|package packageName.avro;
|
|import packageName.model.Identifier;
Expand All @@ -74,7 +73,7 @@ class AvroJavaEmitterTest {
| return record;
| }
|}
""".trimMargin()
""".trimMargin()
val actual = emitter.emit(ast, noLogger)
assertEquals(expected, actual.find { it.file == "packageName/avro/IdentifierAvro.java" }?.result)
}
Expand All @@ -89,7 +88,6 @@ class AvroJavaEmitterTest {
)
val ast = AST(nonEmptyListOf(Module(FileUri(""), nonEmptyListOf(enum))))
val expected =
//language=Java
"""
|package packageName.avro;
|
Expand Down Expand Up @@ -533,7 +531,6 @@ class AvroJavaEmitterTest {
fun compileChannelTest() {
val result = CompileChannelTest.compiler { emitter }
val expect =
//language=Java
"""
|package packageName.channel;
|
Expand All @@ -552,7 +549,6 @@ class AvroJavaEmitterTest {
fun compileEnumTest() {
val result = CompileEnumTest.compiler { emitter }
val expect =
//language=Java
"""
|package packageName.model;
|
Expand Down Expand Up @@ -607,7 +603,6 @@ class AvroJavaEmitterTest {
fun compileRefinedTest() {
val result = CompileRefinedTest.compiler { emitter }
val expect =
//language=Java
"""
|package packageName.model;
|
Expand Down Expand Up @@ -757,7 +752,6 @@ class AvroJavaEmitterTest {
fun compileUnionTest() {
val result = CompileUnionTest.compiler { emitter }
val expect =
//language=Java
"""
|package packageName.model;
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import community.flock.wirespec.java.Wirespec;

import java.util.regex.Pattern;

public record StringRefinedRegex (String value) implements Wirespec.Refined<String> {
@Override
public String toString() { return value.toString(); }
public static boolean validate(StringRefinedRegex record) {
return java.util.regex.Pattern.compile("^[0-9a-f]{8}\\b-[0-9a-f]{4}\\b-[0-9a-f]{4}\\b-[0-9a-f]{4}\\b-[0-9a-f]{12}$").matcher(record.value).find();
return Pattern.compile("^[0-9a-f]{8}\\b-[0-9a-f]{4}\\b-[0-9a-f]{4}\\b-[0-9a-f]{4}\\b-[0-9a-f]{12}$").matcher(record.value).find();
}
@Override
public String getValue() { return value; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import community.flock.wirespec.java.Wirespec;

import java.util.regex.Pattern;

public record TodoId (String value) implements Wirespec.Refined<String> {
@Override
public String toString() { return value.toString(); }
public static boolean validate(TodoId record) {
return java.util.regex.Pattern.compile("^[0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}$").matcher(record.value).find();
return Pattern.compile("^[0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}$").matcher(record.value).find();
}
@Override
public String getValue() { return value; }
Expand Down
Loading
Loading