2
I’m making a library that populates any model with random values, to be used in tests, but it turns out that when I have a relation like below, I get a StackOverflowException
Author
@Entity
public class Author implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private Long id;
private String name;
@OneToMany
private List<Book> books = new ArrayList<Book>();
and Book
@Entity
public class Book implements Serializable {
@ManyToOne
private Author author;
the code that reads the fields is like this
public <T> T fakeIt(Class<T> clazz) throws FakerException {
if(clazz.getAnnotation(Entity.class) == null){
throw new FakerException("The class "+ clazz.getName()+ "is not an entity");
}
try {
T faked = clazz.newInstance();
for(Field f : clazz.getDeclaredFields()){
if(f.getName().equals("serialVersionUID"))
continue;
System.out.println("Genearting value for "+f.getName() + " on " + f.getDeclaringClass());
f.setAccessible(true);
f.set(faked, getValueForField(f));
}
return faked;
} catch(Exception e){
throw new FakerException(e);
}
}
private Object getValueForField(Field f) throws Exception {
if(f.isAnnotationPresent(UseGenerator.class)){
Generator<?> gen = (Generator<?>) f.getAnnotation(UseGenerator.class).generator().newInstance();
return gen.genearte();
} else if(f.isAnnotationPresent(ManyToOne.class)){
return fakeIt(f.getType());
} else if(f.isAnnotationPresent(OneToMany.class)){
Class<?> toFake = extractTypeFromList(f);
List<Object> fakedObjects = new ArrayList<Object>();
for(int i = 0; i < 6; i++){
fakedObjects.add(fakeIt(toFake));
}
return fakedObjects;
}
// Other types
String clazzType = f.getType().getSimpleName();
Generator<?> generator = defaultGenerators.get(clazzType.toLowerCase());
if(generator != null)
return generator.genearte();
return null;
}
private Class<?> extractTypeFromList(Field f) {
ParameterizedType parameterizedType = (ParameterizedType) f.getGenericType();
Class<?> type = (Class<?>) parameterizedType.getActualTypeArguments()[0];
return type;
}
in the case, fakeIt is the function that generates the random values. in this case, it falls into the field books and when he calls again fakeIt, will try to create a new Author that will fall in the field books and so on.
how best to avoid this?
Could you add the error to the question? At first I don’t see where one might occur
StackOverflow. That onefakeItends up calling this same method?– Dener
the
fakeItcalls the methodgetValueForField(Field F)who calls again thefakeItin case of a relationship. I can post the whole code if it helps– Luiz E.
Post yes, at least the getValueForField and fakeIt method.
– Dener
@Dener edited!
– Luiz E.
Luiz, the
StackOverflowis because of the bidirectional relationship: when will create aauthorit creates a list ofbookand these will also try to create aauthor, from then on it will loop. You will have to seek to treat bi-directional relations.– Dener
It makes a logic more or less like this: create
checkIfFieldHasClass(field, clazz, faked)in this method obtain the class offieldchecking whether this class has theclazzas an attribute, if,setyour instance createdfaked, if you don’t ask to generate this value.– Dener
cool, it worked. you could post as an answer to accept?
– Luiz E.
Ok! Sorry for the delay to answer! Solving some bugs here I ended up running out of time
– Dener