--- /dev/null 2016-03-31 18:33:52.540182992 +0300 +++ new/test/java/beans/Introspector/BeanPropertyTest.java 2016-04-19 13:43:36.398848384 +0300 @@ -0,0 +1,757 @@ +/* + * 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"); + } +}