-
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.
Merge pull request #18 from findify/feature/type-mappers
type mapper support
- Loading branch information
Showing
13 changed files
with
358 additions
and
11 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
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
8 changes: 8 additions & 0 deletions
8
src/main/scala/io/findify/flinkadt/api/mapper/BigDecMapper.scala
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,8 @@ | ||
package io.findify.flinkadt.api.mapper | ||
|
||
import io.findify.flinkadt.api.serializer.MappedSerializer.TypeMapper | ||
|
||
class BigDecMapper extends TypeMapper[scala.BigDecimal, java.math.BigDecimal] { | ||
override def map(a: BigDecimal): java.math.BigDecimal = a.bigDecimal | ||
override def contramap(b: java.math.BigDecimal): BigDecimal = BigDecimal(b) | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/scala/io/findify/flinkadt/api/mapper/BigIntMapper.scala
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,10 @@ | ||
package io.findify.flinkadt.api.mapper | ||
|
||
import io.findify.flinkadt.api.serializer.MappedSerializer.TypeMapper | ||
|
||
import java.math.BigInteger | ||
|
||
class BigIntMapper() extends TypeMapper[scala.BigInt, java.math.BigInteger] { | ||
override def contramap(b: BigInteger): BigInt = BigInt(b) | ||
override def map(a: BigInt): BigInteger = a.bigInteger | ||
} |
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
72 changes: 72 additions & 0 deletions
72
src/main/scala/io/findify/flinkadt/api/serializer/MappedSerializer.scala
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,72 @@ | ||
package io.findify.flinkadt.api.serializer | ||
|
||
import io.findify.flinkadt.api.serializer.MappedSerializer.{MappedSerializerSnapshot, TypeMapper} | ||
import org.apache.flink.api.common.typeinfo.TypeInformation | ||
import org.apache.flink.api.common.typeutils.{ | ||
CompositeTypeSerializerSnapshot, | ||
GenericTypeSerializerSnapshot, | ||
SimpleTypeSerializerSnapshot, | ||
TypeSerializer, | ||
TypeSerializerSchemaCompatibility, | ||
TypeSerializerSnapshot | ||
} | ||
import org.apache.flink.core.memory.{DataInputView, DataOutputView} | ||
import org.apache.flink.util.InstantiationUtil | ||
|
||
case class MappedSerializer[A, B](mapper: TypeMapper[A, B], ser: TypeSerializer[B]) extends SimpleSerializer[A] { | ||
override def equals(obj: Any): Boolean = ser.equals(obj) | ||
|
||
override def toString: String = ser.toString | ||
|
||
override def hashCode(): Int = ser.hashCode() | ||
override def getLength: Int = ser.getLength | ||
|
||
override def serialize(record: A, target: DataOutputView): Unit = { | ||
ser.serialize(mapper.map(record), target) | ||
} | ||
|
||
override def deserialize(reuse: A, source: DataInputView): A = { | ||
mapper.contramap(ser.deserialize(mapper.map(reuse), source)) | ||
} | ||
|
||
override def deserialize(source: DataInputView): A = mapper.contramap(ser.deserialize(source)) | ||
|
||
override def snapshotConfiguration(): TypeSerializerSnapshot[A] = new MappedSerializerSnapshot[A, B](mapper, ser) | ||
|
||
override def createInstance(): A = mapper.contramap(ser.createInstance()) | ||
} | ||
|
||
object MappedSerializer { | ||
trait TypeMapper[A, B] { | ||
def map(a: A): B | ||
def contramap(b: B): A | ||
} | ||
class MappedSerializerSnapshot[A, B]() extends TypeSerializerSnapshot[A] { | ||
var mapper: TypeMapper[A, B] = _ | ||
var ser: TypeSerializer[B] = _ | ||
def this(xmapper: TypeMapper[A, B], xser: TypeSerializer[B]) = { | ||
this() | ||
mapper = xmapper | ||
ser = xser | ||
} | ||
|
||
override def readSnapshot(readVersion: Int, in: DataInputView, userCodeClassLoader: ClassLoader): Unit = { | ||
val mapperClazz = InstantiationUtil.resolveClassByName[TypeMapper[A, B]](in, userCodeClassLoader) | ||
mapper = InstantiationUtil.instantiate(mapperClazz) | ||
val serClazz = InstantiationUtil.resolveClassByName(in, userCodeClassLoader) | ||
ser = InstantiationUtil.instantiate(serClazz) | ||
} | ||
|
||
override def resolveSchemaCompatibility(newSerializer: TypeSerializer[A]): TypeSerializerSchemaCompatibility[A] = | ||
TypeSerializerSchemaCompatibility.compatibleAsIs() | ||
|
||
override def writeSnapshot(out: DataOutputView): Unit = { | ||
out.writeUTF(mapper.getClass.getName) | ||
out.writeUTF(ser.getClass.getName) | ||
} | ||
|
||
override def restoreSerializer(): TypeSerializer[A] = new MappedSerializer[A, B](mapper, ser) | ||
|
||
override def getCurrentVersion: Int = 1 | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
src/main/scala/io/findify/flinkadt/api/serializer/UnitSerializer.scala
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,30 @@ | ||
package io.findify.flinkadt.api.serializer | ||
|
||
import io.findify.flinkadt.api.serializer.UnitSerializer.UnitSerializerSnapshot | ||
import org.apache.flink.api.common.typeutils.{SimpleTypeSerializerSnapshot, TypeSerializer, TypeSerializerSnapshot} | ||
import org.apache.flink.core.memory.{DataInputView, DataOutputView} | ||
|
||
import java.util.function.Supplier | ||
|
||
class UnitSerializer extends SimpleSerializer[Unit] { | ||
override def getLength: Int = 0 | ||
|
||
override def serialize(record: Unit, target: DataOutputView): Unit = {} | ||
|
||
override def deserialize(reuse: Unit, source: DataInputView): Unit = {} | ||
|
||
override def deserialize(source: DataInputView): Unit = {} | ||
|
||
override def snapshotConfiguration(): TypeSerializerSnapshot[Unit] = new UnitSerializerSnapshot() | ||
|
||
override def createInstance(): Unit = {} | ||
} | ||
|
||
object UnitSerializer { | ||
class UnitSerializerSnapshot | ||
extends SimpleTypeSerializerSnapshot[Unit]( | ||
new Supplier[TypeSerializer[Unit]] { | ||
override def get(): TypeSerializer[Unit] = new UnitSerializer | ||
} | ||
) | ||
} |
36 changes: 36 additions & 0 deletions
36
src/main/scala/io/findify/flinkadt/api/typeinfo/MappedTypeInformation.scala
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,36 @@ | ||
package io.findify.flinkadt.api.typeinfo | ||
|
||
import io.findify.flinkadt.api.serializer.MappedSerializer | ||
import io.findify.flinkadt.api.serializer.MappedSerializer.TypeMapper | ||
import org.apache.flink.api.common.ExecutionConfig | ||
import org.apache.flink.api.common.typeinfo.TypeInformation | ||
import org.apache.flink.api.common.typeutils.TypeSerializer | ||
|
||
import scala.reflect.{ClassTag, classTag} | ||
|
||
case class MappedTypeInformation[A: ClassTag, B](mapper: TypeMapper[A, B], nested: TypeInformation[B]) | ||
extends TypeInformation[A] { | ||
override def createSerializer(config: ExecutionConfig): TypeSerializer[A] = | ||
new MappedSerializer(mapper, nested.createSerializer(config)) | ||
override def isKeyType: Boolean = nested.isKeyType | ||
override def getTotalFields: Int = nested.getTotalFields | ||
override def isTupleType: Boolean = nested.isTupleType | ||
|
||
override def canEqual(obj: Any): Boolean = obj match { | ||
case m: MappedTypeInformation[_, _] => true | ||
case _ => false | ||
} | ||
override def getTypeClass: Class[A] = classTag[A].runtimeClass.asInstanceOf[Class[A]] | ||
override def getArity: Int = nested.getArity | ||
override def isBasicType: Boolean = nested.isBasicType | ||
|
||
override def toString: String = nested.toString | ||
|
||
override def equals(obj: Any): Boolean = obj match { | ||
case m: MappedTypeInformation[_, _] => (m.nested == nested) && m.mapper.equals(mapper) | ||
case _ => false | ||
} | ||
|
||
override def hashCode(): Int = nested.hashCode() | ||
|
||
} |
26 changes: 26 additions & 0 deletions
26
src/main/scala/io/findify/flinkadt/api/typeinfo/UnitTypeInformation.scala
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,26 @@ | ||
package io.findify.flinkadt.api.typeinfo | ||
|
||
import io.findify.flinkadt.api.serializer.UnitSerializer | ||
import org.apache.flink.api.common.ExecutionConfig | ||
import org.apache.flink.api.common.typeinfo.TypeInformation | ||
import org.apache.flink.api.common.typeutils.TypeSerializer | ||
|
||
class UnitTypeInformation extends TypeInformation[Unit] { | ||
override def createSerializer(config: ExecutionConfig): TypeSerializer[Unit] = new UnitSerializer() | ||
override def isKeyType: Boolean = true | ||
override def getTotalFields: Int = 0 | ||
override def isTupleType: Boolean = false | ||
override def canEqual(obj: Any): Boolean = obj.isInstanceOf[Unit] | ||
override def getTypeClass: Class[Unit] = classOf[Unit] | ||
override def getArity: Int = 0 | ||
override def isBasicType: Boolean = false | ||
|
||
override def toString: String = "{}" | ||
|
||
override def equals(obj: Any): Boolean = obj match { | ||
case _: Unit => true | ||
case _ => false | ||
} | ||
|
||
override def hashCode(): Int = ().hashCode() | ||
} |
43 changes: 43 additions & 0 deletions
43
src/test/scala/io/findify/flinkadt/MappedTypeInfoTest.scala
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,43 @@ | ||
package io.findify.flinkadt | ||
|
||
import io.findify.flinkadt.MappedTypeInfoTest.WrappedString | ||
import org.scalatest.flatspec.AnyFlatSpec | ||
import org.scalatest.matchers.should.Matchers | ||
import io.findify.flinkadt.api._ | ||
import io.findify.flinkadt.api.serializer.MappedSerializer.TypeMapper | ||
import org.apache.flink.api.common.typeinfo.TypeInformation | ||
|
||
import scala.reflect.ClassTag | ||
|
||
class MappedTypeInfoTest extends AnyFlatSpec with Matchers with TestUtils { | ||
import MappedTypeInfoTest._ | ||
it should "derive TI for non-serializeable classes" in { | ||
drop(implicitly[TypeInformation[WrappedString]]) | ||
} | ||
} | ||
|
||
object MappedTypeInfoTest { | ||
class WrappedMapper extends TypeMapper[WrappedString, String] { | ||
override def map(a: WrappedString): String = a.get | ||
|
||
override def contramap(b: String): WrappedString = { | ||
val str = new WrappedString | ||
str.put(b) | ||
str | ||
} | ||
} | ||
implicit val mapper: TypeMapper[WrappedString, String] = new WrappedMapper() | ||
|
||
class WrappedString { | ||
private var internal: String = "" | ||
|
||
override def equals(obj: Any): Boolean = obj match { | ||
case s: WrappedString => s.get == internal | ||
case _ => false | ||
} | ||
def get: String = internal | ||
def put(value: String) = { | ||
internal = value | ||
} | ||
} | ||
} |
Oops, something went wrong.