生成toString方法以包含基类中的成员?

时间:2017-07-26 17:36:47

标签: java oop kotlin

我正在尝试在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。

1 个答案:

答案 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。