Monday, 8 May 2017

Java Reflection, Synthetic Members and Unit Testing.

Recently I was working on developing a Custom Serializer With Custom Annotation using Java reflection you can find more about the same here. Everything seems to be good at the end. But, while extending the project with adding Unit Test cases things seems to be screwing up badly for unknown reason. While debugging UT's I found that the issue seems to be because of Synthetic members that is been define in the class. I had no clues about it. So I dig further to understand the world of Synthetic Members in Java world.

What is Synthetic Members?
Any constructs introduced by the compiler that do not have a corresponding construct in the source code must be marked as synthetic, except for default constructors and the class initialization method.

Why Synthetic Members issues occurring in Junit?  
To collect execution data JaCoCo instruments the classes under test which adds two members to the classes: A private static field $jacocoData and a private static method $jacocoInit(). Both members are marked as synthetic. Since, these members are added to the class and the Serializer that is been developed included those two fields as part of Serialization and test cases failed in the end.

How to fix Synthetic Members issues?  
As a general or good practice we should ignore Synthetic members particularly while dealing with reflection. As per Java Doc we can identify a member whether it's Synthetic or not through isSynthetic() method. By adding a check to the Serialize method the issue is solved and the following is code after the change.
 
public void serialize(Object o, JsonGenerator jsonGenerator, 
SerializerProvider serializerProvider) throws IOException {

    jsonGenerator.writeStartObject();
    jsonGenerator.writeStringField("name", o.getClass()
                .getSimpleName());
    jsonGenerator.writeArrayFieldStart("definition");

    Field[] fields = o.getClass().getDeclaredFields();
    for (Field field : fields) {
        if (!field.isSynthetic()) {
            jsonGenerator.writeStartObject();
            jsonGenerator.writeStringField("name",
            StringUtils.join(StringUtils
             .splitByCharacterTypeCamelCase(field.getName()), '-')
             .toString().toLowerCase());
            addAnnotationInJson(field, jsonGenerator);
            try {
                addTypeInJson(field, jsonGenerator);
            }
            catch (Exception e) {
                //log.info(e.getMessage());            }
            jsonGenerator.writeEndObject();
        }
    }
    jsonGenerator.writeEndArray();
    jsonGenerator.writeEndObject();
} 

 

No comments:

Post a Comment