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