1 /*
2  * Copyright (c) 2004, 2013, 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  * @test
26  * @bug 4679556
27  * @summary Tests for duplication of some kind instances
28  * @run main/othervm -Djava.security.manager=allow Test4679556
29  * @author Sergey Malenkov, Mark Davidson, Philip Milne
30  */
31 
32 import java.beans.DefaultPersistenceDelegate;
33 import java.beans.Encoder;
34 import java.beans.Expression;
35 import java.beans.XMLEncoder;
36 
37 /**
38  * Demonstrates the archiver bug, where the XMLEncoder duplicates
39  * the instance of class A because it is required as the target of
40  * a factory method (to produce an instance of class C).
41  * See the output in the file Test.xml for the results and note
42  * the (invalid) forward reference to the instance of class C.
43  *
44  * TO FIX
45  *
46  * Move the first line of the XMLEncoder::mark(Statement method)
47  * to the end of the method.
48  * I.e. replace the mark() method in XMLEncoder with this:
49  * <pre>private void mark(Statement stm) {
50  *     Object[] args = stm.getArguments();
51  *     for (int i = 0; i < args.length; i++) {
52  *         Object arg = args[i];
53  *         mark(arg, true);
54  *     }
55  *     mark(stm.getTarget(), false);
56  * }</pre>
57  *
58  * VALID ARCHIVE (WITH FIX):
59  * <pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
60  * &lt;java version="1.4.0" class="java.beans.XMLDecoder"&gt;
61  *  &lt;object class="TestDuplicates$A"&gt;
62  *   &lt;void id="TestDuplicates$C0" method="createC"/&gt;
63  *   &lt;void property="x"&gt;
64  *    &lt;void property="x"&gt;
65  *     &lt;object idref="TestDuplicates$C0"/&gt;
66  *    &lt;/void&gt;
67  *   &lt;/void&gt;
68  *  &lt;/object&gt;
69  * &lt;/java&gt;</pre>
70  *
71  * INVALID ARCHIVE (WITHOUT FIX):
72  *  &lt;object class="TestDuplicates$A"&gt;
73  *   &lt;void property="x"&gt;
74  *    &lt;void property="x"&gt;
75  *     &lt;void class="TestDuplicates$A"&gt;
76  *      &lt;void property="x"&gt;
77  *       &lt;void property="x"&gt;
78  *        &lt;object idref="TestDuplicates$C0"/&gt;
79  *       &lt;/void&gt;
80  *      &lt;/void&gt;
81  *      &lt;void id="TestDuplicates$C0" method="createC"/&gt;
82  *     &lt;/void&gt;
83  *     &lt;object idref="TestDuplicates$C0"/&gt;
84  *    &lt;/void&gt;
85  *   &lt;/void&gt;
86  *   &lt;void id="TestDuplicates$C0" method="createC"/&gt;
87  *  &lt;/object&gt;
88  * &lt;/java&gt;</pre>
89  */
90 public class Test4679556 extends AbstractTest {
main(String[] args)91     public static void main(String[] args) {
92         new Test4679556().test(true);
93     }
94 
getObject()95     protected Object getObject() {
96         A a = new A();
97         B b = (B) a.getX();
98         b.setX(a.createC());
99         return a;
100     }
101 
getAnotherObject()102     protected Object getAnotherObject() {
103         return new A();
104     }
105 
initialize(XMLEncoder encoder)106     protected void initialize(XMLEncoder encoder) {
107         encoder.setPersistenceDelegate(C.class, new DefaultPersistenceDelegate() {
108             protected Expression instantiate(Object oldInstance, Encoder out) {
109                 C c = (C) oldInstance;
110                 return new Expression(c, c.getX(), "createC", new Object[] {});
111             }
112         });
113     }
114 
115     public static class Base {
116         private Object x;
117 
getX()118         public Object getX() {
119             return this.x;
120         }
121 
setX(Object x)122         public void setX(Object x) {
123             this.x = x;
124         }
125     }
126 
127     public static class A extends Base {
A()128         public A() {
129             setX(new B());
130         }
131 
createC()132         public C createC() {
133             return new C(this);
134         }
135     }
136 
137     public static class B extends Base {
138     }
139 
140     public static class C extends Base {
C(Object x)141         private C(Object x) {
142             setX(x);
143         }
144     }
145 }
146