/* * Copyright (c) 2016, 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. * * 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.beans.BeanInfo; import java.beans.BeanProperty; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyChangeListener; import java.beans.PropertyDescriptor; import java.util.Arrays; /** * @test * @bug 8132703 8132163 8133183 8132732 8133184 * @summary Some checks for BeanProperty annotation * @author a.stepanov * @run main BeanPropertyTest */ public class BeanPropertyTest { private final static String DESCRIPTION = "TEST"; private final static boolean BOUND = true; private final static boolean EXPERT = false; private final static boolean HIDDEN = true; private final static boolean PREFERRED = false; private final static boolean REQUIRED = true; private final static boolean UPDATE = false; private final static String V_NAME = "javax.swing.SwingConstants.TOP", V_SHORT = "TOP", V = Integer.toString(javax.swing.SwingConstants.TOP); private final static String DESCRIPTION_2 = "XYZ"; // ---------- test cases ---------- public static class G1 { private final static String TESTCASE = "arbitrary getter name"; private final int x = 0; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public int get1() { return x; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S1 { private final static String TESTCASE = "arbitrary setter name"; private int x; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public void setXXXXX(int v) { x = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class G2 { private final static String TESTCASE = "arbitrary getter name"; private final int x = 0; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public int get() { return x; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S2 { private final static String TESTCASE = "arbitrary setter name"; private int x; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public void set(int v) { x = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class G3 { private final static String TESTCASE = "non-public getter"; private final int x = 0; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) int getX() { return x; } // getter is not public public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S3 { private final static String TESTCASE = "non-public setter"; private int x; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) void setX(int v) { x = v; } // setter is not public public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class G4 { private final static String TESTCASE = "arbitrary getter return type"; private final int x = 0; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public Object getX() { return x; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S4 { private final static String TESTCASE = "arbitrary setter argument type"; private int x; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public void setX(short v) { x = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class G5 { private final static String TESTCASE = "indexed getter"; private int x[] = {1, 2, 3}; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public int getX(int i) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } return x[i]; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S5_1 { private final static String TESTCASE = "indexed setter"; private int x[] = new int[3]; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public void setX(int i, int v) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } x[i] = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S5_2 { private final static String TESTCASE = "indexed setter, value type"; private final Object x[] = new Object[3]; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public void setX(int i, Object v) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } x[i] = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S5_3 { private final static String TESTCASE = "indexed setter + value type + order of arguments"; private final Object x[] = new Object[3]; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public void setX(Object v, int i) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } x[i] = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class G6 { private final static String TESTCASE = "indexed + non-indexed getters"; private int x[] = {1, 2, 3}; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public int getX(int i) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } return x[i]; } public int[] getX() { return x; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S6_1 { private final static String TESTCASE = "indexed + non-indexed setters"; private int x[] = new int[3]; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public void setX(int i, int v) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } x[i] = v; } public void setX(int a[]) { x = Arrays.copyOf(a, a.length); } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S6_2 { private final static String TESTCASE = "indexed + non-indexed setters, value type"; private double x[] = new double[3]; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public void setX(int i, double v) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } x[i] = v; } public void setX(double a[]) { x = Arrays.copyOf(a, a.length); } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class G7 { private final static String TESTCASE = "non-indexed + indexed getters"; private int x[] = {1, 2, 3}; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public int[] getX() { return x; } public int getX(int i) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } return x[i]; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S7 { private final static String TESTCASE = "non-indexed + indexed setters"; private int x[] = new int[3]; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public void setX(int a[]) { x = Arrays.copyOf(a, a.length); } public void setX(int i, int v) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } x[i] = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class G8 { private final static String TESTCASE = "two annotated getters"; private int x[] = {1, 2, 3}; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public int[] getX() { return x; } @BeanProperty( description = DESCRIPTION_2, bound = !BOUND, expert = !EXPERT, hidden = !HIDDEN, preferred = !PREFERRED, required = !REQUIRED, visualUpdate = !UPDATE) public int getX(int i) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } return x[i]; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class S8 { private final static String TESTCASE = "two annotated setters"; private int x[] = new int[3]; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public void setX(int a[]) { x = Arrays.copyOf(a, a.length); } @BeanProperty( description = DESCRIPTION_2, bound = !BOUND, expert = !EXPERT, hidden = !HIDDEN, preferred = !PREFERRED, required = !REQUIRED, visualUpdate = !UPDATE) public void setX(int i, int v) throws IndexOutOfBoundsException { if (i < 0 || i >= x.length) { throw new IndexOutOfBoundsException(); } x[i] = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class GS { private final static String TESTCASE = "both getter and setter are annotated"; private int x; @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public int getX() { return x; } @BeanProperty( description = DESCRIPTION_2, bound = !BOUND, expert = !EXPERT, hidden = !HIDDEN, preferred = !PREFERRED, required = !REQUIRED, visualUpdate = !UPDATE) public void setX(int v) { x = v; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } public static class SG { private final static String TESTCASE = "both setter and getter are annotated"; private int x; @BeanProperty( description = DESCRIPTION_2, bound = !BOUND, expert = !EXPERT, hidden = !HIDDEN, preferred = !PREFERRED, required = !REQUIRED, visualUpdate = !UPDATE) public void setX(int v) { x = v; } @BeanProperty( description = DESCRIPTION, bound = BOUND, expert = EXPERT, hidden = HIDDEN, preferred = PREFERRED, required = REQUIRED, visualUpdate = UPDATE, enumerationValues = {V_NAME}) public int getX() { return x; } public void addPropertyChangeListener(PropertyChangeListener l) {} public void removePropertyChangeListener(PropertyChangeListener l) {} } // ---------- checks ---------- private static boolean check(String what, boolean v, boolean ref) { boolean ok = (v == ref); if (!ok) { System.out.println( "invalid " + what + ": " + v + ", expected: " + ref); } return ok; } private static boolean checkInfo(BeanInfo i) { PropertyDescriptor descriptors[] = i.getPropertyDescriptors(); int nd = descriptors.length; if (nd != 1) { System.out.println("invalid number of descriptors: " + nd); return false; } PropertyDescriptor d = descriptors[0]; String descr = d.getShortDescription(); boolean ok = descr.equals(DESCRIPTION); if (!ok) { System.out.println("invalid description: " + descr + ", expected: " + DESCRIPTION); } ok &= check("isBound", d.isBound(), BOUND); ok &= check("isExpert", d.isExpert(), EXPERT); ok &= check("isHidden", d.isHidden(), HIDDEN); ok &= check("isPreferred", d.isPreferred(), PREFERRED); ok &= check("required", (boolean) d.getValue("required"), REQUIRED); ok &= check("visualUpdate", (boolean) d.getValue("visualUpdate"), UPDATE); Object vals[] = (Object[]) d.getValue("enumerationValues"); if (vals == null) { System.out.println("null enumerationValues"); return false; } boolean okVals = ( (vals.length == 3) && vals[0].toString().equals(V_SHORT) && vals[1].toString().equals(V) && vals[2].toString().equals(V_NAME)); if (!okVals) { System.out.println("invalid enumerationValues"); } return (ok && okVals); } private static boolean checkAlternativeInfo(BeanInfo i) { System.out.println("checking alternative info:"); PropertyDescriptor descriptors[] = i.getPropertyDescriptors(); int nd = descriptors.length; if (nd != 1) { System.out.println("invalid number of descriptors: " + nd); return false; } PropertyDescriptor d = descriptors[0]; String descr = d.getShortDescription(); boolean ok = descr.equals(DESCRIPTION_2); if (!ok) { System.out.println("invalid alternative description: " + descr + ", expected: " + DESCRIPTION_2); } ok &= check("isBound", d.isBound(), !BOUND); ok &= check("isExpert", d.isExpert(), !EXPERT); ok &= check("isHidden", d.isHidden(), !HIDDEN); ok &= check("isPreferred", d.isPreferred(), !PREFERRED); ok &= check("required", (boolean) d.getValue("required"), !REQUIRED); ok &= check("visualUpdate", (boolean) d.getValue("visualUpdate"), !UPDATE); Object vals[] = (Object[]) d.getValue("enumerationValues"); if (vals != null || vals.length > 0) { System.out.println("non-null enumerationValues"); return false; } return ok; } private static boolean checkAlternative(Class c) { return ( c.equals(G8.class) || c.equals(S8.class) || c.equals(GS.class) || c.equals(SG.class)); } // ---------- run tests ---------- public static void main(String[] args) throws Exception { Class classes[] = { G1.class, S1.class, G2.class, S2.class, G3.class, S3.class, G4.class, S4.class, G5.class, S5_1.class, S5_2.class, S5_3.class, G6.class, S6_1.class, S6_2.class, G7.class, S7.class, G8.class, S8.class, GS.class, SG.class, }; boolean passed = true; for (Class c: classes) { java.lang.reflect.Field f = c.getDeclaredField("TESTCASE"); f.setAccessible(true); String descr = f.get(c).toString(); System.out.println("\n" + c.getSimpleName() + " (" + descr + "):"); BeanInfo i; try { i = Introspector.getBeanInfo(c, Object.class); } catch (IntrospectionException e) { throw new RuntimeException(e); } boolean ok = checkInfo(i); if (checkAlternative(c)) { ok |= checkAlternativeInfo(i); } System.out.println(ok ? "OK" : "NOK"); passed = passed && ok; } if (!passed) { throw new RuntimeException("test failed"); } System.out.println("test passed"); } }