This repository has been archived by the owner on Apr 12, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add missing partition count from the subtitle binding * Replace jsontoavro converter * Add array parser test * Add byte parser test * Add unit tests for simple type parsers * Add record parser test * Reduce MCC for SimpleTypeParsersFactory * Reduce MCC of FieldParser * Improve unit tests * Add shortcut to search a schema in list schema view
- Loading branch information
1 parent
fb8d1de
commit 346c51d
Showing
36 changed files
with
921 additions
and
635 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
org.gradle.parallel=true | ||
org.gradle.parallel=true | ||
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
src/main/kotlin/insulator/lib/helpers/ExceptionHandlingHelper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,19 @@ | ||
package insulator.lib.helpers | ||
|
||
import arrow.core.Either | ||
import arrow.core.flatMap | ||
import arrow.core.left | ||
import arrow.core.right | ||
|
||
fun <R> Result<R>.toEither() = this.fold({ it.right() }, { it.left() }) | ||
fun <R, T : Throwable> Result<R>.toEither(f: (Throwable) -> T) = this.fold({ it.right() }, { it.left() }).mapLeft { f(it) } | ||
|
||
fun <A, B> List<Either<A, B>>.toEitherOfList() = | ||
this.fold(emptyList<B>().right() as Either<A, List<B>>) { lst, v -> | ||
lst.flatMap { | ||
when (v) { | ||
is Either.Left<A> -> v | ||
is Either.Right<B> -> it.plus(v.b).right() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 0 additions & 135 deletions
135
src/main/kotlin/insulator/lib/jsonhelper/JsonToAvroConverter.kt
This file was deleted.
Oops, something went wrong.
39 changes: 39 additions & 0 deletions
39
src/main/kotlin/insulator/lib/jsonhelper/jsontoavro/FieldParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package insulator.lib.jsonhelper.jsontoavro | ||
|
||
import arrow.core.left | ||
import insulator.lib.jsonhelper.jsontoavro.fieldparser.ComplexTypeParsersFactory | ||
import insulator.lib.jsonhelper.jsontoavro.fieldparser.SimpleTypeParsersFactory | ||
import org.apache.avro.Schema | ||
|
||
class FieldParser( | ||
simpleTypeParsersFactory: SimpleTypeParsersFactory, | ||
complexTypeParsersFactory: ComplexTypeParsersFactory | ||
) { | ||
|
||
private val simpleTypeParsers = simpleTypeParsersFactory.build() | ||
private val complexTypeParsers = complexTypeParsersFactory.build(this) | ||
private val parsersLookup = mapOf( | ||
// composed types | ||
Schema.Type.RECORD to complexTypeParsers.recordParser, | ||
Schema.Type.ARRAY to complexTypeParsers.arrayParser, | ||
Schema.Type.UNION to complexTypeParsers.unionParser, | ||
Schema.Type.BYTES to complexTypeParsers.byteParser, | ||
Schema.Type.FIXED to jsonFieldParser { _, _ -> JsonFieldParsingException("Avro FIXED type not supported").left() }, | ||
Schema.Type.MAP to jsonFieldParser { _, _ -> JsonFieldParsingException("Avro MAP type not supported").left() }, | ||
|
||
// simple types | ||
Schema.Type.STRING to simpleTypeParsers.stringParser, | ||
Schema.Type.ENUM to simpleTypeParsers.enumParser, | ||
Schema.Type.INT to simpleTypeParsers.intParser, | ||
Schema.Type.LONG to simpleTypeParsers.longParser, | ||
Schema.Type.FLOAT to simpleTypeParsers.floatParser, | ||
Schema.Type.DOUBLE to simpleTypeParsers.doubleParser, | ||
Schema.Type.BOOLEAN to simpleTypeParsers.booleanParser, | ||
Schema.Type.NULL to simpleTypeParsers.nullParser, | ||
) | ||
|
||
fun parseField(jsonValue: Any?, fieldSchema: Schema) = ( | ||
parsersLookup[fieldSchema.type] | ||
?: jsonFieldParser { _, _ -> JsonFieldParsingException("Null schema type").left() } | ||
).parse(jsonValue, fieldSchema) | ||
} |
20 changes: 20 additions & 0 deletions
20
src/main/kotlin/insulator/lib/jsonhelper/jsontoavro/Helpers.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package insulator.lib.jsonhelper.jsontoavro | ||
|
||
import arrow.core.Either | ||
import org.apache.avro.Schema | ||
|
||
fun <O> jsonFieldParser(parseFn: (fieldValue: Any?, schema: Schema) -> Either<JsonFieldParsingException, O>): JsonFieldParser<O> = object : JsonFieldParser<O> { | ||
override fun parse(fieldValue: Any?, schema: Schema) = parseFn(fieldValue, schema) | ||
} | ||
|
||
internal fun Schema.printType(): String { | ||
return when (this.type) { | ||
Schema.Type.NULL -> "null" | ||
Schema.Type.RECORD -> "record \"${this.toString(true)}\"" | ||
Schema.Type.BYTES -> "bytes (eg \"0x00\")" | ||
Schema.Type.ENUM -> "enum [${this.enumSymbols.joinToString(", ")}]" | ||
Schema.Type.UNION -> "union [${this.types.joinToString(", ") { it.toString(true) }}]" | ||
Schema.Type.ARRAY -> "array of \"${this.elementType.toString(true)}\"" | ||
else -> this.type.name.toLowerCase() | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
src/main/kotlin/insulator/lib/jsonhelper/jsontoavro/JsonToAvroConverter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package insulator.lib.jsonhelper.jsontoavro | ||
|
||
import arrow.core.Either | ||
import arrow.core.extensions.fx | ||
import arrow.core.left | ||
import arrow.core.right | ||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import insulator.lib.helpers.toEither | ||
import org.apache.avro.Schema | ||
import org.apache.avro.generic.GenericData | ||
import org.apache.avro.generic.GenericRecord | ||
|
||
class JsonToAvroConverter(private val objectMapper: ObjectMapper, private val fieldParser: FieldParser, private val genericData: GenericData) { | ||
fun parse(jsonString: String, schemaString: String) = Either.fx<JsonToAvroException, GenericRecord> { | ||
val jsonMap = !objectMapper.runCatching { readValue(jsonString, Map::class.java) }.toEither { JsonParsingException("Invalid json", it) } | ||
val schema = !Schema.Parser().runCatching { parse(schemaString) }.toEither { SchemaParsingException("Invalid AVRO schema", it) } | ||
val record = !fieldParser.parseField(jsonMap, schema).flatMap { | ||
(it as? GenericRecord)?.right() ?: JsonToAvroException("Invalid record").left() | ||
} | ||
!( | ||
if (genericData.validate(schema, record)) record.right() | ||
else JsonToAvroException("Unable to parse the json into a valid ${schema.name}. Final validation failed.").left() | ||
) | ||
} | ||
} | ||
|
||
interface JsonFieldParser<out O> { | ||
fun parse(fieldValue: Any?, schema: Schema): Either<JsonFieldParsingException, O> | ||
} | ||
|
||
open class JsonToAvroException(message: String? = null, cause: Throwable? = null) : Exception(message, cause) | ||
class SchemaParsingException(message: String?, cause: Throwable? = null) : JsonToAvroException(message, cause) | ||
class JsonParsingException(message: String?, cause: Throwable? = null) : JsonToAvroException(message, cause) | ||
|
||
open class JsonFieldParsingException(message: String?) : JsonToAvroException(message) | ||
class JsonInvalidFieldException(expectedSchema: Schema, fieldName: Any?) : JsonFieldParsingException("Invalid field \"$fieldName\". Expected ${expectedSchema.printType()}") | ||
class JsonMissingFieldException(expectedSchema: Schema, val fieldName: String? = null) : JsonFieldParsingException("Missing field \"$fieldName\". Expected ${expectedSchema.printType()}") |
20 changes: 20 additions & 0 deletions
20
src/main/kotlin/insulator/lib/jsonhelper/jsontoavro/fieldparser/ArrayParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package insulator.lib.jsonhelper.jsontoavro.fieldparser | ||
|
||
import arrow.core.Either | ||
import arrow.core.left | ||
import arrow.core.right | ||
import insulator.lib.helpers.toEitherOfList | ||
import insulator.lib.jsonhelper.jsontoavro.FieldParser | ||
import insulator.lib.jsonhelper.jsontoavro.JsonFieldParser | ||
import insulator.lib.jsonhelper.jsontoavro.JsonFieldParsingException | ||
import insulator.lib.jsonhelper.jsontoavro.JsonInvalidFieldException | ||
import org.apache.avro.Schema | ||
|
||
class ArrayParser(private val fieldParser: FieldParser) : JsonFieldParser<List<Any?>> { | ||
override fun parse(fieldValue: Any?, schema: Schema): Either<JsonFieldParsingException, List<Any?>> { | ||
if (fieldValue !is ArrayList<*>) return JsonInvalidFieldException(schema, fieldValue).left() | ||
if (fieldValue.size == 0) return emptyList<Any?>().right() | ||
// field value is a non-empty list | ||
return fieldValue.map { fieldParser.parseField(it, schema.elementType) }.toEitherOfList() | ||
} | ||
} |
Oops, something went wrong.