changeset 57919:d45c1a111e21 records-and-sealed

Class::getRecordComponents clarification and test update
author chegar
date Fri, 11 Oct 2019 11:27:32 +0100
parents 5fbd6bd20a5b
children e72a614f2a15
files src/java.base/share/classes/java/lang/Class.java src/java.base/share/classes/java/lang/runtime/ObjectMethods.java test/langtools/tools/javac/records/RecordReflectionTest.java
diffstat 3 files changed, 65 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/Class.java	Thu Oct 10 22:23:26 2019 -0400
+++ b/src/java.base/share/classes/java/lang/Class.java	Fri Oct 11 11:27:32 2019 +0100
@@ -2252,10 +2252,13 @@
 
     /**
      * Returns an array containing {@code RecordComponent} objects reflecting all the
-     * declared record components of the record represented by this {@code Class} object
-     *
-     * @return  the array of {@code RecordComponent} objects representing all the
-     *          record components of this record
+     * declared record components of the record represented by this {@code Class} object.
+     * The components are returned in the same order that they are declared in the
+     * record header.
+     *
+     * @return  The array of {@code RecordComponent} objects representing all the
+     *          record components of this record. The array is empty if this class
+     *          is not a record, or if this class is a record with no components.
      * @throws  SecurityException
      *          If a security manager, <i>s</i>, is present and any of the
      *          following conditions is met:
--- a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java	Thu Oct 10 22:23:26 2019 -0400
+++ b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java	Fri Oct 11 11:27:32 2019 +0100
@@ -326,7 +326,7 @@
             case "toString":
                 if (methodType != null && !methodType.equals(MethodType.methodType(String.class, theClass)))
                     throw new IllegalArgumentException("Bad method type: " + methodType);
-                List<String> nameList = List.of(names.split(";"));
+                List<String> nameList = "".equals(names) ? List.of() : List.of(names.split(";"));
                 if (nameList.size() != getterList.size())
                     throw new IllegalArgumentException("Name list and accessor list do not match");
                 handle = makeToString(theClass, getterList, nameList);
--- a/test/langtools/tools/javac/records/RecordReflectionTest.java	Thu Oct 10 22:23:26 2019 -0400
+++ b/test/langtools/tools/javac/records/RecordReflectionTest.java	Fri Oct 11 11:27:32 2019 +0100
@@ -46,6 +46,8 @@
 
     record R3(List<String> ls) {}
 
+    record R4(R1 r1, R2 r2, R3 r3) {}
+
     public void testIsRecord() {
         assertFalse(NoRecord.class.isRecord());
 
@@ -53,23 +55,52 @@
             assertTrue(c.isRecord());
     }
 
-    public void testGetComponentsNoRecord() throws ReflectiveOperationException {
+    public void testGetComponentsNoRecord() {
         assertTrue(NoRecord.class.getRecordComponents().length == 0);
     }
 
-    public void testRecordAccessors() throws ReflectiveOperationException {
-        checkRecordReflection(new R1(), 0, null, null);
-        checkRecordReflection(new R2(1, 2), 2, new Object[]{1, 2}, new String[]{"int", "int"});
-        checkRecordReflection(new R3(List.of("1")), 1, new Object[]{List.of("1")}, new String[]{"java.util.List<java.lang.String>"});
+    @DataProvider(name = "reflectionData")
+    public Object[][] reflectionData() {
+        return new Object[][] {
+            new Object[] { new R1(),
+                           0,
+                           null,
+                           null,
+                           null },
+            new Object[] { new R2(1, 2),
+                           2,
+                           new Object[]{ 1, 2 },
+                           new String[]{ "i", "j" },
+                           new String[]{ "int", "int"} },
+            new Object[] { new R3(List.of("1")),
+                           1,
+                           new Object[]{ List.of("1") },
+                           new String[]{ "ls" },
+                           new String[]{ "java.util.List<java.lang.String>"} },
+            new Object[] { new R4(new R1(), new R2(6, 7), new R3(List.of("s"))),
+                           3,
+                           new Object[]{ new R1(), new R2(6, 7), new R3(List.of("s")) } ,
+                           new String[]{ "r1", "r2", "r3" },
+                           new String[]{ R1.class.toString(), R2.class.toString(), R3.class.toString()} },
+        };
     }
 
-    private void checkRecordReflection(Object recordOb, int numberOfComponents, Object[] values, String[] signatures) throws ReflectiveOperationException {
+    @Test(dataProvider = "reflectionData")
+    public void testRecordReflection(Object recordOb,
+                                     int numberOfComponents,
+                                     Object[] values,
+                                     String[] names,
+                                     String[] signatures)
+        throws ReflectiveOperationException
+    {
         Class<?> recordClass = recordOb.getClass();
         assertTrue(recordClass.isRecord());
         RecordComponent[] recordComponents = recordClass.getRecordComponents();
         assertEquals(recordComponents.length, numberOfComponents);
         int i = 0;
         for (RecordComponent rc : recordComponents) {
+            assertEquals(rc.getName(), names[i]);
+            assertEquals(rc.getType(), rc.getAccessor().getReturnType());
             assertEquals(rc.getAccessor().invoke(recordOb), values[i]);
             assertEquals(rc.getAccessor().getGenericReturnType().toString(), signatures[i],
                          String.format("signature of method \"%s\" different from expected signature \"%s\"",
@@ -78,6 +109,26 @@
         }
     }
 
+    record R5(String... args) {}
+    record R6(long l, String... args) {}
+    record R7(String s1, String s2, String... args) {}
+
+    @DataProvider(name = "varArgsData")
+    public Object[][] varArgsData() {
+        return new Object[][] {
+                new Object[] { new R5("h", "e", "l", "l", "o"),     1 },
+                new Object[] { new R6(5L, "w", "o", "r", "l", "d"), 2 },
+                new Object[] { new R7("s1", "s2", "b", "y", "e") ,  3 },
+        };
+    }
+
+    @Test(dataProvider = "varArgsData")
+    public void testVarArgs(Object recordObj, int numberOfComponents) {
+        assertTrue(recordObj.getClass().isRecord());
+        assertEquals(recordObj.getClass().getRecordComponents().length, numberOfComponents);
+        assertTrue(recordObj.getClass().getRecordComponents()[numberOfComponents-1].isVarArgs());
+    }
+
     @Retention(RetentionPolicy.RUNTIME)
     @Target({ ElementType.RECORD_COMPONENT, ElementType.FIELD })
     @interface RCA {}