changeset 50728:a064652a444f jep-334

Minor updates based on CSR and spec review; add tests for FieldTypeDescriptor methods
author briangoetz
date Wed, 23 May 2018 13:24:31 -0400
parents c97d728ea327
children d8ea829882ad
files src/java.base/share/classes/java/lang/Class.java src/java.base/share/classes/java/lang/Double.java src/java.base/share/classes/java/lang/Enum.java src/java.base/share/classes/java/lang/Float.java src/java.base/share/classes/java/lang/Integer.java src/java.base/share/classes/java/lang/Long.java src/java.base/share/classes/java/lang/String.java src/java.base/share/classes/java/lang/invoke/FieldTypeDescriptor.java src/java.base/share/classes/java/lang/invoke/VarHandles.java src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template src/java.base/share/classes/java/lang/invoke/constant/ClassDesc.java src/java.base/share/classes/java/lang/invoke/constant/Constable.java src/java.base/share/classes/java/lang/invoke/constant/ConstantClassDesc.java src/java.base/share/classes/java/lang/invoke/constant/ConstantDesc.java src/java.base/share/classes/java/lang/invoke/constant/ConstantMethodHandleDesc.java src/java.base/share/classes/java/lang/invoke/constant/ConstantUtils.java src/java.base/share/classes/java/lang/invoke/constant/DynamicCallSiteDesc.java test/jdk/java/lang/invoke/constant/ClassRefTest.java test/jdk/java/lang/invoke/constant/TypeDescriptorTest.java
diffstat 19 files changed, 134 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/Class.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/Class.java	Wed May 23 13:24:31 2018 -0400
@@ -3879,9 +3879,7 @@
 
     @Override
     public Class<?> componentType() {
-        if (!isArray())
-            throw new IllegalStateException("not an array class");
-        return componentType;
+        return isArray() ? componentType : null;
     }
 
     @Override
--- a/src/java.base/share/classes/java/lang/Double.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/Double.java	Wed May 23 13:24:31 2018 -0400
@@ -1077,10 +1077,10 @@
     }
 
     /**
-     * Returns a symbolic constant reference for this instance, which is
-     * the instance itself.
+     * Returns a nominal descriptor for this instance, which is the instance
+     * itself.
      *
-     * @return the {@linkplain Double} instance
+     * @return an {@link Optional} describing the {@linkplain Double} instance
      */
     @Override
     public Optional<ConstantDesc<Double>> describeConstable() {
--- a/src/java.base/share/classes/java/lang/Enum.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/Enum.java	Wed May 23 13:24:31 2018 -0400
@@ -206,16 +206,6 @@
         return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
     }
 
-    /**
-     * Return a nominal descriptor for this instance, if one can be
-     * constructed.  This object (and any classes needed to construct its
-     * nominal description) must be accessible from the class described by the
-     * {@code lookup} parameter.
-     *
-     * @return An {@link Optional} containing the resulting nominal descriptor,
-     * or an empty {@link Optional} if one cannot be constructed or this object
-     * is not accessible from {@code lookup}
-     */
     @Override
     public final Optional<EnumDesc<E>> describeConstable() {
         return getDeclaringClass()
--- a/src/java.base/share/classes/java/lang/Float.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/Float.java	Wed May 23 13:24:31 2018 -0400
@@ -989,10 +989,10 @@
     }
 
     /**
-     * Returns a symbolic constant reference for this instance, which is
-     * the instance itself.
+     * Returns a nominal descriptor for this instance, which is the instance
+     * itself.
      *
-     * @return the {@linkplain Float} instance
+     * @return an {@link Optional} describing the {@linkplain Float} instance
      */
     @Override
     public Optional<ConstantDesc<Float>> describeConstable() {
--- a/src/java.base/share/classes/java/lang/Integer.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/Integer.java	Wed May 23 13:24:31 2018 -0400
@@ -1824,10 +1824,10 @@
     }
 
     /**
-     * Returns a symbolic constant reference for this instance, which is
-     * the instance itself.
+     * Returns a nominal descriptor for this instance, which is the instance
+     * itself.
      *
-     * @return the {@linkplain Integer} instance
+     * @return an {@link Optional} describing the {@linkplain Integer} instance
      */
     @Override
     public Optional<ConstantDesc<Integer>> describeConstable() {
--- a/src/java.base/share/classes/java/lang/Long.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/Long.java	Wed May 23 13:24:31 2018 -0400
@@ -1970,10 +1970,10 @@
     }
 
     /**
-     * Returns a symbolic constant reference for this instance, which is
-     * the instance itself.
+     * Returns a nominal descriptor for this instance, which is the instance
+     * itself.
      *
-     * @return the {@linkplain Long} instance
+     * @return an {@link Optional} describing the {@linkplain Long} instance
      */
     @Override
     public Optional<ConstantDesc<Long>> describeConstable() {
--- a/src/java.base/share/classes/java/lang/String.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/String.java	Wed May 23 13:24:31 2018 -0400
@@ -3280,10 +3280,10 @@
     }
 
     /**
-     * Returns a symbolic constant reference for this instance, which is
-     * the instance itself.
+     * Returns a nominal descriptor for this instance, which is the instance
+     * itself.
      *
-     * @return the {@linkplain String} instance
+     * @return an {@link Optional} describing the {@linkplain String} instance
      */
     @Override
     public Optional<ConstantDesc<String>> describeConstable() {
--- a/src/java.base/share/classes/java/lang/invoke/FieldTypeDescriptor.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/FieldTypeDescriptor.java	Wed May 23 13:24:31 2018 -0400
@@ -20,9 +20,9 @@
 
     /**
      * If this field descriptor describes an array type, return
-     * a descriptor for its component type.
-     * @return the component type
-     * @throws IllegalStateException if this descriptor does not describe an array type
+     * a descriptor for its component type, otherwise return {@code null}.
+     * @return the component type, or {@code null} if this field descriptor does
+     * not describe an array type
      */
     F componentType();
 
--- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java	Wed May 23 13:24:31 2018 -0400
@@ -148,7 +148,7 @@
     }
 
     // Required by instance field handles
-    static Field getFieldFromRecieverAndOffset(Class<?> receiverType,
+    static Field getFieldFromReceiverAndOffset(Class<?> receiverType,
                                                long offset,
                                                Class<?> fieldType) {
         for (Field f : receiverType.getDeclaredFields()) {
--- a/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template	Wed May 23 13:24:31 2018 -0400
@@ -81,7 +81,7 @@
             if (!receiverTypeRef.isPresent() || !fieldTypeRef.isPresent())
                 return Optional.empty();
 
-            String name = VarHandles.getFieldFromRecieverAndOffset(
+            String name = VarHandles.getFieldFromReceiverAndOffset(
                 receiverType, fieldOffset, {#if[Object]?fieldType:$type$.class}).getName();
             return Optional.of(VarHandleDesc.ofField(receiverTypeRef.get(), name, fieldTypeRef.get()));
         }
--- a/src/java.base/share/classes/java/lang/invoke/constant/ClassDesc.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/constant/ClassDesc.java	Wed May 23 13:24:31 2018 -0400
@@ -57,7 +57,12 @@
                 FieldTypeDescriptor<ClassDesc> {
 
     /**
-     * Create a {@linkplain ClassDesc} given a class name.
+     * Create a {@linkplain ClassDesc} given the name of a class or interface
+     * type, such as {@code "java.lang.String"}.  (To create a descriptor for an
+     * array type, either use {@link #ofDescriptor(String)}
+     * or {@link #arrayType()}; to create a descriptor for a primitive type, use
+     * {@link #ofDescriptor(String)} or use the predefined constants in
+     * {@link ConstantDescs}).
      *
      * @param name the fully qualified (dot-separated) binary class name
      * @return a {@linkplain ClassDesc} describing the desired class
@@ -196,23 +201,21 @@
 
     /**
      * Returns the component type of this {@linkplain ClassDesc}, if it describes
-     * an array type.
+     * an array type, or {@code null} otherwise.
      *
-     * @return a {@linkplain ClassDesc} describing the component type
-     * @throws IllegalStateException if this {@linkplain ClassDesc} does not
-     * describe an array type
+     * @return a {@linkplain ClassDesc} describing the component type, or {@code null}
+     * if this descriptor does not describe an array type
      */
     default ClassDesc componentType() {
-        if (!isArray())
-            throw new IllegalStateException("not an array");
-        return ClassDesc.ofDescriptor(descriptorString().substring(1));
+        return isArray() ? ClassDesc.ofDescriptor(descriptorString().substring(1)) : null;
     }
 
     /**
      * Returns the package name of this {@linkplain ClassDesc}, if it describes
      * a class or interface type.
      *
-     * @return the package name, or the empty string if no package
+     * @return the package name, or the empty string if the class is in the
+     * default package
      * @throws IllegalStateException if this {@linkplain ClassDesc} does not
      * describe a class or interface type
      */
--- a/src/java.base/share/classes/java/lang/invoke/constant/Constable.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/constant/Constable.java	Wed May 23 13:24:31 2018 -0400
@@ -64,7 +64,7 @@
 public interface Constable<T> {
     /**
      * Return a nominal descriptor for this instance, if one can be
-     * constructed.
+     * constructed, or an empty {@link Optional} if one cannot be.
      *
      * @return An {@link Optional} containing the resulting nominal descriptor,
      * or an empty {@link Optional} if one cannot be constructed.
--- a/src/java.base/share/classes/java/lang/invoke/constant/ConstantClassDesc.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/constant/ConstantClassDesc.java	Wed May 23 13:24:31 2018 -0400
@@ -40,7 +40,7 @@
  * interface, or array type.  A {@linkplain ConstantClassDesc} corresponds to a
  * {@code Constant_Class_info} entry in the constant pool of a classfile.
  */
-public class ConstantClassDesc implements ClassDesc {
+public final class ConstantClassDesc implements ClassDesc {
     private final String descriptor;
 
     /**
--- a/src/java.base/share/classes/java/lang/invoke/constant/ConstantDesc.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/constant/ConstantDesc.java	Wed May 23 13:24:31 2018 -0400
@@ -65,6 +65,10 @@
  * Instead, they should extend {@link DynamicConstantDesc} (as {@link EnumDesc}
  * and {@link VarHandleDesc} do.)
  *
+ * <p>Nominal descriptors should be compared using the
+ * {@link Object#equals(Object)} method. There is no guarantee that any
+ * particular entity will always be represented by the same descriptor instance.
+ *
  * @apiNote In the future, if the Java language permits, {@linkplain ConstantDesc}
  * may become a {@code sealed} interface, which would prohibit subclassing except by
  * explicitly permitted types.  Bytecode libraries can assume that the following
--- a/src/java.base/share/classes/java/lang/invoke/constant/ConstantMethodHandleDesc.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/constant/ConstantMethodHandleDesc.java	Wed May 23 13:24:31 2018 -0400
@@ -43,7 +43,7 @@
  * {@link MethodHandle}.  A {@linkplain ConstantMethodHandleDesc} corresponds to
  * a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile.
  */
-public class ConstantMethodHandleDesc implements MethodHandleDesc {
+public final class ConstantMethodHandleDesc implements MethodHandleDesc {
 
     private final Kind kind;
     private final ClassDesc owner;
--- a/src/java.base/share/classes/java/lang/invoke/constant/ConstantUtils.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/constant/ConstantUtils.java	Wed May 23 13:24:31 2018 -0400
@@ -33,9 +33,7 @@
 import sun.invoke.util.Wrapper;
 
 /**
- * ConstantUtils
- *
- * @author Brian Goetz
+ * Helper methods for the implementation of {@code java.lang.invoke.constant}.
  */
 class ConstantUtils {
     static final ConstantDesc<?>[] EMPTY_CONSTANTDESC = new ConstantDesc<?>[0];
--- a/src/java.base/share/classes/java/lang/invoke/constant/DynamicCallSiteDesc.java	Wed May 23 07:17:14 2018 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/constant/DynamicCallSiteDesc.java	Wed May 23 13:24:31 2018 -0400
@@ -40,9 +40,12 @@
 /**
  * A <a href="package-summary.html#nominal">nominal descriptor</a> for an
  * {@code invokedynamic} call site.
+ *
+ * <p>Concrete subtypes of {@linkplain DynamicCallSiteDesc} must be
+ * <a href="../doc-files/ValueBased.html">value-based</a>.
  */
 @SuppressWarnings("rawtypes")
-public final class DynamicCallSiteDesc {
+public class DynamicCallSiteDesc {
 
     private final ConstantMethodHandleDesc bootstrapMethod;
     private final ConstantDesc<?>[] bootstrapArgs;
--- a/test/jdk/java/lang/invoke/constant/ClassRefTest.java	Wed May 23 07:17:14 2018 -0700
+++ b/test/jdk/java/lang/invoke/constant/ClassRefTest.java	Wed May 23 13:24:31 2018 -0400
@@ -38,6 +38,7 @@
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
@@ -195,13 +196,7 @@
             assertEquals(a1.descriptorString(), "[" + a0.descriptorString());
             assertEquals(a2.descriptorString(), "[[" + a0.descriptorString());
 
-            try {
-                assertEquals(a0, a0.componentType());
-                fail("Didn't throw ISE");
-            }
-            catch (IllegalStateException expected) {
-                // succeed
-            }
+            assertNull(a0.componentType());
             assertEquals(a0, a1.componentType());
             assertEquals(a1, a2.componentType());
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/constant/TypeDescriptorTest.java	Wed May 23 13:24:31 2018 -0400
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.invoke.FieldTypeDescriptor;
+import java.lang.invoke.constant.ClassDesc;
+
+import org.testng.annotations.Test;
+
+import static java.lang.invoke.constant.ConstantDescs.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * @test
+ * @compile -XDfolding=false TypeDescriptorTest.java
+ * @run testng TypeDescriptorTest
+ * @summary unit tests for implementations of java.lang.invoke.TypeDescriptor
+ */
+@Test
+public class TypeDescriptorTest {
+    private<F extends FieldTypeDescriptor<F>> void testArray(F f, boolean isArray, F component, F array) {
+        if (isArray) {
+            assertTrue(f.isArray());
+            assertEquals(f.arrayType(), array);
+            assertEquals(f.componentType(), component);
+        }
+        else {
+            assertFalse(f.isArray());
+            assertEquals(f.arrayType(), array);
+            assertNull(f.componentType());
+        }
+    }
+
+    public void testClass() {
+        testArray(int.class, false, null, int[].class);
+        testArray(int[].class, true, int.class, int[][].class);
+        testArray(int[][].class, true, int[].class, int[][][].class);
+        testArray(String.class, false, null, String[].class);
+        testArray(String[].class, true, String.class, String[][].class);
+        testArray(String[][].class, true, String[].class, String[][][].class);
+
+        assertTrue(int.class.isPrimitive());
+        assertFalse(int[].class.isPrimitive());
+        assertFalse(String.class.isPrimitive());
+        assertFalse(String[].class.isPrimitive());
+    }
+
+    public void testClassDesc() {
+
+        testArray(CR_int, false, null, CR_int.arrayType());
+        testArray(CR_int.arrayType(), true, CR_int, CR_int.arrayType(2));
+        testArray(CR_int.arrayType(2), true, CR_int.arrayType(), CR_int.arrayType(3));
+        testArray(CR_String, false, null, CR_String.arrayType());
+        testArray(CR_String.arrayType(), true, CR_String, CR_String.arrayType(2));
+        testArray(CR_String.arrayType(2), true, CR_String.arrayType(), CR_String.arrayType(3));
+
+        assertTrue(CR_int.isPrimitive());
+        assertFalse(CR_int.arrayType().isPrimitive());
+        assertFalse(CR_String.isPrimitive());
+        assertFalse(CR_String.arrayType().isPrimitive());
+    }
+
+}