JDK-8308831 : javax.lang.model updates for JEP 445 (preview)
  • Type: CSR
  • Component: core-libs
  • Sub-Component: javax.lang.model
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 21
  • Submitted: 2023-05-25
  • Updated: 2023-10-30
  • Resolved: 2023-06-03
Related Reports
CSR :  
Relates :  
Description
Summary
-------

JEP 445 involves language changes and `javax.lang.model` needs supporting updates.

Problem
-------

Add and update API elements in `javax.lang.model` to support JEP 445's unnamed classes.

Solution
--------

Add a predicate to `TypeElement` to query for an unnamed class and update `Filer` to support creating unnamed classes.

Specification
-------------

    diff --git a/src/java.compiler/share/classes/javax/annotation/processing/Filer.java b/src/java.compiler/share/classes/javax/annotation/processing/Filer.java
    index a2e73ee8786..9ebcf2c5908 100644
    --- a/src/java.compiler/share/classes/javax/annotation/processing/Filer.java
    +++ b/src/java.compiler/share/classes/javax/annotation/processing/Filer.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -28,6 +28,7 @@ package javax.annotation.processing;
     import javax.tools.JavaFileManager;
     import javax.tools.*;
     import javax.lang.model.element.Element;
    +import javax.lang.model.element.TypeElement;
     import javax.lang.model.util.Elements;
     import java.io.IOException;
     
    @@ -176,6 +177,13 @@ public interface Filer {
          * <p>Creating a source file in or for an <em>unnamed</em> package in a <em>named</em>
          * module is <em>not</em> supported.
          *
    +     * <p>If the environment is configured to support {@linkplain
    +     * TypeElement#isUnnamed unnamed classes}, the name argument is
    +     * used to provide the leading component of the name used for the
    +     * output file. For example {@code filer.createSourceFile("Foo")}
    +     * to create an unnamed class hosted in {@code Foo.java}. All
    +     * unnamed classes must be in an unnamed package.
    +     *
          * @apiNote To use a particular {@linkplain
          * java.nio.charset.Charset charset} to encode the contents of the
          * file, an {@code OutputStreamWriter} with the chosen charset can
    @@ -255,6 +263,13 @@ public interface Filer {
          * <p>Creating a class file in or for an <em>unnamed</em> package in a <em>named</em>
          * module is <em>not</em> supported.
          *
    +     * <p>If the environment is configured to support {@linkplain
    +     * TypeElement#isUnnamed unnamed classes}, the name argument is
    +     * used to provide the leading component of the name used for the
    +     * output file. For example {@code filer.createClassFile("Foo")} to
    +     * create an unnamed class hosted in {@code Foo.class}. All unnamed
    +     * classes must be in an unnamed package.
    +     *
          * @apiNote To avoid subsequent errors, the contents of the class
          * file should be compatible with the {@linkplain
          * ProcessingEnvironment#getSourceVersion source version} being
    diff --git a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java
    index 68df8920342..ab83acb344c 100644
    diff --git a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java
    index 68df8920342..48bc4132eea 100644
    --- a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java
    +++ b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java
    @@ -25,6 +25,8 @@
     
     package javax.lang.model.element;
     
    +import jdk.internal.javac.PreviewFeature;
    +
     import java.util.List;
     import javax.lang.model.type.*;
     import javax.lang.model.util.*;
    @@ -147,7 +149,7 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
         /**
          * Returns the fully qualified name of this class or interface
          * element.  More precisely, it returns the <i>canonical</i> name.
    -     * For local and anonymous classes, which do not have canonical
    +     * For local, anonymous, and {@linkplain #isUnnamed() unnamed} classes, which do not have canonical
          * names, an {@linkplain Name##empty_name empty name} is
          * returned.
          *
    @@ -163,6 +165,7 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
          *
          * @see Elements#getBinaryName
          * @jls 6.7 Fully Qualified Names and Canonical Names
    +     * @jls 7.3 Compilation Units
          */
         Name getQualifiedName();
     
    @@ -172,6 +175,10 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
          * For an anonymous class, an {@linkplain Name##empty_name empty
          * name} is returned.
          *
    +     * For an {@linkplain #isUnnamed() unnamed} class, a name matching
    +     * the base name of the hosting file, minus any extension, is
    +     * returned.
    +     *
          * @return the simple name of this class or interface,
          * an empty name for an anonymous class
          *
    @@ -179,6 +186,22 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
         @Override
         Name getSimpleName();
     
    +    /**
    +     * {@return {@code true} if this is an unnamed class and {@code
    +     * false} otherwise}
    +     *
    +     * @implSpec
    +     * The default implementation of this method returns {@code false}.
    +     *
    +     * @jls 7.3 Compilation Units
    +     * @since 21
    +     */
    +    @PreviewFeature(feature=PreviewFeature.Feature.UNNAMED_CLASSES,
    +                    reflective=true)
    +    default boolean isUnnamed() {
    +        return false;
    +    }
    +
         /**
          * Returns the direct superclass of this class or interface element.
          * If this class or interface element represents an interface or the class


Comments
After further consideration, it was preferable to have `getQualifiedName` rather than `getSimpleName` be the naming method that returned empty for an unnamed class. This also aligns with the explicit JLS text about unnamed classes having a qualified or canonical name. Moving back to Approved.
03-06-2023

Integrated into https://github.com/openjdk/jdk/pull/13689
02-06-2023

Moving to Approved.
01-06-2023

[~jlaskey], returning a constant false is reasonable for this particular default method.
01-06-2023

``` + default boolean isUnnamed() { + return false; + } ``` Is a TBD for the next release?
01-06-2023