我正在尝试在Kotlin中构建一个DTO(数据传输对象)类,以便从Java应用程序中调用它。给出以下代码:
BaseDto.kt
package sandbox.KotlinDataObjects
import org.apache.commons.lang3.builder.ToStringBuilder
import java.sql.ResultSet
import java.sql.SQLException
/**
* Base DTO
* (JSON/XML serialization code removed for clarity)
*/
abstract class BaseDto(
var id: Long = 0
) {
@Throws(SQLException::class)
open protected fun fromResultSet(rs: ResultSet) {
this.id = rs.getLong("id")
}
/**
* Override toString and use StringBuilder
* Since DataObject may be one of many objects based on BaseDto
* we want to avoid doing this in every data class
* Derived class seems to generate a toString and this never gets
* called, this is the issue I believe
*/
override fun toString(): String {
return ToStringBuilder.reflectionToString(this)
}
}
DataObject.kt
package sandbox.KotlinDataObjects
import org.apache.commons.lang3.builder.ToStringBuilder
import java.sql.ResultSet
data class DataObject(
var name: String = ""
) : BaseDto() {
override fun fromResultSet(rs: ResultSet) {
super.fromResultSet(rs)
name = rs.getString("name")
}
}
Main.java
package sandbox.KotlinDataObjects;
import org.mockito.Mockito;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Main {
/**
* Mock ResultSet for testing with columns we are requesting
* @return ResultSet
* @throws SQLException
*/
private static ResultSet getMockedResultSet() throws SQLException {
ResultSet mockedRs = Mockito.mock(ResultSet.class);
Mockito.when(mockedRs.getLong("id")).thenReturn(12L);
Mockito.when(mockedRs.getString("name")).thenReturn("MyName");
return mockedRs;
}
public static void main(String[] args) {
try (ResultSet mockedRs = getMockedResultSet()) {
// Read DataObject from ResultSet (mocked to avoid DB connection)
DataObject dobj = new DataObject();
dobj.fromResultSet(mockedRs);
System.out.println("toString: dobj="+dobj);
System.out.println("getters: dobj.name="+dobj.getName()+" dobj.id="+dobj.getId());
} catch (SQLException e) {
e.printStackTrace();
}
}
}
显示:
toString: dobj2=DataObject(name=MyName)
getters: dobj2.name=MyName dobj2.id=12
我想在DataObject.toString调用中包含BaseDto的 id 字段。一种选择是使用DataObject.toSting中的ToStringBuilder.reflectionToString覆盖toString,但必须将其添加到从BaseDto派生的每个对象中。有没有办法声明一个自动包含基类成员的数据对象层次结构。这在java中可以通过覆盖基类中的toString()并使用ToStringBuilder.reflectionToString来实现,在Kotlin中不会调用基础toString,因为数据对象生成自己的toString版本,而不调用super。
答案 0 :(得分:0)
使用以下反射调用覆盖toString
中的BaseDto
reflectionToString()
代码示例的credit to @junique ...
import kotlin.reflect.*
import kotlin.collections.*
import java.lang.reflect.Modifier
abstract class BaseDto(
var id: Long = 0L
) {
open protected fun fromResultSet(rs: ResultSet) {
this.id = rs.id
}
override open public fun toString() = reflectionToString(this)
fun reflectionToString(obj: Any?): String {
if(obj == null) {
return "null"
}
val s = mutableListOf<String>()
var clazz: Class<in Any>? = obj.javaClass
while (clazz != null) {
for (prop in clazz.declaredFields.filterNot { Modifier.isStatic(it.modifiers) }) {
prop.isAccessible = true
s += "${prop.name}=" + prop.get(obj)?.toString()?.trim()
}
clazz = clazz.superclass
}
return "${obj.javaClass.simpleName}=[${s.joinToString(", ")}]"
}
}
修改强>
我通过创建常规class
而不是data class
对此进行了测试。它不适用于data class
。在1.1。之前,data classes
甚至无法扩展其他类(但它们可以实现接口)。越来越多,我同意OP。