JDK-8281235 : com.sun.tools.javac.code.Types.erasure inconsistently removes annotations
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 9,11,17
  • Priority: P3
  • Status: Resolved
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2022-01-31
  • Updated: 2022-10-14
  • Resolved: 2022-10-14
Related Reports
Duplicate :  
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Bug appears present in the latest https://github.com/openjdk/jdk, and is OS-neutral

A DESCRIPTION OF THE PROBLEM :
The method `com.sun.tools.javac.code.Types.erasure` does not document any intention to deal with annotations, but in practice appears to intend to remove them: its `combineMetadata` method drops any annotations such that e.g. `@Nullable String` erases to `String`.

However, it leaves annotations specifically on (a) array types, because StructuralTypeMapping defines a visitArrayType method that preserves annotations, and (b) primitive types, because it explicitly declines to erase primitives even if they are annotated. The result is a hodge-podge of de-annotated and still-annotated types.

The version of the routine in JDK8 appears to specifically try to retain annotations, then the version in JDK9 appears to try to drop them, but misses out the case of an annotated array or annotated primitive type.

REGRESSION : Last worked in version 8

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Pass a type `@MyAnnotation int` or `@MyAnnotation int[]` or `int @MyAnnotation []` to `Types.erasure`. Contrast behaviour with `@MyAnnotation String` for example.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Either consistently keep or consistently drop annotations. Document which is intended in erasure's javadoc.
ACTUAL -
Annotations are dropped apart from array and primitive types.

---------- BEGIN SOURCE ----------
import java.lang.annotation.*;

public class Test {

  @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE})
  @interface MyAnno { }

  class Inner { }

  public void annotations(@MyAnno byte[] b1, byte @MyAnno [] b2, @MyAnno String s, Class<@MyAnno String> c, @MyAnno Test.Inner ti, Class<? extends @MyAnno String> wc, Class<String>[] classes, @MyAnno byte b, @MyAnno String[] sArray, String @MyAnno [] sArray2) { }

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Follow up the erasure visitor with one of my own dropping remaining annotations.

FREQUENCY : always



Comments
Same as JDK-8042981
14-10-2022

This is the subset of what is dealt with in JDK-8042981 and the case about the array is called out in the PR review there too (by Cushon) and is best handled together.
14-10-2022

The method combineMetadata in com.sun.tools.javac.code.Types drops any annotations such that e.g. `@Nullable String` erases to `String`. However, it leaves annotations specifically on (a) array types - because StructuralTypeMapping defines a visitArrayType method that preserves annotations, and (b) primitive types - because it explicitly declines to erase primitives even if they are annotated. The result is a hodge-podge of de-annotated and still-annotated types. Can be reproduced by passing a type `@MyAnnotation int` or `@MyAnnotation int[]` or `int @MyAnnotation []` to `Types.erasure`. Contrast behaviour with `@MyAnnotation String` for example.
03-02-2022

JDK 8: appears to specifically try to retain annotations JDK 9 onwards : appears to drop them, but misses out the case of an annotated array or annotated primitive type. This is a regression
03-02-2022