Review request for type annotation reflection test

Sergey Grinev sergey.grinev at oracle.com
Fri Aug 23 03:36:01 PDT 2013


Hi, all.

Sorry if this review covers same issue I reported on reviewboard one, 
but it seems few important point were not fixed:

1.  public Map<Helper.Declaration, Object> lhm = new LinkedHashMap<>();
and
     public synchronized static String genDeclaration(
             Map<Helper.Declaration, Object> input, Declaration... srcType)

- fields used as a method-local temporary variables are error-prone and confusing. Users/readers of that code are not aware when this field can be used or when this field can be cleared, also using such field is not thread-safe. Imagine someone added one more ENUM value to TestCase, used lhm and didn't call lhm.clear() -- things will break and very different place this person didn't even touch.

- Map claims it stores Objects but actually they are only String and String[]. Thus your getDeclaration() has invalid signature and is error-prone. Also you calls instanceof several times to resolve this ambiguity which is considered to be an anti-pattern as well.

You can solve these problems by introducing separate entity responsible for declaration generation:

public class DeclarationGenerator {

     private final Map<Helper.Declaration, String[]> lhm = new LinkedHashMap<>();
     
     public void add(Helper.Declaration key, String... value) {
         lhm.put(key, value);
     }
     public String genDeclaration(Declaration... srcType) {
         //...
         for (Declaration st : Declaration.values()) {
                 if (input.containsKey(st))
                         result.append(st.getSrc(input.get(st)));
         }
         //...
     }
}

with this helper class instead of

                 lhm.clear();
                 lhm.put(Helper.Declaration.IMPORT, null);
                 lhm.put(Helper.Declaration.CLASS, str[0]);
                 testCode += Helper.genDeclaration(lhm);

you can write

                 DeclarationGenerator dg = new DeclarationGenerator(); // not to reuse, create new one for each generation
                 dg.put(Helper.Declaration.IMPORT, null);
                 dg.put(Helper.Declaration.CLASS, str[0]);
                 testCode += dg.genDeclaration();

having clean design without field used as temporary variable and type ambiguity.


2. several TestCase enum entries, especially TESTBASECLSSTART and 
TESTBASECLS are copypasted in several places.

3. public static Map<String, String> testInput = new LinkedHashMap<>();

why this field in static?


-- Sergey

On 22-Aug-13 22:43, Alex Buckley wrote:
> I have no further comments. Thanks for all your work to test this new 
> and expansive API.
>
> Alex
>
> On 8/20/2013 1:56 AM, Charlie Wang wrote:
>> Hi Alex,
>>    I used testInput.size() instead of static int clsIdx as suffix this
>> time. And other update according to your comments.
>>
>> Here's the link. Please review again.
>> http://cr.openjdk.java.net/~pzhang/Charlie/TypeAnnotation1/webrev/
>>
>>
>> - Charlie
>>
>> On 2013/8/9 1:05, Alex Buckley wrote:
>>> - AnnotationTest.i/clsIdx: it wasn't the name of the variable I was
>>> objecting to. It was the fact that you're relying on a mutable public
>>> static variable at all.
>>>
>>> - GenTestCode should take Class<? extends TestCaseGenerator>, so you
>>> don't need to cast to TestCaseGenerator in GenTestCode. (Same comment
>>> for AnnotationTest.compileCode).
>>>
>>> - AnnotationTest.testInput is a Map<Object,String> but I'm sure you
>>> can do better than Object for keys.'
>>>
>>> - ExecutableGetAnnotatedParameterTypesTest.testInput hides
>>> AnnotationTest.testInput, but swaps the order of the type arguments!
>>> Map<String,Object> is either wrong, or should not use Object.
>>>
>>> Alex



More information about the type-annotations-dev mailing list