valid-pojo

ttvkxqim  于 2021-06-21  发布在  Flink
关注(0)|答案(1)|浏览(381)

我正在用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邮件列表,没有发现类似的问题。

ldioqlga

ldioqlga1#

我发现至少有两个pojo规则与提供的数据类冲突。
1) 类有一个公共的无参数构造函数
默认情况下,kotlin不会为具有默认参数值的函数生成重载(https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#overloads-(代)
因此,编译后的类将只有一个具有两个参数构造函数的构造函数,并且不会创建任何参数构造函数。要强制kotlin编译器生成多个重载,应该使用 @JvmOverloads 注解。在您的情况下,它将用于构造函数,所以我们还需要添加 constructor 关键字:

data class SomeDataClass @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-字段)
所以最终的代码应该是这样的:

data class SomeDataClass @JvmOverloads constructor(
    var topic: String = "",
    var message: String = ""
)

相关问题