We're trying to fixture an array of TypeA, which is field aField in test class SomeTest. We get
com.flextrade.jfixture.exceptions.ObjectCreationException: Unable to create an instance of TypeA[] SomeTest.aField because it contains a circular reference.
TypeA[] SomeTest.aField -->
[LTypeA; -->
TypeA -->
TypeA
But TypeA doesn't contain any fields of type TypeA, or any setters that require a TypeA so there shouldn't be a recursion error. What seems to be happening is that one of its setters requires a type that has multiple constructors, one of which throws a NumberFormatException when invoked by JFixture because the provided string can't be parsed as a number:
com.flextrade.jfixture.exceptions.ObjectCreationException: Unable to invoke constructor public Quantity(java.lang.String)
java.lang.reflect.InvocationTargetException
java.lang.NumberFormatException
The other constructor takes a Long and succeeds, but the exception is propagating past the RecursionGuard, which isn't popping the failed request for Quantity off the stack. This means it always thinks it's one level deeper in the request stack than it actually is, meaning when it finally goes to request the next TypeA for the array it hasn't popped the original TypeA request off the stack and it thinks there's a circular reference.
The following is a simple way to reproduce the issue:
class TypeWithThrowingConstructor {
public TypeWithThrowingConstructor() {
throw new RuntimeException();
}
public TypeWithThrowingConstructor(String string) {
}
}
class TypeWithFieldWithThrowingConstructor {
public TypeWithThrowingConstructor fieldWithThrowingConstructor;
}
JFixture fixture = new JFixture();
fixture.create(TypeWithFieldWithThrowingConstructor[].class);
The solution we employ here is to make sure that RecursionGuard always pops requests off the stack, even if they throw an exception.
We're trying to fixture an array of
TypeA
, which is fieldaField
in test classSomeTest
. We getBut
TypeA
doesn't contain any fields of typeTypeA
, or any setters that require aTypeA
so there shouldn't be a recursion error. What seems to be happening is that one of its setters requires a type that has multiple constructors, one of which throws aNumberFormatException
when invoked byJFixture
because the provided string can't be parsed as a number:The other constructor takes a
Long
and succeeds, but the exception is propagating past theRecursionGuard
, which isn't popping the failed request forQuantity
off the stack. This means it always thinks it's one level deeper in the request stack than it actually is, meaning when it finally goes to request the nextTypeA
for the array it hasn't popped the originalTypeA
request off the stack and it thinks there's a circular reference.The following is a simple way to reproduce the issue:
The solution we employ here is to make sure that
RecursionGuard
always pops requests off the stack, even if they throw an exception.