如何在 java 项目中查找哪些数据 class 未覆盖 toString() 方法
How to find which data class not overriden toString() method in java project
在我们的项目中,某些数据 classes (POJO used for API Request & Response)
覆盖 toString()
方法以提供有意义的信息 - 但某些数据 classes 未 覆盖toString()
.
当应用程序打印数据 class 的 logs
时,其中 toString()
未被覆盖,它们没有打印有意义的信息,它们只是调用对象 class toString()
.
所以我们要识别那些数据 class 并提供 toString()
implementation
.
有什么方法可以识别 class 其中 toString()
方法不是 implemented
.
查看每个数据 class 并检查 toString()
方法是一项乏味且耗时的任务。
有没有更好的方法可以使用一些工具(如 eclipse 或其他工具)来做到这一点?
使用反射。在我的项目中,我为每个域对象编写测试。测试检查 toString
方法是来自 Object
class 还是来自我的 class。该测试的代码
/**
* Passes if class has overridden toString method. Fails otherwise.
*/
public static void toStringTest(Object o) throws NoSuchMethodException {
Class<?> clazz = o.getClass().getMethod("toString").getDeclaringClass();
assertThat(clazz).isNotEqualTo(Object.class)
.withFailMessage("expecting method toString to be defined in actual class");
assertThat(o.toString()).isNotEmpty();
}
然后有 class SomeClass
,在 SomeClassTest
我按如下方式调用它
public void shouldOverrideToString() throws NoSuchMethodException {
TestUtils.toStringTest(new SomeClassTest());
}
如果您想识别所有未覆盖 toString 的 classes,您可以编写工具来扫描 classpath 并为每个 class(来自您的包裹)。但这种方法有局限性。并非所有 classes 都需要 toString。服务 classes、REST 控制器等不需要 toString。所以自动化会给你很多误报。您可以仅扫描带有模型 classes 的包(如果您将模型保存在单独的包中)或使用自定义注释对模型 classes 进行注释(然后仅扫描带注释的 classes),但我认为这样的解决方案不值得付出努力。
最后,你可以使用https://projectlombok.org/ https://immutables.github.io/ or https://github.com/google/auto/tree/master/value
这些库使用代码 generation/anotation 处理来自动生成 equals/hashcode/toString。我使用 Immutables,它工作得很好。甚至将遗留数据模型迁移到 Immutables 也很简单。
在我的项目中,我为每个域对象编写了这样的测试。
当 class 未覆盖 toString()
- 它必须使用默认实现,其中 包含 class 名称。因此:检查您的日志并向后工作!
或者,您可以使用反射:
- 启动一个 JVM 运行,它包含 所有 你的 classes 在 classpath
- 扫描所有你的 class的class路径(或者如果可能的话:那些类似于你的 POJO)
- 检查每个 class 是否实现了
toString()
显然这需要大量工作 - 但没有技术原因说明为什么这不可行。当然,您的主要问题可能是减少要查看的 classes 的数量 - 包含 500 classes 的列表也不会太有帮助。
还有一个(可能的)选项:创建一个使用 反射 来实现 toString() 和 equals()/hashCode() 的 PojoBase class - 以及然后只需确保所有 POJO classes 扩展该基 class。 (免责声明:当然,您必须了解这样做的后果。但我们最近创建了这样一个 BaseBean
,它使用 Apache Commons EqualsBuilder,...以这种方式调用)
一种方法是使用 Reflections Library 获取给定包中的所有 classes,请注意,这不适用于 classes,如匿名、私有、部分、不可访问, ..等,所以最好的方法是根据 @GhostCat answer
手动完成
现在你应该走这条路,这是如何完成的,首先通过 Reflections Library 获得 classes,引用自 this answer by @Staale
Reflections reflections = new Reflections("my.project.prefix");
Set<Class<? extends Object>> allClasses =
reflections.getSubTypesOf(Object.class);
然后遍历 classes,并检查 toString 是否在 class 自身中声明
for(Class clazz : allClasses)
{
if(!clazz.getMethod("toString").getDeclaringClass().getName().equals(clazz.getName()))
System.out.println("toString not overridden in class "+clazz.getName());
}
如果您的数据 class 具有共同的抽象 class 它们从中继承,那么这个想法就可行。
在你的super中引入一个摘要toString()
class:
public abstract String toString();
这将强制所有子classes 覆盖它,如果他们不这样做,您将得到编译错误。
遗憾的是,这种方法有一个主要的限制。如果你有这样的事情:
abstract class A {
public abstract String toString();
}
class B extends A {
public String toString() {
return "foo";
}
}
class C extends B {
}
它不会注意到 C
中缺少的 toString()
。
这种方法可能不适合你,但我想我还是会 post,所以也许它会对阅读你的问题的其他人有所帮助。
实际上应该很简单,只要检查你是否可以通过 .getDeclaredMethod("toString")
检索 toString 方法,如果这个语句触发 java.lang.NoSuchMethodException
,那么它不会在你的焦点 class 中声明.
在我们的项目中,某些数据 classes (POJO used for API Request & Response)
覆盖 toString()
方法以提供有意义的信息 - 但某些数据 classes 未 覆盖toString()
.
当应用程序打印数据 class 的 logs
时,其中 toString()
未被覆盖,它们没有打印有意义的信息,它们只是调用对象 class toString()
.
所以我们要识别那些数据 class 并提供 toString()
implementation
.
有什么方法可以识别 class 其中 toString()
方法不是 implemented
.
查看每个数据 class 并检查 toString()
方法是一项乏味且耗时的任务。
有没有更好的方法可以使用一些工具(如 eclipse 或其他工具)来做到这一点?
使用反射。在我的项目中,我为每个域对象编写测试。测试检查 toString
方法是来自 Object
class 还是来自我的 class。该测试的代码
/**
* Passes if class has overridden toString method. Fails otherwise.
*/
public static void toStringTest(Object o) throws NoSuchMethodException {
Class<?> clazz = o.getClass().getMethod("toString").getDeclaringClass();
assertThat(clazz).isNotEqualTo(Object.class)
.withFailMessage("expecting method toString to be defined in actual class");
assertThat(o.toString()).isNotEmpty();
}
然后有 class SomeClass
,在 SomeClassTest
我按如下方式调用它
public void shouldOverrideToString() throws NoSuchMethodException {
TestUtils.toStringTest(new SomeClassTest());
}
如果您想识别所有未覆盖 toString 的 classes,您可以编写工具来扫描 classpath 并为每个 class(来自您的包裹)。但这种方法有局限性。并非所有 classes 都需要 toString。服务 classes、REST 控制器等不需要 toString。所以自动化会给你很多误报。您可以仅扫描带有模型 classes 的包(如果您将模型保存在单独的包中)或使用自定义注释对模型 classes 进行注释(然后仅扫描带注释的 classes),但我认为这样的解决方案不值得付出努力。
最后,你可以使用https://projectlombok.org/ https://immutables.github.io/ or https://github.com/google/auto/tree/master/value 这些库使用代码 generation/anotation 处理来自动生成 equals/hashcode/toString。我使用 Immutables,它工作得很好。甚至将遗留数据模型迁移到 Immutables 也很简单。
在我的项目中,我为每个域对象编写了这样的测试。
当 class 未覆盖 toString()
- 它必须使用默认实现,其中 包含 class 名称。因此:检查您的日志并向后工作!
或者,您可以使用反射:
- 启动一个 JVM 运行,它包含 所有 你的 classes 在 classpath
- 扫描所有你的 class的class路径(或者如果可能的话:那些类似于你的 POJO)
- 检查每个 class 是否实现了
toString()
显然这需要大量工作 - 但没有技术原因说明为什么这不可行。当然,您的主要问题可能是减少要查看的 classes 的数量 - 包含 500 classes 的列表也不会太有帮助。
还有一个(可能的)选项:创建一个使用 反射 来实现 toString() 和 equals()/hashCode() 的 PojoBase class - 以及然后只需确保所有 POJO classes 扩展该基 class。 (免责声明:当然,您必须了解这样做的后果。但我们最近创建了这样一个 BaseBean
,它使用 Apache Commons EqualsBuilder,...以这种方式调用)
一种方法是使用 Reflections Library 获取给定包中的所有 classes,请注意,这不适用于 classes,如匿名、私有、部分、不可访问, ..等,所以最好的方法是根据 @GhostCat answer
手动完成现在你应该走这条路,这是如何完成的,首先通过 Reflections Library 获得 classes,引用自 this answer by @Staale
Reflections reflections = new Reflections("my.project.prefix"); Set<Class<? extends Object>> allClasses = reflections.getSubTypesOf(Object.class);
然后遍历 classes,并检查 toString 是否在 class 自身中声明
for(Class clazz : allClasses)
{
if(!clazz.getMethod("toString").getDeclaringClass().getName().equals(clazz.getName()))
System.out.println("toString not overridden in class "+clazz.getName());
}
如果您的数据 class 具有共同的抽象 class 它们从中继承,那么这个想法就可行。
在你的super中引入一个摘要toString()
class:
public abstract String toString();
这将强制所有子classes 覆盖它,如果他们不这样做,您将得到编译错误。
遗憾的是,这种方法有一个主要的限制。如果你有这样的事情:
abstract class A {
public abstract String toString();
}
class B extends A {
public String toString() {
return "foo";
}
}
class C extends B {
}
它不会注意到 C
中缺少的 toString()
。
这种方法可能不适合你,但我想我还是会 post,所以也许它会对阅读你的问题的其他人有所帮助。
实际上应该很简单,只要检查你是否可以通过 .getDeclaredMethod("toString")
检索 toString 方法,如果这个语句触发 java.lang.NoSuchMethodException
,那么它不会在你的焦点 class 中声明.