我正在用kotlin编写一个flink应用程序,数据类(以及其他kotlin类)没有被标识为有效的pojo类型。
flink文档说明,如果满足以下条件,则数据类型将被识别为pojo类型(并允许“按名称”字段引用):
这个类是公共的和独立的
类有一个公共的无参数构造函数
类中的所有非静态、非临时字段要么是公共的(非final),要么具有遵循javabean命名约定的公共getter和setter方法。
我在实现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.
进一步调查,我回顾了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 = ""
)
默认情况下,kotlin类字段具有公共可见性,而modifier.ispublic将字段识别为私有。此外,modifier.isfinal将字段识别为final。
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
但是,公共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)]
然而,getter和setter方法是最终的,这使我相信这就是问题所在。
我对jvm开发还比较陌生,所以非常感谢您的帮助。我已经查看了flink jira、stack overflow和flink邮件列表,没有发现类似的问题。
1条答案
按热度按时间ldioqlga1#
我发现至少有两个pojo规则与提供的数据类冲突。
1) 类有一个公共的无参数构造函数
默认情况下,kotlin不会为具有默认参数值的函数生成重载(https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#overloads-(代)
因此,编译后的类将只有一个具有两个参数构造函数的构造函数,并且不会创建任何参数构造函数。要强制kotlin编译器生成多个重载,应该使用
@JvmOverloads
注解。在您的情况下,它将用于构造函数,所以我们还需要添加constructor
关键字:2) 类中的所有非静态、非临时字段要么是公共的(非final),要么具有遵循javabean命名约定的公共getter和setter方法。
既然你用的是
val
关键字生成的字段将final
,并且不会为它们生成setter。所以你可以改变val
s到var
而田野将不再是final
也会产生合适的getter和setter(或者可以使用另一个注解来防止生成getter和setter,并按原样公开字段https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-字段)所以最终的代码应该是这样的: