Skip to content

Commit ad8e258

Browse files
Lo1ntlo1nt
andauthored
fix: exception when write replace return itself (#112)
* fix: exception when write replace return itself * ut --------- Co-authored-by: lo1nt <[email protected]>
1 parent d1d810a commit ad8e258

File tree

2 files changed

+177
-5
lines changed

2 files changed

+177
-5
lines changed

src/main/java/com/caucho/hessian/io/JavaSerializer.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,16 @@ public void writeObject(Object obj, AbstractHessianOutput out)
146146
try {
147147
if (_writeReplace != null) {
148148
Object repl = _writeReplace.invoke(obj, new Object[0]);
149+
// for those writeReplaces that might return obj itself, no need to replace repl with obj
150+
if (repl != obj) {
149151

150-
out.removeRef(obj);
152+
out.removeRef(obj);
151153

152-
out.writeObject(repl);
154+
out.writeObject(repl);
153155

154-
out.replaceRef(repl, obj);
155-
156-
return;
156+
out.replaceRef(repl, obj);
157+
return;
158+
}
157159
}
158160
} catch (Exception e) {
159161
log.log(Level.FINE, e.toString(), e);
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.caucho.hessian.io;
18+
19+
import org.junit.Assert;
20+
import org.junit.BeforeClass;
21+
import org.junit.Test;
22+
23+
import java.io.ByteArrayInputStream;
24+
import java.io.ByteArrayOutputStream;
25+
import java.io.IOException;
26+
import java.io.Serializable;
27+
28+
/**
29+
*
30+
* @author junyuan
31+
* @version WriteReplaceTest.java, v 0.1 2024-03-20 10:34 junyuan Exp $
32+
*/
33+
public class WriteReplaceTest {
34+
private static SerializerFactory factory;
35+
private static ByteArrayOutputStream os;
36+
37+
@BeforeClass
38+
public static void setUp() {
39+
factory = new SerializerFactory();
40+
os = new ByteArrayOutputStream();
41+
}
42+
43+
@Test
44+
public void TestWriteReplace() throws IOException {
45+
TestObject origin = new TestObject();
46+
origin.setName("testWR");
47+
48+
os.reset();
49+
Hessian2Output output = new Hessian2Output(os);
50+
51+
output.setSerializerFactory(factory);
52+
try {
53+
output.writeObject(origin);
54+
} catch (Exception e) {
55+
Assert.fail("should be no exception");
56+
}
57+
output.flush();
58+
59+
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
60+
Hessian2Input input = new Hessian2Input(is);
61+
input.setSerializerFactory(factory);
62+
TestObject actual = (TestObject) input.readObject();
63+
Assert.assertEquals(actual.name, origin.name);
64+
}
65+
66+
@Test
67+
public void TestWrappedWriteReplace() throws IOException {
68+
WrappedTestObject origin = new WrappedTestObject();
69+
TestObject testObject = new TestObject();
70+
testObject.setName("testWR");
71+
origin.setTestObject(testObject);
72+
73+
TestObjectWriteReplace wrObject = new TestObjectWriteReplace();
74+
wrObject.name = "testProxy";
75+
origin.setWrObject(wrObject);
76+
77+
os.reset();
78+
Hessian2Output output = new Hessian2Output(os);
79+
80+
output.setSerializerFactory(factory);
81+
try {
82+
output.writeObject(origin);
83+
} catch (Exception e) {
84+
Assert.fail("should be no exception");
85+
}
86+
output.flush();
87+
88+
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
89+
Hessian2Input input = new Hessian2Input(is);
90+
input.setSerializerFactory(factory);
91+
WrappedTestObject actual = (WrappedTestObject) input.readObject();
92+
Assert.assertEquals(actual.testObject.name, origin.testObject.name);
93+
Assert.assertEquals(actual.wrObject.name, origin.wrObject.name);
94+
}
95+
96+
private static class WrappedTestObject implements Serializable {
97+
private TestObject testObject;
98+
private TestObjectWriteReplace wrObject;
99+
100+
public TestObject getTestObject() {
101+
return testObject;
102+
}
103+
104+
public void setTestObject(TestObject testObject) {
105+
this.testObject = testObject;
106+
}
107+
108+
public TestObjectWriteReplace getWrObject() {
109+
return wrObject;
110+
}
111+
112+
public void setWrObject(TestObjectWriteReplace wrObject) {
113+
this.wrObject = wrObject;
114+
}
115+
}
116+
117+
// write replace to TestObjectProxy
118+
private static class TestObjectWriteReplace implements Serializable {
119+
private static final long serialVersionUID = 462771763706189820L;
120+
121+
String name;
122+
123+
Object writeReplace() {
124+
TestObjectProxy o = new TestObjectProxy();
125+
o.name = this.name;
126+
return o;
127+
}
128+
}
129+
130+
// read resolve back to TestObjectWriteReplace
131+
private static class TestObjectProxy implements Serializable {
132+
private static final long serialVersionUID = 462771763706189820L;
133+
134+
String name;
135+
136+
Object readResolve() {
137+
TestObjectWriteReplace o = new TestObjectWriteReplace();
138+
o.name = this.name;
139+
return o;
140+
}
141+
}
142+
143+
private static class TestObject implements Serializable {
144+
private static final long serialVersionUID = -452701306050912437L;
145+
146+
String name;
147+
148+
Object writeReplace() {
149+
return this;
150+
}
151+
152+
/**
153+
* Getter method for property <tt>name</tt>.
154+
*
155+
* @return property value of name
156+
*/
157+
public String getName() {
158+
return name;
159+
}
160+
161+
/**
162+
* Setter method for property <tt>name</tt>.
163+
*
164+
* @param name value to be assigned to property name
165+
*/
166+
public void setName(String name) {
167+
this.name = name;
168+
}
169+
}
170+
}

0 commit comments

Comments
 (0)