java成员方法tostring,生成toString方法以包括基类的成员吗?

I am trying to build a DTO (data-transfer-object) classes in Kotlin to be called from a Java application. Given following code:

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();

}

}

}

This displays:

toString: dobj2=DataObject(name=MyName)

getters: dobj2.name=MyName dobj2.id=12

I would like to include the id field form the BaseDto in the DataObject.toString call. One option is to override the toString with ToStringBuilder.reflectionToString in DataObject.toSting, but it would have to be added to every object derived from BaseDto. Is there a way to declare a data object hierarchy that automatically includes members from base classes. This is doable in java by overriding toString() in the base and using the ToStringBuilder.reflectionToString, in Kotlin the base toString is not called since data object generates its own version of toString which does not call super.

解决方案

Override toString in BaseDto with a reflection call like the following (credit to @junique for the reflectionToString() code example)...

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()

var clazz: Class? = 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(", ")}]"

}

}

EDIT

I tested this by creating a regular class instead of a data class. It doesn't work for a data class. Prior to 1.1., data classes could not even extend other classes (but they could implement interfaces). More and more, I am agreeing with the OP.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值