如何生成源代码来创建我正在调试的对象?

我的典型场景:

  1. 我处理的遗留代码有一个只有生产中的客户端才有的错误
  2. 我附加了一个调试器,并找出如何在给定输入的情况下在系统上重现该问题。 但是,我不知道为什么错误发生了。
  3. 现在我想在我的本地系统上编写一个自动化测试来尝试重现然后修复bug

最后一步真的很难。 输入可能非常复杂并且有大量数据。 手动创建输入(例如: P p = new P(); p.setX("x"); p.setY("x");想象这样做1000次以创建对象)非常繁琐且容易出错。 事实上你可能会注意到我刚给出的例子中有一个拼写错误。

是否有一种自动方式从调试器中的断点处获取字段并生成将创建该对象的源代码,以相同的方式填充?

我唯一想到的就是序列化这个输入(例如使用Xstream)。 我可以将其保存到文件中并在自动测试中将其读回。 这有一个主要问题:如果类以某种方式发生变化(例如:重命名了字段/ getter / setter名称),我将无法再反序列化该对象。 换句话说,测试非常脆弱。

众所周知,Java标准序列化在对象更改其版本(内容,字段命名)时不是非常有用。 它适用于快速演示项目。

objetcs支持您自己的(二进制)自定义序列化的方法更适合您的需求:
这并不难,使用DataOutputStream写出对象的所有字段。 但是现在通过首先写出一个versionId介绍versiong。 只有一个版本的对象,写出versionId 1.这样你以后可以在objetcs中引入更改,删除字段,添加字段,提高版本号。

然后,这样的ICustomSerializable将首先在readObject()方法中从输入流中读出版本号,并且取决于版本Id调用readVersionV1()或例如readVersionV2().

 public Interface ICustomSerializable { void writeObject(DataOutputStream dos); Object readObject(DataInputStream dis); } public Class Foo { public static final VERSION_V1 = 1; public static final VERSION_V2 = 2; public static final CURRENT_VERSION = VERSION_V2; private int version; private int fooNumber; private double fooDouble; public void writeObject(DataOutputStream dos) { dos.writeInt(this.version); if (version == VERSION_V1) { writeVersionV1(dos); } else (version == VERSION_V2) { writeVersionV2(dos); } else { throw new IllegalFormatException("unkown version: " + this.version); } } public void writeVersionV1(DataOutputStream dos) { writeInt(this.fooNumber); writeDouble(this.fooValue); } } 

需要进一步的getter和setter,以及将版本初始化为CURRENT_VERSION的构造函数。

如果您更改或添加适当的读写版本,这种序列化可以安全地重构。 对于使用来自外部库而不是您的控件的类的复杂对象,它可以更多工作,但字符串,列表很容易序列化。

我想你想要做的是存储“状态”,然后在测试中恢复它以确保错误保持不变。

简短回答:没有这样的通用代码生成工具,但只要保留了几个约束,编写这样的工具就是小工作。

长评:有些限制可以发挥作用。 如果一切都只是带有getter和setter的bean,那么你需要的所有字段,那么为此生成代码并不困难。 如果你重构生成的代码和普通代码,那么重命名是安全的。 如果缺少setter,那么这种方法将不起作用。 这只是为什么这不是一般解决方案的一个例子。

重构也可以例如将字段移动到其他类。 您想如何从该类的其他字段中引入值? 你怎么能知道改变你保存状态的人是否仍然反映了关键数据? 或者更糟糕的是,想象重构会给同一个字段带来与之前不同的含义。

错误本身的性质也是一种约束。 想象一下,例如发生了错误,因为字段/方法有这个和那个名字。 如果重构现在更改名称,则无论您的状态如何,错误都不会再出现。

这些只是任意的例子,可能与你的真实案例完全无关。 但这是一个案例决策案例,而不是一般战略。 无论如何,如果你知道你的代码,那么bug和你的重构都表现得非常好,那么制作这样一个工具的时间不到一天,可能要少得多。

使用xstream你也可以部分得到它,但你必须自己更改xml。 如果你使用例如db4o,你必须告诉它这个和那个字段现在有这个和那个名字。