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

wuwen5 / hessian / 17328794241

29 Aug 2025 03:55PM UTC coverage: 68.88% (+0.1%) from 68.748%
17328794241

push

github

web-flow
fix: Fix the issue of parent class fields covering subclasses (#39)

1835 of 2863 branches covered (64.09%)

Branch coverage included in aggregate %.

4212 of 5916 relevant lines covered (71.2%)

3.1 hits per line

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

73.59
hessian2-codec/src/main/java/io/github/wuwen5/hessian/io/JavaSerializer.java
1
/*
2
 * Copyright (c) 2001-2008 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.HessianUnshared;
52
import java.io.IOException;
53
import java.lang.ref.SoftReference;
54
import java.lang.reflect.Field;
55
import java.lang.reflect.InvocationTargetException;
56
import java.lang.reflect.Method;
57
import java.lang.reflect.Modifier;
58
import java.util.ArrayList;
59
import java.util.Collections;
60
import java.util.WeakHashMap;
61
import java.util.logging.Level;
62
import java.util.logging.Logger;
63

64
/**
65
 * Serializing an object for known object types.
66
 */
67
public class JavaSerializer extends AbstractSerializer {
68
    private static final Logger log = Logger.getLogger(JavaSerializer.class.getName());
4✔
69

70
    private static final WeakHashMap<Class<?>, SoftReference<JavaSerializer>> SERIALIZER_MAP = new WeakHashMap<>();
5✔
71

72
    private Field[] fields;
73
    private FieldSerializer[] fieldSerializers;
74

75
    private Object writeReplaceFactory;
76
    private final Method writeReplace;
77

78
    public JavaSerializer(Class<?> cl) {
2✔
79
        introspect(cl);
3✔
80

81
        writeReplace = getWriteReplace(cl);
4✔
82

83
        if (writeReplace != null) {
3✔
84
            writeReplace.setAccessible(true);
4✔
85
        }
86
    }
1✔
87

88
    public static Serializer create(Class<?> cl) {
89
        synchronized (SERIALIZER_MAP) {
4✔
90
            SoftReference<JavaSerializer> baseRef = SERIALIZER_MAP.get(cl);
5✔
91

92
            JavaSerializer base = baseRef != null ? baseRef.get() : null;
4!
93

94
            if (base == null) {
2!
95
                if (cl.isAnnotationPresent(HessianUnshared.class)) {
4!
96
                    base = new JavaUnsharedSerializer(cl);
×
97
                } else {
98
                    base = new JavaSerializer(cl);
5✔
99
                }
100

101
                baseRef = new SoftReference<>(base);
5✔
102
                SERIALIZER_MAP.put(cl, baseRef);
5✔
103
            }
104

105
            return base;
4✔
106
        }
107
    }
108

109
    protected void introspect(Class<?> cl) {
110
        if (writeReplace != null) {
3!
111
            writeReplace.setAccessible(true);
×
112
        }
113

114
        ArrayList<Field> primitiveFields = new ArrayList<>();
4✔
115
        ArrayList<Field> compoundFields = new ArrayList<>();
4✔
116

117
        for (; cl != null; cl = cl.getSuperclass()) {
6✔
118
            for (Field field : cl.getDeclaredFields()) {
17✔
119
                if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
8✔
120
                    continue;
1✔
121
                }
122

123
                // XXX: could parameterize the handler to only deal with public
124
                field.setAccessible(true);
3✔
125

126
                if (field.getType().isPrimitive()
5✔
127
                        || (field.getType().getName().startsWith("java.lang.")
6✔
128
                                && !field.getType().equals(Object.class))) {
4✔
129
                    primitiveFields.add(field);
5✔
130
                } else {
131
                    compoundFields.add(field);
4✔
132
                }
133
            }
134
        }
135

136
        ArrayList<Field> fieldArrayList = new ArrayList<>();
4✔
137
        fieldArrayList.addAll(primitiveFields);
4✔
138
        fieldArrayList.addAll(compoundFields);
4✔
139
        Collections.reverse(fieldArrayList);
2✔
140

141
        this.fields = new Field[fieldArrayList.size()];
5✔
142
        fieldArrayList.toArray(this.fields);
5✔
143

144
        fieldSerializers = new FieldSerializer[this.fields.length];
6✔
145

146
        for (int i = 0; i < this.fields.length; i++) {
9✔
147
            fieldSerializers[i] = getFieldSerializer(this.fields[i].getType());
10✔
148
        }
149
    }
1✔
150

151
    /**
152
     * Returns the writeReplace method
153
     */
154
    protected static Method getWriteReplace(Class<?> cl) {
155
        for (; cl != null; cl = cl.getSuperclass()) {
6✔
156
            Method[] methods = cl.getDeclaredMethods();
3✔
157

158
            for (Method method : methods) {
16✔
159
                if ("writeReplace".equals(method.getName()) && method.getParameterTypes().length == 0) {
9!
160
                    return method;
2✔
161
                }
162
            }
163
        }
164

165
        return null;
2✔
166
    }
167

168
    /**
169
     * Returns the writeReplace method
170
     */
171
    protected Method getWriteReplace(Class<?> cl, Class<?> param) {
172
        for (; cl != null; cl = cl.getSuperclass()) {
×
173
            for (Method method : cl.getDeclaredMethods()) {
×
174
                if ("writeReplace".equals(method.getName())
×
175
                        && method.getParameterTypes().length == 1
×
176
                        && param.equals(method.getParameterTypes()[0])) {
×
177
                    return method;
×
178
                }
179
            }
180
        }
181

182
        return null;
×
183
    }
184

185
    @Override
186
    public void writeObject(Object obj, AbstractHessianEncoder out) throws IOException {
187
        if (out.addRef(obj)) {
4!
188
            return;
×
189
        }
190

191
        Class<?> cl = obj.getClass();
3✔
192

193
        try {
194
            if (writeReplace != null) {
3✔
195
                Object repl;
196

197
                if (writeReplaceFactory != null) {
3!
198
                    repl = writeReplace.invoke(writeReplaceFactory, obj);
×
199
                } else {
200
                    repl = writeReplace.invoke(obj);
7✔
201
                }
202

203
                // hessian/3a5a
204
                int ref = out.writeObjectBegin(cl.getName());
5✔
205

206
                if (ref < -1) {
3!
207
                    writeObject10(repl, out);
×
208
                } else {
209
                    if (ref == -1) {
3!
210
                        writeDefinition20(out);
3✔
211
                        out.writeObjectBegin(cl.getName());
5✔
212
                    }
213

214
                    writeInstance(repl, out);
4✔
215
                }
216

217
                return;
1✔
218
            }
219
        } catch (InvocationTargetException | IllegalAccessException e) {
×
220
            throw new IllegalStateException(e);
×
221
        }
1✔
222

223
        int ref = out.writeObjectBegin(cl.getName());
5✔
224

225
        if (ref < -1) {
3!
226
            writeObject10(obj, out);
×
227
        } else {
228
            if (ref == -1) {
3✔
229
                writeDefinition20(out);
3✔
230
                out.writeObjectBegin(cl.getName());
5✔
231
            }
232

233
            writeInstance(obj, out);
4✔
234
        }
235
    }
1✔
236

237
    @Override
238
    protected void writeObject10(Object obj, AbstractHessianEncoder out) throws IOException {
239
        for (int i = 0; i < fields.length; i++) {
×
240
            Field field = fields[i];
×
241

242
            out.writeString(field.getName());
×
243

244
            fieldSerializers[i].serialize(out, obj, field);
×
245
        }
246

247
        out.writeMapEnd();
×
248
    }
×
249

250
    private void writeDefinition20(AbstractHessianEncoder out) throws IOException {
251
        out.writeClassFieldLength(fields.length);
5✔
252

253
        for (Field field : fields) {
17✔
254
            out.writeString(field.getName());
4✔
255
        }
256
    }
1✔
257

258
    @Override
259
    public void writeInstance(Object obj, AbstractHessianEncoder out) throws IOException {
260
        try {
261
            for (int i = 0; i < fields.length; i++) {
9✔
262
                Field field = fields[i];
5✔
263

264
                fieldSerializers[i].serialize(out, obj, field);
8✔
265
            }
266
        } catch (RuntimeException e) {
×
267
            throw new IllegalStateException(
×
268
                    e.getMessage() + "\n class: " + obj.getClass().getName() + " (object=" + obj + ")", e);
×
269
        } catch (IOException e) {
×
270
            throw new IOExceptionWrapper(
×
271
                    e.getMessage() + "\n class: " + obj.getClass().getName() + " (object=" + obj + ")", e);
×
272
        }
1✔
273
    }
1✔
274

275
    private static FieldSerializer getFieldSerializer(Class<?> type) {
276
        if (int.class.equals(type) || byte.class.equals(type) || short.class.equals(type)) {
12✔
277
            return IntFieldSerializer.SER;
2✔
278
        } else if (long.class.equals(type)) {
4✔
279
            return LongFieldSerializer.SER;
2✔
280
        } else if (double.class.equals(type) || float.class.equals(type)) {
8✔
281
            return DoubleFieldSerializer.SER;
2✔
282
        } else if (boolean.class.equals(type)) {
4✔
283
            return BooleanFieldSerializer.SER;
2✔
284
        } else if (String.class.equals(type)) {
4✔
285
            return StringFieldSerializer.SER;
2✔
286
        } else if (java.util.Date.class.equals(type)
6✔
287
                || java.sql.Date.class.equals(type)
4✔
288
                || java.sql.Timestamp.class.equals(type)
4✔
289
                || java.sql.Time.class.equals(type)) {
2✔
290
            return DateFieldSerializer.SER;
2✔
291
        } else {
292
            return FieldSerializer.SER;
2✔
293
        }
294
    }
295

296
    static class FieldSerializer {
3✔
297
        static final FieldSerializer SER = new FieldSerializer();
5✔
298

299
        void serialize(AbstractHessianEncoder out, Object obj, Field field) throws IOException {
300
            Object value = null;
2✔
301

302
            try {
303
                value = field.get(obj);
4✔
304
            } catch (IllegalAccessException e) {
×
305
                log.log(Level.FINE, e.toString(), e);
×
306
            }
1✔
307

308
            try {
309
                out.writeObject(value);
3✔
310
            } catch (RuntimeException e) {
×
311
                throw new IllegalStateException(
×
312
                        e.getMessage() + "\n field: "
×
313
                                + field.getDeclaringClass().getName()
×
314
                                + '.' + field.getName(),
×
315
                        e);
316
            } catch (IOException e) {
×
317
                throw new IOExceptionWrapper(
×
318
                        e.getMessage() + "\n field: "
×
319
                                + field.getDeclaringClass().getName()
×
320
                                + '.' + field.getName(),
×
321
                        e);
322
            }
1✔
323
        }
1✔
324
    }
325

326
    static class BooleanFieldSerializer extends FieldSerializer {
3✔
327
        static final FieldSerializer SER = new BooleanFieldSerializer();
5✔
328

329
        @Override
330
        void serialize(AbstractHessianEncoder out, Object obj, Field field) throws IOException {
331
            boolean value = false;
2✔
332

333
            try {
334
                value = field.getBoolean(obj);
4✔
335
            } catch (IllegalAccessException e) {
×
336
                log.log(Level.FINE, e.toString(), e);
×
337
            }
1✔
338

339
            out.writeBoolean(value);
3✔
340
        }
1✔
341
    }
342

343
    static class IntFieldSerializer extends FieldSerializer {
3✔
344
        static final FieldSerializer SER = new IntFieldSerializer();
5✔
345

346
        @Override
347
        void serialize(AbstractHessianEncoder out, Object obj, Field field) throws IOException {
348
            int value = 0;
2✔
349

350
            try {
351
                value = field.getInt(obj);
4✔
352
            } catch (IllegalAccessException e) {
×
353
                log.log(Level.FINE, e.toString(), e);
×
354
            }
1✔
355

356
            out.writeInt(value);
3✔
357
        }
1✔
358
    }
359

360
    static class LongFieldSerializer extends FieldSerializer {
3✔
361
        static final FieldSerializer SER = new LongFieldSerializer();
5✔
362

363
        @Override
364
        void serialize(AbstractHessianEncoder out, Object obj, Field field) throws IOException {
365
            long value = 0;
2✔
366

367
            try {
368
                value = field.getLong(obj);
4✔
369
            } catch (IllegalAccessException e) {
×
370
                log.log(Level.FINE, e.toString(), e);
×
371
            }
1✔
372

373
            out.writeLong(value);
3✔
374
        }
1✔
375
    }
376

377
    static class DoubleFieldSerializer extends FieldSerializer {
3✔
378
        static final FieldSerializer SER = new DoubleFieldSerializer();
5✔
379

380
        @Override
381
        void serialize(AbstractHessianEncoder out, Object obj, Field field) throws IOException {
382
            double value = 0;
2✔
383

384
            try {
385
                value = field.getDouble(obj);
4✔
386
            } catch (IllegalAccessException e) {
×
387
                log.log(Level.FINE, e.toString(), e);
×
388
            }
1✔
389

390
            out.writeDouble(value);
3✔
391
        }
1✔
392
    }
393

394
    static class StringFieldSerializer extends FieldSerializer {
3✔
395
        static final FieldSerializer SER = new StringFieldSerializer();
5✔
396

397
        @Override
398
        void serialize(AbstractHessianEncoder out, Object obj, Field field) throws IOException {
399
            String value = null;
2✔
400

401
            try {
402
                value = (String) field.get(obj);
5✔
403
            } catch (IllegalAccessException e) {
×
404
                log.log(Level.FINE, e.toString(), e);
×
405
            }
1✔
406

407
            out.writeString(value);
3✔
408
        }
1✔
409
    }
410

411
    static class DateFieldSerializer extends FieldSerializer {
3✔
412
        static final FieldSerializer SER = new DateFieldSerializer();
5✔
413

414
        @Override
415
        void serialize(AbstractHessianEncoder out, Object obj, Field field) throws IOException {
416
            java.util.Date value = null;
2✔
417

418
            try {
419
                value = (java.util.Date) field.get(obj);
5✔
420
            } catch (IllegalAccessException e) {
×
421
                log.log(Level.FINE, e.toString(), e);
×
422
            }
1✔
423

424
            if (value == null) {
2!
425
                out.writeNull();
×
426
            } else {
427
                out.writeUTCDate(value.getTime());
4✔
428
            }
429
        }
1✔
430
    }
431
}
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