1 package be
.nikiroo
.utils
.serial
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
5 import java
.io
.OutputStream
;
7 import be
.nikiroo
.utils
.IOUtils
;
8 import be
.nikiroo
.utils
.streams
.BufferedInputStream
;
9 import be
.nikiroo
.utils
.streams
.NextableInputStream
;
10 import be
.nikiroo
.utils
.streams
.NextableInputStreamStep
;
11 import be
.nikiroo
.utils
.streams
.ReplaceInputStream
;
12 import be
.nikiroo
.utils
.streams
.ReplaceOutputStream
;
15 * A {@link CustomSerializer} supports and generates values in the form:
17 * <li><tt>custom^<i>TYPE</i>^<i>ENCODED_VALUE</i></tt></li>
20 * In this scheme, the values are:
22 * <li><tt>custom</tt>: a fixed keyword</li>
23 * <li><tt>^</tt>: a fixed separator character (the
24 * <tt><i>ENCODED_VALUE</i></tt> can still use it inside its content, though</li>
25 * <li><tt><i>TYPE</i></tt>: the object type of this value</li>
26 * <li><tt><i>ENCODED_VALUE</i></tt>: the custom encoded value</li>
29 * To create a new {@link CustomSerializer}, you are expected to implement the
30 * abstract methods of this class. The rest should be taken care of bythe
35 public abstract class CustomSerializer
{
37 * Generate the custom <tt><i>ENCODED_VALUE</i></tt> from this
40 * The <tt>value</tt> will always be of the supported type.
43 * the {@link OutputStream} to write the value to
45 * the value to serialize
48 * in case of I/O error
50 protected abstract void toStream(OutputStream out
, Object value
)
54 * Regenerate the value from the custom <tt><i>ENCODED_VALUE</i></tt>.
56 * The value in the {@link InputStream} <tt>in</tt> will always be of the
60 * the {@link InputStream} containing the
61 * <tt><i>ENCODED_VALUE</i></tt>
63 * @return the regenerated object
66 * in case of I/O error
68 protected abstract Object
fromStream(InputStream in
) throws IOException
;
71 * Return the supported type name.
73 * It <b>must</b> be the name returned by {@link Object#getClass()
74 * #getCanonicalName()}.
76 * @return the supported class name
78 protected abstract String
getType();
81 * Encode the object into the given {@link OutputStream}.
84 * the builder to append to
86 * the object to encode
89 * in case of I/O error
91 public void encode(OutputStream out
, Object value
) throws IOException
{
92 ReplaceOutputStream replace
= new ReplaceOutputStream(out
, //
93 new String
[] { "\\", "\n" }, //
94 new String
[] { "\\\\", "\\n" });
97 SerialUtils
.write(replace
, "custom^");
98 SerialUtils
.write(replace
, getType());
99 SerialUtils
.write(replace
, "^");
100 toStream(replace
, value
);
102 replace
.close(false);
107 * Decode the value back into the supported object type.
114 * @throws IOException
115 * in case of I/O error
117 public Object
decode(InputStream in
) throws IOException
{
118 ReplaceInputStream replace
= new ReplaceInputStream(in
, //
119 new String
[] { "\\\\", "\\n" }, //
120 new String
[] { "\\", "\n" });
123 NextableInputStream stream
= new NextableInputStream(
124 replace
.open(), new NextableInputStreamStep('^'));
126 if (!stream
.next()) {
127 throw new IOException(
128 "Cannot find the first custom^ element");
131 String custom
= IOUtils
.readSmallStream(stream
);
132 if (!"custom".equals(custom
)) {
133 throw new IOException(
134 "Cannot find the first custom^ element, it is: "
138 if (!stream
.next()) {
139 throw new IOException("Cannot find the second custom^"
140 + getType() + " element");
143 String type
= IOUtils
.readSmallStream(stream
);
144 if (!getType().equals(type
)) {
145 throw new IOException("Cannot find the second custom^"
146 + getType() + " element, it is: custom^" + type
150 if (!stream
.nextAll()) {
151 throw new IOException("Cannot find the third custom^"
152 + getType() + "^value element");
155 return fromStream(stream
);
160 replace
.close(false);
164 /** Use {@link CustomSerializer#isCustom(BufferedInputStream)}. */
166 public static boolean isCustom(String encodedValue
) {
167 int pos1
= encodedValue
.indexOf('^');
168 int pos2
= encodedValue
.indexOf('^', pos1
+ 1);
170 return pos1
>= 0 && pos2
>= 0 && encodedValue
.startsWith("custom^");
173 public static boolean isCustom(BufferedInputStream in
) throws IOException
{
174 return in
.startsWith("custom^");
177 public static String
typeOf(String encodedValue
) {
178 int pos1
= encodedValue
.indexOf('^');
179 int pos2
= encodedValue
.indexOf('^', pos1
+ 1);
180 String type
= encodedValue
.substring(pos1
+ 1, pos2
);