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 onefakeIt
ends up calling this same method?– Dener
the
fakeIt
calls the methodgetValueForField(Field F)
who calls again thefakeIt
in 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
StackOverflow
is because of the bidirectional relationship: when will create aauthor
it creates a list ofbook
and 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 offield
checking whether this class has theclazz
as an attribute, if,set
your 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