dec*_*ctl 5 kotlin apache-flink
我正在用 Kotlin 编写 Flink 应用程序,并且数据类(以及其他 Kotlin 类)未被识别为有效的 POJO 类型。
Flink 文档指出,如果满足以下条件,则数据类型被识别为 POJO 类型(并允许“按名称”字段引用):
我在实现 Kotlin 数据类时收到以下信息,该数据类应满足上述条件才能被识别为 POJO:
[main] INFO org.apache.flink.api.java.typeutils.TypeExtractor -
Class class <Class> cannot be used as a POJO type because not all
fields are valid POJO fields, and must be processed as GenericType.
Please read the Flink documentation on "Data Types & Serialization"
for details of the effect on performance.
Run Code Online (Sandbox Code Playgroud)
进一步调查,我回顾了Flink的TypeExtractor.isValidPojoField方法@ https://github.com/apache/flink/blob/master/flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor .java
在一个单独的项目中,我在一个简单的 Kotlin 数据类上应用了 java.lang.reflect.Modifier 的字段检查,试图缩小问题范围。
data class SomeDataClass(
val topic: String = "",
val message: String = ""
)
Run Code Online (Sandbox Code Playgroud)
虽然 Kotlin 类字段默认具有公共可见性,但 Modifier.isPublic 将这些字段识别为私有字段。此外,Modifier.isFinal 将这些字段识别为最终字段。
val clazz = SomeDataClass::class.java
val fields = clazz.declaredFields
fields.forEach { it ->
println("field: $it")
println(it.genericType)
println("public? " + Modifier.isPublic(it.modifiers))
println("final? " + Modifier.isFinal(it.modifiers))
println("transient? " + Modifier.isTransient(it.modifiers))
println("static? " + Modifier.isStatic(it.modifiers))
}
>
field: private final java.lang.String SomeDataClass.topic
class java.lang.String
public? false
final? true
transient? false
static? false
Run Code Online (Sandbox Code Playgroud)
但是,为这些字段创建了公共 getter 和 setter 方法,因此该对象仍应满足 POJO 标准。
println(clazz.declaredMethods.toList())
>
[public boolean SomeDataClass.equals(java.lang.Object),
public java.lang.String SomeDataClass.toString(),
public int SomeDataClass.hashCode(),
**public final java.lang.String SomeDataClass.getMessage(),**
public final SomeDataClass SomeDataClass.copy(java.lang.String,java.lang.String),
**public final java.lang.String SomeDataClass.getTopic(),**
public final java.lang.String SomeDataClass.component1(),
public final java.lang.String SomeDataClass.component2(),
public static SomeDataClass SomeDataClass.copy$default(SomeDataClass,java.lang.String,java.lang.String,int,java.lang.Object)]
Run Code Online (Sandbox Code Playgroud)
然而,getter 和 setter 方法是最终的,这让我相信这就是问题所在。
我对 JVM 开发比较陌生,因此我们将不胜感激。我查看了 Flink Jira、Stack Overflow 和 Flink 邮件列表,没有发现类似的问题报告。
我发现所提供的数据类至少有两个违反 POJO 规则的情况。
1) 该类有一个公共的无参构造函数
默认情况下,Kotlin 不会为具有默认参数值的函数生成重载 ( https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#overloads- Generation )
所以你编译的类将只有一个带有两参数构造函数的构造函数,并且不会创建无参构造函数。要强制 Kotlin 编译器生成多个重载,应该使用@JvmOverloads注释。在您的情况下,它将在构造函数中使用,因此我们还需要添加 constructor 关键字:
data class SomeDataClass @JvmOverloads constructor
Run Code Online (Sandbox Code Playgroud)
2) 类中的所有非静态、非瞬态字段要么是公共的(且非最终的),要么具有遵循 Java bean 命名约定的公共 getter 和 setter 方法。
由于您使用的是val关键字,生成的字段将为final,并且不会为它们生成任何设置器。因此,您可以将vals 更改为vars,字段将不再存在final,并且也会生成正确的 getter 和 setter。(或者您可以使用另一个注释来防止生成 getter 和 setter 并公开一个字段,因为它是https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields)
所以最终的代码应该是这样的:
data class SomeDataClass @JvmOverloads constructor(
var topic: String = "",
var message: String = ""
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2047 次 |
| 最近记录: |