Skip to content

Commit

Permalink
8315458: Implement JEP 463: Implicitly Declared Classes and Instance …
Browse files Browse the repository at this point in the history
…Main Method (Second Preview)

Reviewed-by: jlahoda, mcimadamore, vromero, rriggs, alanb, mchung
  • Loading branch information
JimLaskey committed Nov 30, 2023
1 parent 03759e8 commit 04ad98e
Show file tree
Hide file tree
Showing 48 changed files with 612 additions and 664 deletions.
78 changes: 28 additions & 50 deletions src/java.base/share/classes/java/lang/Class.java
Expand Up @@ -190,30 +190,21 @@
* a class or interface is hidden has no bearing on the characteristics
* exposed by the methods of class {@code Class}.
*
* <h2><a id=unnamedClasses>Unnamed Classes</a></h2>
*
* A {@code class} file representing an {@linkplain #isUnnamedClass unnamed class}
* is generated by a Java compiler from a source file for an unnamed class.
* The {@code Class} object representing an unnamed class is top-level,
* {@linkplain #isSynthetic synthetic}, and {@code final}. While an
* unnamed class does <em>not</em> have a name in its Java source
* form, several of the name-related methods of {@code java.lang.Class}
* do return non-null and non-empty results for the {@code Class}
* object representing an unnamed class.
* <h2><a id=implicitClasses>Implicit Classes</a></h2>
*
* Conventionally, a Java compiler, starting from a source file for an
* unnamed class, say {@code HelloWorld.java}, creates a
* implicit class, say {@code HelloWorld.java}, creates a
* similarly-named {@code class} file, {@code HelloWorld.class}, where
* the class stored in that {@code class} file is named {@code
* "HelloWorld"}, matching the base names of the source and {@code
* class} files.
*
* For the {@code Class} object of an unnamed class {@code
* For the {@code Class} object of an implicit class {@code
* HelloWorld}, the methods to get the {@linkplain #getName name} and
* {@linkplain #getTypeName type name} return results
* equal to {@code "HelloWorld"}. The {@linkplain #getSimpleName
* simple name} of such an unnamed class is the empty string and the
* {@linkplain #getCanonicalName canonical name} is {@code null}.
* simple name} of such an implicit class is {@code "HelloWorld"} and the
* {@linkplain #getCanonicalName canonical name} is {@code "HelloWorld"}.
*
* @param <T> the type of the class modeled by this {@code Class}
* object. For example, the type of {@code String.class} is {@code
Expand Down Expand Up @@ -1809,7 +1800,7 @@ public Class<?> getEnclosingClass() throws SecurityException {
/**
* Returns the simple name of the underlying class as given in the
* source code. An empty string is returned if the underlying class is
* {@linkplain #isAnonymousClass() anonymous} or {@linkplain #isUnnamedClass() unnamed}.
* {@linkplain #isAnonymousClass() anonymous}.
* A {@linkplain #isSynthetic() synthetic class}, one not present
* in source code, can have a non-empty name including special
* characters, such as "{@code $}".
Expand All @@ -1822,9 +1813,6 @@ public Class<?> getEnclosingClass() throws SecurityException {
* @since 1.5
*/
public String getSimpleName() {
if (isUnnamedClass()) {
return "";
}
ReflectionData<T> rd = reflectionData();
String simpleName = rd.simpleName;
if (simpleName == null) {
Expand Down Expand Up @@ -1874,7 +1862,6 @@ public String getTypeName() {
* <ul>
* <li>a {@linkplain #isLocalClass() local class}
* <li>a {@linkplain #isAnonymousClass() anonymous class}
* <li>an {@linkplain #isUnnamedClass() unnamed class}
* <li>a {@linkplain #isHidden() hidden class}
* <li>an array whose component type does not have a canonical name</li>
* </ul>
Expand All @@ -1894,9 +1881,6 @@ public String getTypeName() {
* @since 1.5
*/
public String getCanonicalName() {
if (isUnnamedClass()) {
return null;
}
ReflectionData<T> rd = reflectionData();
String canonicalName = rd.canonicalName;
if (canonicalName == null) {
Expand Down Expand Up @@ -1931,33 +1915,12 @@ private String getCanonicalName0() {
}
}

/**
* {@return {@code true} if and only if the underlying class
* is an unnamed class}
*
* @apiNote
* An unnamed class is not an {@linkplain #isAnonymousClass anonymous class}.
*
* @since 21
*
* @jls 7.3 Compilation Units
*/
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED_CLASSES,
reflective=true)
public boolean isUnnamedClass() {
return PreviewFeatures.isEnabled() && isSynthetic()
&& isTopLevelClass()
&& Modifier.isFinal(getModifiers());
}


/**
* Returns {@code true} if and only if the underlying class
* is an anonymous class.
*
* @apiNote
* An anonymous class is not a {@linkplain #isHidden() hidden class}.
* An anonymous class is not an {@linkplain #isUnnamedClass() unnamed class}.
*
* @return {@code true} if and only if this class is an anonymous class.
* @since 1.5
Expand Down Expand Up @@ -2922,6 +2885,21 @@ List<Method> getDeclaredPublicMethods(String name, Class<?>... parameterTypes) {
return result;
}

/**
* Returns the most specific {@code Method} object of this class, super class or
* interface that have the specified method name and parameter types.
*
* @param publicOnly true if only public methods are examined, otherwise all methods
* @param name the name of the method
* @param parameterTypes the parameter array
* @return the {@code Method} object for the method found from this class matching
* the specified name and parameters, or null if not found
*/
Method findMethod(boolean publicOnly, String name, Class<?>... parameterTypes) {
PublicMethods.MethodList res = getMethodsRecursive(name, parameterTypes, true, publicOnly);
return res == null ? null : getReflectionFactory().copyMethod(res.getMostSpecific());
}

/**
* Returns a {@code Constructor} object that reflects the specified
* constructor of the class represented by this
Expand Down Expand Up @@ -3750,7 +3728,7 @@ private Method getMethod0(String name, Class<?>[] parameterTypes) {
PublicMethods.MethodList res = getMethodsRecursive(
name,
parameterTypes == null ? EMPTY_CLASS_ARRAY : parameterTypes,
/* includeStatic */ true);
/* includeStatic */ true, /* publicOnly */ true);
return res == null ? null : res.getMostSpecific();
}

Expand All @@ -3759,9 +3737,10 @@ private Method getMethod0(String name, Class<?>[] parameterTypes) {
// via ReflectionFactory.copyMethod.
private PublicMethods.MethodList getMethodsRecursive(String name,
Class<?>[] parameterTypes,
boolean includeStatic) {
// 1st check declared public methods
Method[] methods = privateGetDeclaredMethods(/* publicOnly */ true);
boolean includeStatic,
boolean publicOnly) {
// 1st check declared methods
Method[] methods = privateGetDeclaredMethods(publicOnly);
PublicMethods.MethodList res = PublicMethods.MethodList
.filter(methods, name, parameterTypes, includeStatic);
// if there is at least one match among declared methods, we need not
Expand All @@ -3775,15 +3754,14 @@ private PublicMethods.MethodList getMethodsRecursive(String name,
// we must consult the superclass (if any) recursively...
Class<?> sc = getSuperclass();
if (sc != null) {
res = sc.getMethodsRecursive(name, parameterTypes, includeStatic);
res = sc.getMethodsRecursive(name, parameterTypes, includeStatic, publicOnly);
}

// ...and coalesce the superclass methods with methods obtained
// from directly implemented interfaces excluding static methods...
for (Class<?> intf : getInterfaces(/* cloneArray */ false)) {
res = PublicMethods.MethodList.merge(
res, intf.getMethodsRecursive(name, parameterTypes,
/* includeStatic */ false));
res, intf.getMethodsRecursive(name, parameterTypes, /* includeStatic */ false, publicOnly));
}

return res;
Expand Down
3 changes: 3 additions & 0 deletions src/java.base/share/classes/java/lang/System.java
Expand Up @@ -2345,6 +2345,9 @@ private static void setJavaLangAccess() {
public List<Method> getDeclaredPublicMethods(Class<?> klass, String name, Class<?>... parameterTypes) {
return klass.getDeclaredPublicMethods(name, parameterTypes);
}
public Method findMethod(Class<?> klass, boolean publicOnly, String name, Class<?>... parameterTypes) {
return klass.findMethod(publicOnly, name, parameterTypes);
}
public jdk.internal.reflect.ConstantPool getConstantPool(Class<?> klass) {
return klass.getConstantPool();
}
Expand Down
Expand Up @@ -65,6 +65,11 @@ public interface JavaLangAccess {
*/
List<Method> getDeclaredPublicMethods(Class<?> klass, String name, Class<?>... parameterTypes);

/**
* Return most specific method that matches name and parameterTypes.
*/
Method findMethod(Class<?> klass, boolean publicOnly, String name, Class<?>... parameterTypes);

/**
* Return the constant pool for a class.
*/
Expand Down
Expand Up @@ -69,8 +69,10 @@ public enum Feature {
FOREIGN,
@JEP(number=459, title="String Templates", status="Second Preview")
STRING_TEMPLATES,
@JEP(number=445, title="Unnamed Classes and Instance Main Methods")
@JEP(number=445, title="Unnamed Classes and Instance Main Methods", status="Deprecated")
UNNAMED_CLASSES,
@JEP(number=463, title="Implicit Classes and Instance Main Methods", status="Preview")
IMPLICIT_CLASSES,
@JEP(number=446, title="Scoped Values", status="Preview")
SCOPED_VALUES,
@JEP(number=453, title="Structured Concurrency", status="Preview")
Expand Down
169 changes: 0 additions & 169 deletions src/java.base/share/classes/jdk/internal/misc/MainMethodFinder.java

This file was deleted.

1 comment on commit 04ad98e

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.