【问题标题】:How to find which data class not overriden toString() method in java projectjava - 如何在java项目中查找未覆盖toString()方法的数据类
【发布时间】:2017-07-26 06:25:30
【问题描述】:

在我们的项目中,某些数据类 (POJO used for API Request & Response) 覆盖 toString() 方法以提供有意义的信息 - 但某些数据类没有覆盖 toString()

当应用程序打印toString() 未被覆盖的数据类的logs 时,它们不会打印有意义的信息,它们只是调用对象类toString()

所以我们要识别那些数据类并提供toString()implementation

有什么方法可以识别出toString() 方法不是implemented 的类。

查看每个数据类并检查toString() 方法是一项乏味且耗时的任务。

有没有更好的方法可以使用 eclipse 之类的工具或其他工具来做到这一点?

【问题讨论】:

    标签: java eclipse tostring


    【解决方案1】:

    当类没有覆盖toString() - 它必须使用默认实现,其中包含类名。因此:检查您的日志并向后工作!

    或者,您可以使用反射:

    • 启动 JVM 运行,其中包含 所有类路径中的类
    • 扫描所有你的类的类路径(或者如果可能的话:那些类似于你的POJO的类)
    • 检查每个类是否实现toString()

    显然,这是一项繁重的工作 - 但没有技术上的理由不能解决这个问题。当然,您这里的主要问题可能是减少要查看的类的数量 - 包含 500 个类的列表也不会有太大帮助。

    还有另一个(潜在的)选项:创建一个使用 reflection 来实现 toString() 和可能 equals()/hashCode() 的 PojoBase 类 - 然后只需确保所有 POJO 类都扩展那个基类。 (免责声明:您当然必须了解这样做的后果。但我们最近创建了这样一个使用 Apache Commons EqualsBuilder 的BaseBean,......这样调用)

    【讨论】:

      【解决方案2】:

      一种方法是使用Reflections Library 获取给定包中的所有类,请注意这不适用于匿名、私有、部分、不可访问等类,因此最好的方法是手动进行根据 @GhostCat 回答

      现在如果你走这条路,可以这样做,首先通过反射库获取类,引用自this answer by @Staale

      Reflections reflections = new Reflections("my.project.prefix");
      
      Set<Class<? extends Object>> allClasses =
                  reflections.getSubTypesOf(Object.class);
      

      然后遍历类,检查类本身是否声明了toString

      for(Class clazz : allClasses)
      {
          if(!clazz.getMethod("toString").getDeclaringClass().getName().equals(clazz.getName()))
              System.out.println("toString not overridden in class "+clazz.getName());
      }
      

      【讨论】:

      • 上述方法适用于我,因为没有匿名类。
      【解决方案3】:

      如果您的数据类具有它们继承自的公共抽象类,则此想法可行。

      在您的超类中引入抽象 toString()

      public abstract String toString();
      

      这将强制所有子类覆盖它,如果不这样做,您将收到编译错误。

      遗憾的是,这种方法有一个主要限制。如果你有这样的事情:

      abstract class A {
          public abstract String toString();
      }
      
      class B extends A {
          public String toString() {
              return "foo";
          }
      }
      
      class C extends B {
      }
      

      它不会注意到C 中缺少的toString()

      这种方法可能不适合你,但我想我还是会发布它,所以也许它会帮助其他阅读你问题的人。

      【讨论】:

        【解决方案4】:

        使用反射。在我的项目中,我为每个域对象编写测试。测试检查 toString 方法是来自 Object 班级还是来自我的班级。该测试的代码

        /**
             * 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();
            }
        

        然后有类SomeClass,在SomeClassTest我调用它如下

           public void shouldOverrideToString() throws NoSuchMethodException {
                TestUtils.toStringTest(new SomeClassTest());
            }
        

        如果您想识别所有不覆盖 toString 的类,您可以编写工具来扫描类路径并为每个类(从您的包中)调用此类测试。但这种方法有局限性。并非所有类都需要 toString。服务类、REST 控制器等不需要 toString。所以自动化会给你很多误报。您可以只扫描带有模型类的包(如果您将模型保存在单独的包中)或使用自定义注释对模型类进行注释(然后只扫描带注释的类),但我认为这样的解决方案不值得。

        最后,您可以使用https://projectlombok.org/ https://immutables.github.io/https://github.com/google/auto/tree/master/value 这些库使用代码生成/注释处理来自动生成equals/hashcode/toString。我使用 Immutables 并且效果很好。甚至将遗留数据模型迁移到 Immutables 也很简单。

        在我的项目中,我为每个域对象编写了这样的测试。

        【讨论】:

        • new SomeClassTest():这意味着该类必须是已知的。 OP 明确表示他想快速识别那些不覆盖toString 方法的类。
        【解决方案5】:

        其实应该很简单,只要看看你能不能通过.getDeclaredMethod("toString")检索到toString方法,如果这个语句触发了java.lang.NoSuchMethodException,那么你的focused类中没有声明它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-01-10
          • 1970-01-01
          • 2013-08-10
          • 1970-01-01
          • 1970-01-01
          • 2013-09-27
          • 2012-05-30
          相关资源
          最近更新 更多