1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.executor.loader;
17
18 import static org.junit.jupiter.api.Assertions.assertEquals;
19 import static org.junit.jupiter.api.Assertions.assertFalse;
20 import static org.junit.jupiter.api.Assertions.fail;
21
22 import java.io.ByteArrayInputStream;
23 import java.io.ByteArrayOutputStream;
24 import java.io.ObjectInputStream;
25 import java.io.ObjectOutputStream;
26 import java.io.ObjectStreamException;
27 import java.io.Serializable;
28 import java.util.ArrayList;
29
30 import org.apache.ibatis.domain.blog.Author;
31 import org.apache.ibatis.domain.blog.Section;
32 import org.apache.ibatis.executor.ExecutorException;
33 import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
34 import org.apache.ibatis.session.Configuration;
35 import org.junit.jupiter.api.Assertions;
36 import org.junit.jupiter.api.Test;
37
38 public abstract class SerializableProxyTest {
39
40 protected Author author = new Author(999, "someone", "!@#@!#!@#", "someone@somewhere.com", "blah", Section.NEWS);
41
42 static ProxyFactory proxyFactory;
43
44 @Test
45 void shouldKeepGenericTypes() {
46 for (int i = 0; i < 10000; i++) {
47 Author pc = new Author();
48 Author proxy = (Author) proxyFactory.createProxy(pc, new ResultLoaderMap(), new Configuration(),
49 new DefaultObjectFactory(), new ArrayList<>(), new ArrayList<>());
50 proxy.getBio();
51 }
52 }
53
54 @Test
55 void shouldSerializeAProxyForABeanWithDefaultConstructor() throws Exception {
56 Object proxy = proxyFactory.createProxy(author, new ResultLoaderMap(), new Configuration(),
57 new DefaultObjectFactory(), new ArrayList<>(), new ArrayList<>());
58 Object proxy2 = deserialize(serialize((Serializable) proxy));
59 assertEquals(author, proxy2);
60 }
61
62 @Test
63 void shouldSerializeAProxyForABeanWithoutDefaultConstructor() throws Exception {
64 AuthorWithoutDefaultConstructor author = new AuthorWithoutDefaultConstructor(999, "someone", "!@#@!#!@#",
65 "someone@somewhere.com", "blah", Section.NEWS);
66 ArrayList<Class<?>> argTypes = new ArrayList<>();
67 argTypes.add(Integer.class);
68 argTypes.add(String.class);
69 argTypes.add(String.class);
70 argTypes.add(String.class);
71 argTypes.add(String.class);
72 argTypes.add(Section.class);
73 ArrayList<Object> argValues = new ArrayList<>();
74 argValues.add(999);
75 argValues.add("someone");
76 argValues.add("!@#@!#!@#");
77 argValues.add("someone@somewhere.com");
78 argValues.add("blah");
79 argValues.add(Section.NEWS);
80 Object proxy = proxyFactory.createProxy(author, new ResultLoaderMap(), new Configuration(),
81 new DefaultObjectFactory(), argTypes, argValues);
82 Object proxy2 = deserialize(serialize((Serializable) proxy));
83 assertEquals(author, proxy2);
84 }
85
86 @Test
87 void shouldSerializeAProxyForABeanWithoutDefaultConstructorAndUnloadedProperties() throws Exception {
88 AuthorWithoutDefaultConstructor author = new AuthorWithoutDefaultConstructor(999, "someone", "!@#@!#!@#",
89 "someone@somewhere.com", "blah", Section.NEWS);
90 ArrayList<Class<?>> argTypes = new ArrayList<>();
91 argTypes.add(Integer.class);
92 argTypes.add(String.class);
93 argTypes.add(String.class);
94 argTypes.add(String.class);
95 argTypes.add(String.class);
96 argTypes.add(Section.class);
97 ArrayList<Object> argValues = new ArrayList<>();
98 argValues.add(999);
99 argValues.add("someone");
100 argValues.add("!@#@!#!@#");
101 argValues.add("someone@somewhere.com");
102 argValues.add("blah");
103 argValues.add(Section.NEWS);
104 ResultLoaderMap loader = new ResultLoaderMap();
105 loader.addLoader("id", null, null);
106 Object proxy = proxyFactory.createProxy(author, loader, new Configuration(), new DefaultObjectFactory(), argTypes,
107 argValues);
108 Object proxy2 = deserialize(serialize((Serializable) proxy));
109 assertEquals(author, proxy2);
110 }
111
112 @Test
113 void shouldSerizaliceAFullLoadedObjectToOriginalClass() throws Exception {
114 Object proxy = proxyFactory.createProxy(author, new ResultLoaderMap(), new Configuration(),
115 new DefaultObjectFactory(), new ArrayList<>(), new ArrayList<>());
116 Object proxy2 = deserialize(serialize((Serializable) proxy));
117 assertEquals(author.getClass(), proxy2.getClass());
118 }
119
120 @Test
121 void shouldGenerateWriteReplace() throws Exception {
122 try {
123 author.getClass().getDeclaredMethod("writeReplace");
124 fail("Author should not have a writeReplace method");
125 } catch (NoSuchMethodException e) {
126
127 }
128 Object proxy = proxyFactory.createProxy(author, new ResultLoaderMap(), new Configuration(),
129 new DefaultObjectFactory(), new ArrayList<>(), new ArrayList<>());
130 proxy.getClass().getDeclaredMethod("writeReplace");
131 }
132
133 @Test
134 void shouldNotGenerateWriteReplaceItThereIsAlreadyOne() {
135 AuthorWithWriteReplaceMethod beanWithWriteReplace = new AuthorWithWriteReplaceMethod(999, "someone", "!@#@!#!@#",
136 "someone@somewhere.com", "blah", Section.NEWS);
137 try {
138 beanWithWriteReplace.getClass().getDeclaredMethod("writeReplace");
139 } catch (NoSuchMethodException e) {
140 fail("Bean should declare a writeReplace method");
141 }
142 Object proxy = proxyFactory.createProxy(beanWithWriteReplace, new ResultLoaderMap(), new Configuration(),
143 new DefaultObjectFactory(), new ArrayList<>(), new ArrayList<>());
144 Class<?>[] interfaces = proxy.getClass().getInterfaces();
145 boolean ownInterfaceFound = false;
146 for (Class<?> i : interfaces) {
147 if (i.equals(WriteReplaceInterface.class)) {
148 ownInterfaceFound = true;
149 break;
150 }
151 }
152 assertFalse(ownInterfaceFound);
153 }
154
155 @Test
156 void shouldNotCreateAProxyForAFullyLoadedBean() throws Exception {
157 Object proxy = proxyFactory.createProxy(author, new ResultLoaderMap(), new Configuration(),
158 new DefaultObjectFactory(), new ArrayList<>(), new ArrayList<>());
159 Author author2 = (Author) deserialize(serialize((Serializable) proxy));
160 assertEquals(author.getClass(), author2.getClass());
161 }
162
163 @Test
164 void shouldNotLetReadUnloadedPropertyAfterSerialization() throws Exception {
165 ResultLoaderMap loader = new ResultLoaderMap();
166 loader.addLoader("id", null, null);
167 Object proxy = proxyFactory.createProxy(author, loader, new Configuration(), new DefaultObjectFactory(),
168 new ArrayList<>(), new ArrayList<>());
169 Author author2 = (Author) deserialize(serialize((Serializable) proxy));
170 Assertions.assertThrows(ExecutorException.class, author2::getId);
171 }
172
173 @Test
174 void shouldNotLetReadUnloadedPropertyAfterTwoSerializations() throws Exception {
175 ResultLoaderMap loader = new ResultLoaderMap();
176 loader.addLoader("id", null, null);
177 Object proxy = proxyFactory.createProxy(author, loader, new Configuration(), new DefaultObjectFactory(),
178 new ArrayList<>(), new ArrayList<>());
179 Author author2 = (Author) deserialize(serialize(deserialize(serialize((Serializable) proxy))));
180 Assertions.assertThrows(ExecutorException.class, author2::getId);
181 }
182
183 @Test
184 void shouldLetReadALoadedPropertyAfterSerialization() throws Exception {
185 Object proxy = proxyFactory.createProxy(author, new ResultLoaderMap(), new Configuration(),
186 new DefaultObjectFactory(), new ArrayList<>(), new ArrayList<>());
187 byte[] ser = serialize((Serializable) proxy);
188 Author author2 = (Author) deserialize(ser);
189 assertEquals(999, author2.getId());
190 }
191
192 byte[] serialize(Serializable value) throws Exception {
193 try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
194 ObjectOutputStream oos = new ObjectOutputStream(bos)) {
195 oos.writeObject(value);
196 oos.flush();
197 return bos.toByteArray();
198 }
199 }
200
201 Serializable deserialize(byte[] value) throws Exception {
202 try (ByteArrayInputStream bis = new ByteArrayInputStream(value);
203 ObjectInputStream ois = new ObjectInputStream(bis)) {
204 return (Serializable) ois.readObject();
205 }
206 }
207
208 public static class AuthorWithWriteReplaceMethod extends Author {
209
210 public AuthorWithWriteReplaceMethod() {
211 }
212
213 AuthorWithWriteReplaceMethod(Integer id, String username, String password, String email, String bio,
214 Section section) {
215 super(id, username, password, email, bio, section);
216 }
217
218 Object writeReplace() throws ObjectStreamException {
219 return this;
220 }
221 }
222
223 public static class AuthorWithoutDefaultConstructor extends Author {
224
225 AuthorWithoutDefaultConstructor(Integer id, String username, String password, String email, String bio,
226 Section section) {
227 super(id, username, password, email, bio, section);
228 }
229
230 protected Object writeReplace() throws ObjectStreamException {
231 return this;
232 }
233 }
234
235 }