1 package com.atlassian.vcache.marshallers;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.ObjectInputStream;
8 import java.io.ObjectOutputStream;
9 import java.io.ObjectStreamClass;
10 import java.io.Serializable;
11 import java.util.Optional;
12 import javax.annotation.Nonnull;
13
14 import com.atlassian.annotations.Internal;
15 import com.atlassian.vcache.Marshaller;
16 import com.atlassian.vcache.MarshallerException;
17
18 import static java.util.Objects.requireNonNull;
19
20
21
22
23
24
25
26
27
28 @Internal
29 class JavaSerializationMarshaller<T extends Serializable> implements Marshaller<T>
30 {
31 private final Class<T> clazz;
32 private final Optional<ClassLoader> loader;
33
34
35
36
37
38 JavaSerializationMarshaller(Class<T> clazz)
39 {
40 this.clazz = requireNonNull(clazz);
41 this.loader = Optional.empty();
42 }
43
44
45
46
47
48 JavaSerializationMarshaller(Class<T> clazz, ClassLoader loader)
49 {
50 this.clazz = requireNonNull(clazz);
51 this.loader = Optional.of(loader);
52 }
53
54 @Nonnull
55 @Override
56 public byte[] marshall(T obj) throws MarshallerException
57 {
58 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
59 try (ObjectOutputStream oos = new ObjectOutputStream(baos))
60 {
61 oos.writeObject(obj);
62 }
63 catch (IOException ioe)
64 {
65 throw new MarshallerException("Unable to marshall", ioe);
66 }
67
68 return baos.toByteArray();
69 }
70
71 @Nonnull
72 @Override
73 public T unmarshall(byte[] raw) throws MarshallerException
74 {
75 final ByteArrayInputStream bais = new ByteArrayInputStream(raw);
76 try (ObjectInputStream ois = createObjectInputStream(bais))
77 {
78 return clazz.cast(ois.readObject());
79 }
80 catch (ClassCastException | ClassNotFoundException | IOException ex)
81 {
82 throw new MarshallerException("Unable to unmarshall", ex);
83 }
84 }
85
86 private ObjectInputStream createObjectInputStream(InputStream istr) throws IOException
87 {
88 return loader.isPresent()
89 ? new ObjectInputStreamWithLoader(istr, loader.get())
90 : new ObjectInputStream(istr);
91 }
92
93 private static class ObjectInputStreamWithLoader extends ObjectInputStream
94 {
95 private final ClassLoader loader;
96
97 public ObjectInputStreamWithLoader(InputStream in, ClassLoader loader) throws IOException
98 {
99 super(in);
100 this.loader = requireNonNull(loader);
101 }
102
103 @Override
104 protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException
105 {
106 return Class.forName(desc.getName(), false, loader);
107 }
108 }
109 }