IMHO, you should put the type of the field annotated with the @Version annotation in that class. I think this will work with inheritance too, out of the box.
If you don't know the type beforehand, I'd go with standard reflection. I'd iterate through all the declared fields, and check annotations if they contain the @Version annotation. If not found, check superclass, until found...
public static Field getVersionField(Object entity) {
Class<?> myClass = entity.getClass();
do {
Field[] fields = myClass.getDeclaredFields();
for(Field field:fields) {
if(field.getAnnotation(Version.class)!=null) {
return field;
}
}
} while((myClass=myClass.getSuperclass())!=null);
return null;
}
Beware While the Class.getFields() seems to be a nicer alternative, as it only returns the public fields, it would not work:
Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object.
EDIT The above works only in a case, when the @Version annotation is strictly used on Fields. However, as Konstantin Pribluda pointed out, this annotation can be put on methods too, which means two things:
- methods must be checked too
- interfaces must be checked too, as methods can be defined by interfaces...
This also means that our simple cycle must be transformed into a recursive graph traversal...
public static Method getVersionMethod(Class<?> myClass) {
Method[] methods = myClass.getDeclaredMethods();
for(Method method : methods) {
if(method.getAnnotation(Version.class)!=null) {
return method;
}
}
if(myClass.getSuperclass()!=null) {
Class<?> returned = getVersionMethod(myClass.getSuperclass());
if(returned!=null) {
return returned;
}
}
for(Class<?> interfaceToCheck : myClass.getInterfaces()) {
Class<?> returned = getVersionMethod(interfaceToCheck);
if(returned!=null) {
return returned;
}
}
return null;
}