--- /dev/null 2016-03-31 18:33:52.540182992 +0300 +++ new/test/java/beans/Introspector/BeanPropertyTest.java 2016-04-20 17:15:18.526766951 +0300 @@ -0,0 +1,892 @@ +/* + * 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 8132732 8132973 8154756 8132888 + * @summary Some check 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 G01 { + + 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 S01 { + + 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) {} + } + + // JDK-8132703 + public static class G02 { + + 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) {} + } + + // JDK-8132703 + public static class S02 { + + 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) {} + } + + // JDK-8132703 + public static class G03 { + + 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 GetX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132703 + public static class S03 { + + 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 SetX(int v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132163 + public static class G04 { + + 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) {} + } + + // JDK-8132163 + public static class S04 { + + 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 G05 { + + private final static String TESTCASE = + "annotated getter + 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 int getX() { return x; } + public void setX(short v) { x = v; } + + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132163 + public static class S05 { + + private final static String TESTCASE = + "annotated setter + arbitrary getter return 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(int v) { x = v; } + public Object getX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class G06 { + + private final static String TESTCASE = "indexed getter"; + + private final 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 S06 { + + private final static String TESTCASE = "indexed setter"; + + private final 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 G07 { + + private final static String TESTCASE = + "indexed (annotated) + non-indexed getters"; + + private final 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 S07 { + + private final static String TESTCASE = + "indexed (annotated) + 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) {} + } + + // JDK-8132732 + public static class G08 { + + private final static String TESTCASE = + "non-indexed (annotated) + indexed getters"; + + private final 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) {} + } + + // JDK-8132732 + public static class S08 { + + private final static String TESTCASE = + "non-indexed (annotated) + 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) {} + } + + // JDK-8132732 + public static class G09 { + + private final static String TESTCASE = "two annotated getters"; + + private final 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) {} + } + + // JDK-8132732 + public static class S09 { + + 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 G10 { + + private final static String TESTCASE = + "getter + similarly named field"; + + public int prop, Prop, setProp, getProp; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getProp() { return 123; } + public void setProp(int v) { prop = Prop = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class S10 { + + private final static String TESTCASE = + "setter + similarly named field"; + + public int prop, Prop, setProp, getProp; + + private int x; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public int getProp() { return x; } + public void setProp(int v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class G11 { + + private final static String TESTCASE = + "getter + overloading methods"; + + private final int x = 0, y = 123; + + @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(boolean arg) { return (arg ? x : y); } + public int getX(int ... dummy) { return 0; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8154756 + public static class S11 { + + private final static String TESTCASE = + "setter + overloading methods"; + + private int x; + private final static int V = 123; + + @BeanProperty( + description = DESCRIPTION, + bound = BOUND, + expert = EXPERT, + hidden = HIDDEN, + preferred = PREFERRED, + required = REQUIRED, + visualUpdate = UPDATE, + enumerationValues = {V_NAME}) + public void setX(int v) { x = v; } + public int setX() { return (x = V); } + public void setX(int ... dummy) {} + private void setX(Object ... dummy) {} + + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + + // JDK-8132888 + public static class G12 { + + 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) {} + } + + // JDK-8132888 + public static class S12 { + + 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 getX { + + private final static String TESTCASE = + "class name coincides with getter name"; + + 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; } + public void setX(int v) { x = v; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + public static class setX { + + private final static String TESTCASE = + "class name coincides with 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 setX(int v) { x = v; } + public int getX() { return x; } + + public void addPropertyChangeListener(PropertyChangeListener l) {} + public void removePropertyChangeListener(PropertyChangeListener l) {} + } + + // JDK-8132973 + 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) {} + } + + + + + // ---------- 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) { + + System.out.println("checking 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); + 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(G09.class) || + c.equals(S09.class) || + c.equals(GS.class)); + } + + + // ---------- run test ---------- + + public static void main(String[] args) throws Exception { + + Class cases[] = { + + G01.class, S01.class, + // G02.class, S02.class, // TODO: please update after 8132703 fix + // G03.class, S03.class, // TODO: please update after 8132703 fix + // G04.class, S04.class, // TODO: please update after 8132163 fix + G05.class, // S05.class, // TODO: please update after 8132163 fix + G06.class, S06.class, + G07.class, S07.class, + // G08.class, S08.class, // TODO: please update after 8132732 fix + // G09.class, S09.class, // TODO: please update after 8132732 fix + G10.class, S10.class, + G11.class, // S11.class, // TODO: please update after 8154756 fix + // G12.class, S12.class, // TODO: please update after 8132888 fix or + // remove these cases if it is not an issue + // GS.class // TODO: please update after 8132973 fix + getX.class, setX.class + }; + + boolean passed = true; + + for (Class c: cases) { + + 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("\ntest passed"); + } +}