* @since 1.0
*/
@Override
public ThreadSafety test(final Class<?> clazz) {
ThreadSafety storedResult = ThreadSafety.THREAD;
/* Get the fields from this class and it's superclass. */
FieldOperation[] ownFields = ClassOperations.getFields(clazz);
/* Add any fields that are non-static to the list. */
for (FieldOperation f : ownFields) {
/* Skip members marked with the 'ThreadSafe' annotation. */
if (f.hasAnnotation(ThreadSafe.class)) continue;
/* Check for certain modifiers on the field we are looking at. */
if (!f.isStatic()) { // We only want to test non-static members.
/* Check to see if the type is Atomic or ThreadLocal. */
if (f.getReturnType().getName().matches("[\\w\\d\\.]*Atomic+[\\w\\d]*")
|| f.getReturnType().equals(AtomicReference.class)
|| f.getReturnType().equals(AtomicReferenceArray.class)
|| f.getReturnType().equals(ThreadLocal.class))
continue;
/* If a field can be accessed by other classes in any way, it
might not be thread safe. Though if it is final or volatile
it should be fine. */
if (f.getAccessModifier() != Access.PRIVATE
&& !(f.isFinal() || f.isVolatile())) {
return ThreadSafety.VM;
}
logger.fine(f.toString());
/* Test the type of the field to see if it is unsafe. */
ThreadSafety result = new MemberTest().test(f.getReturnType());
if (result.val() < storedResult.val())
storedResult = result;
}
}
/* Get the super class for this class if it has one. */
Class<?> superClass = null;
if ((superClass = clazz.getSuperclass()) != null) {
logger.finer(String.format("\tTesting class %s as field of %s",
superClass.getName(), clazz.getName()));
/* If a super class exists, test it. */
ThreadSafety result = new MemberTest().test(superClass);
/* Overwrite the stored value if it is less safe. */
if (result.val() < storedResult.val()) {
logger.finer(String.format("\t%s unsafe.",
superClass.getName()));
storedResult = result;
}
}