1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 /*
  26  * @test
  27  * @summary Test reflection of constructors for inline classes
  28  * @run main/othervm -XX:+EnableValhalla InlineConstructorTest
  29  */
  30 
  31 import java.lang.reflect.Constructor;
  32 import java.lang.reflect.Field;
  33 import java.lang.reflect.InaccessibleObjectException;
  34 import java.lang.reflect.Method;
  35 import java.lang.reflect.Modifier;
  36 import java.util.Arrays;
  37 import java.util.Set;
  38 import java.util.stream.Collectors;
  39 
  40 public class InlineConstructorTest {
  41 
  42     // Target test class
  43     static inline class SimpleInline {
  44         public final int x;
  45 
  46         SimpleInline() {
  47             x = -1;
  48         }
  49 
  50         public SimpleInline(int x) {
  51             this.x = x;
  52         }
  53     }
  54 
  55     private final Class<?> c;
  56 
  57     public static void main(String... args) throws Exception {
  58         testSimpleInlineClass();
  59     }
  60 
  61     static void testSimpleInlineClass() throws Exception  {
  62         InlineConstructorTest test = new InlineConstructorTest(SimpleInline.class);
  63         test.constructor();
  64         test.constructors("public InlineConstructorTest$SimpleInline(int)",
  65                 "InlineConstructorTest$SimpleInline()");
  66         test.setAccessible();
  67         test.trySetAccessible();
  68         test.initFactoryNotMethods();
  69     }
  70 
  71     InlineConstructorTest(Class<?> type) throws Exception {
  72         String cn = type.getName();
  73         this.c = Class.forName(cn);
  74 
  75         assertTrue(c.isInlineClass());
  76         assertEquals(c, type);
  77     }
  78 
  79     void constructor() throws Exception {
  80         Constructor<?> ctor = c.getDeclaredConstructor();
  81         Object o = ctor.newInstance();
  82         assertEquals(o.getClass(), c);
  83     }
  84 
  85     // Check that the class has the expected Constructors
  86     void constructors(String... expected) throws Exception {
  87         Constructor<? extends Object>[] cons = c.getDeclaredConstructors();
  88         Set<String> actualSig =
  89                 Arrays.stream(cons).map(Constructor::toString).collect(Collectors.toSet());
  90         Set<String> expectedSig = Set.of(expected);
  91         boolean ok = expectedSig.equals(actualSig);
  92         if (!ok) {
  93             System.out.printf("expected: %s%n", expectedSig);
  94             System.out.printf("declared: %s%n", actualSig);
  95             assertTrue(ok);
  96         }
  97     }
  98 
  99     // Check that the constructor can be set accessible and that the field x can not
 100     void setAccessible() throws Exception {
 101         Constructor<?> ctor = c.getDeclaredConstructor();
 102         ctor.setAccessible(true);
 103         Field field = c.getField("x");
 104         try {
 105             field.setAccessible(true);
 106             throw new RuntimeException("InaccessibleObjectException not thrown");
 107         } catch (InaccessibleObjectException e) {
 108             // IOE is expected
 109         }
 110     }
 111 
 112     // Check that the constructor can be set accessible and that the field x can not
 113     void trySetAccessible() throws Exception {
 114         Constructor<?> ctor = c.getDeclaredConstructor();
 115         assertTrue(ctor.trySetAccessible());
 116         Field field = c.getField("x");
 117         if (field.trySetAccessible()) {
 118             throw new RuntimeException("trySetAccessible should not succeed");
 119         }
 120     }
 121 
 122     // Check that the class does not have a static method with the name <init>
 123     void initFactoryNotMethods() {
 124         Method[] methods = c.getDeclaredMethods();
 125         for (Method m : methods) {
 126             if (Modifier.isStatic(m.getModifiers())) {
 127                 assertFalse(m.getName().equals("<init>"));
 128             }
 129         }
 130     }
 131 
 132     static void assertEquals(Object o1, Object o2) {
 133         if (o1 == o2 || o1.equals(o2))
 134             return;
 135 
 136         throw new AssertionError(o1 + " != " + o2);
 137     }
 138 
 139     static void assertTrue(boolean value) {
 140         if (!value)
 141             throw new AssertionError("expected true");
 142     }
 143 
 144     static void assertFalse(boolean value) {
 145         if (value)
 146             throw new AssertionError("expected false");
 147     }
 148 }