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 @@ -5,13 +5,19 @@ import com.github.imflog.schema.registry.SchemaType
import io.confluent.kafka.schemaregistry.client.SchemaRegistryClient
import org.json.JSONArray
import org.json.JSONObject
import org.json.JSONTokener
import java.io.File

class AvroSchemaParser(
client: SchemaRegistryClient,
rootDir: File
) : SchemaParser(client, rootDir) {

data class MainSchema(
val schema: JSONObject,
val isObject: Boolean,
)

override val schemaType: SchemaType = SchemaType.AVRO

override fun resolveLocalReferences(
Expand All @@ -20,7 +26,7 @@ class AvroSchemaParser(
localReferences: List<LocalReference>
): String {
// Load and parse the main schema
val mainSchema = JSONObject(loadContent(schemaPath))
val mainSchema = loadMainSchema(loadContent(schemaPath))

// Create a map of reference name to schema content
val referenceSchemas = localReferences.associate { reference ->
Expand All @@ -31,8 +37,14 @@ class AvroSchemaParser(
val visitedReferences = mutableSetOf<String>()

// Process the schema recursively
val resolvedSchema = resolveReferences(mainSchema, referenceSchemas, null, visitedReferences)
return resolvedSchema.toString()
val resolvedSchema = resolveReferences(mainSchema.schema, referenceSchemas, null, visitedReferences)
if (mainSchema.isObject) {
return resolvedSchema.toString()
}
val myArray = JSONArray()
myArray.put(resolvedSchema.get("items"))

return myArray.toString();
}

private fun resolveReferences(
Expand Down Expand Up @@ -201,4 +213,25 @@ class AvroSchemaParser(

return null
}

// if json is object return it, if array with one item, coerce it into a json object
private fun loadMainSchema(input: String): MainSchema {
return when (val parsedInput = JSONTokener(input).nextValue()) {
is JSONObject -> MainSchema(parsedInput, true)
is JSONArray -> {
if (parsedInput.length() == 1) {
val mySchema = JSONObject();
mySchema.put("type", "array")
mySchema.put("items", parsedInput.get(0))
Comment on lines +222 to +225
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I see in the spec, it allows multiple primitive values. Things like ["string", "null"] is valid.


MainSchema(mySchema, false)
} else {
throw IllegalArgumentException("Invalid schema format: array must contain exactly one JSONObject")
}
}
else -> {
throw IllegalArgumentException("Invalid schema format: must be a JSONObject or an array containing a JSONObject")
}
Comment on lines +228 to +234
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this based on the specifications.
For me, we could have multiple items in the array and that represent an union, could be primitive types or objects.

WDYT ?

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.github.imflog.schema.registry.LocalReference
import io.confluent.kafka.schemaregistry.client.MockSchemaRegistryClient
import org.assertj.core.api.Assertions
import org.intellij.lang.annotations.Language
import org.json.JSONArray
import org.json.JSONObject
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
Expand Down Expand Up @@ -126,6 +127,64 @@ class AvroSchemaParserTest {
)
}

@Test
fun `Should resolve simple array type subject correctly`() {
// Given
val parser = AvroSchemaParser(schemaRegistryClient, File(testFilesPath))
val schema = File("${testFilesPath}testSubjectArraySimple.avsc")
// When
val resolvedSchema = parser.resolveLocalReferences(
"test",
schema.path,
listOf()
)
// Then
val resolved = JSONArray(resolvedSchema).toString()

@Language("JSON")
val expected = """
[
"string"
]
"""

Assertions.assertThat(resolved).isEqualTo(
JSONArray(expected).toString()
)
}

@Test
fun `Should resolve array type subject correctly`() {
// Given
val parser = AvroSchemaParser(schemaRegistryClient, File(testFilesPath))
val reference = LocalReference("B", "${testFilesPath}testType.avsc")
val schema = File("${testFilesPath}testSubjectArray.avsc")
// When
val resolvedSchema = parser.resolveLocalReferences(
"test",
schema.path,
listOf(reference)
)
// Then
val resolved = JSONArray(resolvedSchema).toString()

@Language("JSON")
val expected = """
[
{
"name":"B",
"namespace": "com.mycompany",
"type": "enum",
"symbols": ["X1", "X2"]
}
]
"""

Assertions.assertThat(resolved).isEqualTo(
JSONArray(expected).toString()
)
}

@Test
fun `Should handle local recursive type properly`() {
// Given
Expand Down
3 changes: 3 additions & 0 deletions src/test/resources/testSubjectArray.avsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
"com.mycompany.B"
]
3 changes: 3 additions & 0 deletions src/test/resources/testSubjectArraySimple.avsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
"string"
]