• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wuwen5 / hessian / 18043144273

25 Sep 2025 12:46AM UTC coverage: 71.311% (+0.2%) from 71.118%
18043144273

push

github

web-flow
Refactor JavaSerializer, UnsafeSerializer, and BeanSerializer to eliminate code duplication (#57)

* Initial plan

* Refactor JavaSerializer and UnsafeSerializer to use FieldBasedSerializer base class

Co-authored-by: wuwen5 <5037807+wuwen5@users.noreply.github.com>

* Complete refactoring - consolidate writeReplace methods and fix module access

Co-authored-by: wuwen5 <5037807+wuwen5@users.noreply.github.com>

* Address code review feedback: move setAccessible to JavaSerializer only, remove writeObject10 from base classes

Co-authored-by: wuwen5 <5037807+wuwen5@users.noreply.github.com>

* Refactor JavaSerializer to reuse parent introspection and remove unused writeFieldValue method

Co-authored-by: wuwen5 <5037807+wuwen5@users.noreply.github.com>

* Remove unused writeObject10 methods and writeReplaceFactory field

Co-authored-by: wuwen5 <5037807+wuwen5@users.noreply.github.com>

* Rename writeReplace field to writeReplaceMethod to avoid confusion with superclass method

Co-authored-by: wuwen5 <5037807+wuwen5@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wuwen5 <5037807+wuwen5@users.noreply.github.com>

1724 of 2605 branches covered (66.18%)

Branch coverage included in aggregate %.

4152 of 5635 relevant lines covered (73.68%)

3.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

40.54
hessian2-codec/src/main/java/io/github/wuwen5/hessian/io/AbstractSerializer.java
1
/*
2
 * Copyright (c) 2001-2004 Caucho Technology, Inc.  All rights reserved.
3
 *
4
 * The Apache Software License, Version 1.1
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 *
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in
15
 *    the documentation and/or other materials provided with the
16
 *    distribution.
17
 *
18
 * 3. The end-user documentation included with the redistribution, if
19
 *    any, must include the following acknowlegement:
20
 *       "This product includes software developed by the
21
 *        Caucho Technology (http://www.caucho.com/)."
22
 *    Alternately, this acknowlegement may appear in the software itself,
23
 *    if and wherever such third-party acknowlegements normally appear.
24
 *
25
 * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
26
 *    endorse or promote products derived from this software without prior
27
 *    written permission. For written permission, please contact
28
 *    info@caucho.com.
29
 *
30
 * 5. Products derived from this software may not be called "Resin"
31
 *    nor may "Resin" appear in their names without prior written
32
 *    permission of Caucho Technology.
33
 *
34
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
35
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37
 * DISCLAIMED.  IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
38
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
39
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
40
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
43
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
44
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45
 *
46
 * @author Scott Ferguson
47
 */
48

49
package io.github.wuwen5.hessian.io;
50

51
import io.github.wuwen5.hessian.HessianException;
52
import java.io.IOException;
53
import java.lang.reflect.InvocationTargetException;
54
import java.lang.reflect.Method;
55
import lombok.extern.slf4j.Slf4j;
56

57
/**
58
 * Serializing an object.
59
 */
60
@Slf4j
3✔
61
public abstract class AbstractSerializer implements HessianSerializer {
3✔
62
    public static final NullSerializer NULL = new NullSerializer();
5✔
63

64
    /**
65
     * Writes the object.
66
     * @param obj the object to serialize
67
     * @param out hessian encoder
68
     * @throws IOException if an error occurs
69
     */
70
    @Override
71
    public void writeObject(Object obj, AbstractHessianEncoder out) throws IOException {
72
        if (out.addRef(obj)) {
×
73
            return;
×
74
        }
75

76
        try {
77
            Object replace = writeReplace(obj);
×
78

79
            if (replace != null) {
×
80

81
                out.writeObject(replace);
×
82

83
                out.replaceRef(replace, obj);
×
84

85
                return;
×
86
            }
87
        } catch (RuntimeException e) {
×
88
            throw e;
×
89
        } catch (Exception e) {
×
90
            throw new HessianException(e);
×
91
        }
×
92

93
        Class<?> cl = getClass(obj);
×
94

95
        int ref = out.writeObjectBegin(cl.getName());
×
96

97
        if (ref == -1) {
×
98
            writeDefinition20(cl, out);
×
99

100
            out.writeObjectBegin(cl.getName());
×
101
        }
102

103
        writeInstance(obj, out);
×
104
    }
×
105

106
    /**
107
     * Shared writeReplace method discovery for all serializers
108
     */
109
    protected static Method getWriteReplace(Class<?> cl) {
110
        for (; cl != null; cl = cl.getSuperclass()) {
6✔
111
            Method[] methods = cl.getDeclaredMethods();
3✔
112

113
            for (Method method : methods) {
16✔
114
                if ("writeReplace".equals(method.getName()) && method.getParameterTypes().length == 0) {
9!
115
                    return method;
2✔
116
                }
117
            }
118
        }
119

120
        return null;
2✔
121
    }
122

123
    /**
124
     * Shared writeReplace method discovery with parameter for all serializers
125
     */
126
    protected static Method getWriteReplace(Class<?> cl, Class<?> param) {
127
        for (; cl != null; cl = cl.getSuperclass()) {
×
128
            for (Method method : cl.getDeclaredMethods()) {
×
129
                if ("writeReplace".equals(method.getName())
×
130
                        && method.getParameterTypes().length == 1
×
131
                        && param.equals(method.getParameterTypes()[0])) {
×
132
                    return method;
×
133
                }
134
            }
135
        }
136

137
        return null;
×
138
    }
139

140
    @SuppressWarnings("unused")
141
    protected Object writeReplace(Object obj) {
142
        return null;
×
143
    }
144

145
    protected Class<?> getClass(Object obj) {
146
        return obj.getClass();
×
147
    }
148

149
    protected void writeDefinition20(Class<?> cl, AbstractHessianEncoder out) throws IOException {
150
        throw new UnsupportedOperationException(getClass().getName());
×
151
    }
152

153
    protected void writeInstance(Object obj, AbstractHessianEncoder out) throws IOException {
154
        throw new UnsupportedOperationException(getClass().getName());
×
155
    }
156

157
    /**
158
     * The NullSerializer exists as a marker for the factory classes so
159
     * they save a null result.
160
     */
161
    static final class NullSerializer extends AbstractSerializer {
3✔
162
        @Override
163
        public void writeObject(Object obj, AbstractHessianEncoder out) throws IOException {
164
            throw new IllegalStateException(getClass().getName());
×
165
        }
166
    }
167

168
    enum MethodSerializer {
32✔
169

170
        /**
171
         * Default method serializer
172
         */
173
        DEFAULT {
11✔
174
            @Override
175
            void serialize(AbstractHessianEncoder out, Object obj, Method method) {
176
                Object value = null;
×
177

178
                try {
179
                    value = method.invoke(obj);
×
180
                } catch (InvocationTargetException e) {
×
181
                    throw error(method, e.getCause());
×
182
                } catch (IllegalAccessException e) {
×
183
                    log.debug(e.toString(), e);
×
184
                }
×
185

186
                try {
187
                    out.writeObject(value);
×
188
                } catch (Exception e) {
×
189
                    throw error(method, e);
×
190
                }
×
191
            }
×
192
        },
193
        /**
194
         * Boolean method serializer
195
         */
196
        BOOLEAN {
11✔
197
            @Override
198
            void serialize(AbstractHessianEncoder out, Object obj, Method method) throws IOException {
199
                boolean value = false;
2✔
200
                try {
201
                    value = (Boolean) method.invoke(obj);
8✔
202
                } catch (InvocationTargetException e) {
×
203
                    throw error(method, e.getCause());
×
204
                } catch (IllegalAccessException e) {
×
205
                    log.debug(e.toString(), e);
×
206
                }
1✔
207
                out.writeBoolean(value);
3✔
208
            }
1✔
209
        },
210
        INT {
11✔
211
            @Override
212
            void serialize(AbstractHessianEncoder out, Object obj, Method method) throws IOException {
213
                int value = 0;
2✔
214

215
                try {
216
                    value = Integer.parseInt(method.invoke(obj).toString());
8✔
217
                } catch (InvocationTargetException e) {
×
218
                    throw error(method, e.getCause());
×
219
                } catch (IllegalAccessException e) {
×
220
                    log.debug(e.toString(), e);
×
221
                }
1✔
222

223
                out.writeInt(value);
3✔
224
            }
1✔
225
        },
226
        LONG {
11✔
227
            @Override
228
            void serialize(AbstractHessianEncoder out, Object obj, Method method) throws IOException {
229
                long value = 0;
2✔
230

231
                try {
232
                    value = (Long) method.invoke(obj);
8✔
233
                } catch (InvocationTargetException e) {
×
234
                    throw error(method, e.getCause());
×
235
                } catch (IllegalAccessException e) {
×
236
                    log.debug(e.toString(), e);
×
237
                }
1✔
238

239
                out.writeLong(value);
3✔
240
            }
1✔
241
        },
242
        DOUBLE {
11✔
243
            @Override
244
            void serialize(AbstractHessianEncoder out, Object obj, Method method) throws IOException {
245
                double value = 0;
2✔
246

247
                try {
248
                    value = Double.parseDouble(method.invoke(obj).toString());
8✔
249
                } catch (InvocationTargetException e) {
×
250
                    throw error(method, e.getCause());
×
251
                } catch (IllegalAccessException e) {
×
252
                    log.debug(e.toString(), e);
×
253
                }
1✔
254

255
                out.writeDouble(value);
3✔
256
            }
1✔
257
        },
258
        STRING {
11✔
259
            @Override
260
            void serialize(AbstractHessianEncoder out, Object obj, Method method) throws IOException {
261
                String value = null;
2✔
262

263
                try {
264
                    value = (String) method.invoke(obj);
7✔
265
                } catch (InvocationTargetException e) {
×
266
                    throw error(method, e.getCause());
×
267
                } catch (IllegalAccessException e) {
×
268
                    log.debug(e.toString(), e);
×
269
                }
1✔
270

271
                out.writeString(value);
3✔
272
            }
1✔
273
        },
274
        DATE {
11✔
275
            @Override
276
            void serialize(AbstractHessianEncoder out, Object obj, Method method) throws IOException {
277
                java.util.Date value = null;
×
278

279
                try {
280
                    value = (java.util.Date) method.invoke(obj);
×
281
                } catch (InvocationTargetException e) {
×
282
                    throw error(method, e.getCause());
×
283
                } catch (IllegalAccessException e) {
×
284
                    log.debug(e.toString(), e);
×
285
                }
×
286

287
                if (value == null) {
×
288
                    out.writeNull();
×
289
                } else {
290
                    out.writeUTCDate(value.getTime());
×
291
                }
292
            }
×
293
        };
294

295
        /**
296
         * serialize
297
         * @param out hessian encoder
298
         * @param obj the object to serialize
299
         * @param method the read method to be called
300
         * @throws IOException if an error occurs
301
         */
302
        abstract void serialize(AbstractHessianEncoder out, Object obj, Method method) throws IOException;
303

304
        static RuntimeException error(Method method, Throwable cause) {
305
            String msg = (method.getDeclaringClass().getSimpleName() + "." + method.getName() + "(): " + cause);
×
306

307
            return new HessianMethodSerializationException(msg, cause);
×
308
        }
309
    }
310

311
    static MethodSerializer getMethodSerializer(Class<?> type) {
312
        if (int.class.equals(type) || byte.class.equals(type) || short.class.equals(type)) {
12✔
313
            return MethodSerializer.INT;
2✔
314
        } else if (long.class.equals(type)) {
4✔
315
            return MethodSerializer.LONG;
2✔
316
        } else if (double.class.equals(type) || float.class.equals(type)) {
8✔
317
            return MethodSerializer.DOUBLE;
2✔
318
        } else if (boolean.class.equals(type)) {
4✔
319
            return MethodSerializer.BOOLEAN;
2✔
320
        } else if (String.class.equals(type)) {
4!
321
            return MethodSerializer.STRING;
2✔
322
        } else if (java.util.Date.class.equals(type)
×
323
                || java.sql.Date.class.equals(type)
×
324
                || java.sql.Timestamp.class.equals(type)
×
325
                || java.sql.Time.class.equals(type)) {
×
326
            return MethodSerializer.DATE;
×
327
        } else {
328
            return MethodSerializer.DEFAULT;
×
329
        }
330
    }
331
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc