3

I run mvn clean cobertura:cobertura install on my project but one the tests fail.

The test try to access a class with a builder that is written by reflection.

public MyClass(Builder builder) throws Exception {
    Field[] classFields = MyClass.class.getDeclaredFields();
    Field[] classBuilderFields = Builder.class.getDeclaredFields();
    for (int i = 0; i < classBuilderFields.length; i++) {
        Field fieldInClass = classFields[i];
        Field fieldInBuilder = classBuilderFields[i];
        fieldInBuilder.setAccessible(true);
        String fieldNameInClass = fieldInClass.getName();
        String fieldNameInBuilder = fieldInBuilder.getName();
        if (null != fieldNameInClass && null != fieldNameInBuilder && fieldNameInClass.equals(fieldNameInBuilder)) {
            fieldInClass.set(this, fieldInBuilder.get(builder));
        } else {
            throw new Exception("");
        }
    }
}

I debugged the code and saw that cobertura "implents" a variable of its own in my class __cobertura_counters. Here is the exception:

java.lang.IllegalAccessException: Can not set static final [I field com.domain.MyClass.__cobertura_counters to
    at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:73)
    at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:77)
    at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77)
    at java.lang.reflect.Field.set(Field.java:741)
    at com.domain.MyClass.<init>(MyClass.java:217)
    at com.domain.MyClassTest.setUp(MyClassTest.java:57)
    at com.domain.MyClass$Builder.build(MyClass.java:197)

How can I resolve this issue?

Igor
  • 846
  • 1
  • 11
  • 25

1 Answers1

4

It's true, Cobertura adds this field so it can keep track of which code has been accessed. Other code coverage tools add similar fields, for similar purposes. The generated field has this signature:

public static final transient int[] __cobertura_counters;

What you can do, is simply ignore transient fields in your code. You can do that like this:

if (!Modifier.isTransient(fieldInClass.getModifiers())) {
    // do a thing
}

Note, however, that non-generated code can also have transient fields, so depending on what code you want to reflect on, this may or may not be an option. Otherwise, your only option (AFAIK) is to simply check whether fieldInClass.getName().equals("__cobertura_counters").

Normally, fields that are generated by the compiler would be marked "synthetic". For example, the this$0 field that javac generates for non-static inner classes is synthetic. It's pretty easy to check for that: fieldInClass.isSynthetic(). However, for some reason, Cobertura doesn't follow this convention.

jqno
  • 15,133
  • 7
  • 57
  • 84