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
.NextableInputStream
;
9 import be
.nikiroo
.utils
.streams
.NextableInputStreamStep
;
10 import be
.nikiroo
.utils
.streams
.ReplaceInputStream
;
11 import be
.nikiroo
.utils
.streams
.ReplaceOutputStream
;
14 * A {@link CustomSerializer} supports and generates values in the form:
16 * <li><tt>custom^<i>TYPE</i>^<i>ENCODED_VALUE</i></tt></li>
19 * In this scheme, the values are:
21 * <li><tt>custom</tt>: a fixed keyword</li>
22 * <li><tt>^</tt>: a fixed separator character (the
23 * <tt><i>ENCODED_VALUE</i></tt> can still use it inside its content, though</li>
24 * <li><tt><i>TYPE</i></tt>: the object type of this value</li>
25 * <li><tt><i>ENCODED_VALUE</i></tt>: the custom encoded value</li>
28 * To create a new {@link CustomSerializer}, you are expected to implement the
29 * abstract methods of this class. The rest should be taken care of bythe
34 public abstract class CustomSerializer
{
36 * Generate the custom <tt><i>ENCODED_VALUE</i></tt> from this
39 * The <tt>value</tt> will always be of the supported type.
42 * the {@link OutputStream} to write the value to
44 * the value to serialize
47 * in case of I/O error
49 protected abstract void toStream(OutputStream out
, Object value
)
53 * Regenerate the value from the custom <tt><i>ENCODED_VALUE</i></tt>.
55 * The value in the {@link InputStream} <tt>in</tt> will always be of the
59 * the {@link InputStream} containing the
60 * <tt><i>ENCODED_VALUE</i></tt>
62 * @return the regenerated object
65 * in case of I/O error
67 protected abstract Object
fromStream(InputStream in
) throws IOException
;
70 * Return the supported type name.
72 * It <b>must</b> be the name returned by {@link Object#getClass()
73 * #getCanonicalName()}.
75 * @return the supported class name
77 protected abstract String
getType();
80 * Encode the object into the given {@link OutputStream}.
83 * the builder to append to
85 * the object to encode
88 * in case of I/O error
90 public void encode(OutputStream out
, Object value
) throws IOException
{
91 ReplaceOutputStream replace
= new ReplaceOutputStream(out
, //
92 new String
[] { "\\", "\n" }, //
93 new String
[] { "\\\\", "\\n" });
96 SerialUtils
.write(replace
, "custom^");
97 SerialUtils
.write(replace
, getType());
98 SerialUtils
.write(replace
, "^");
99 toStream(replace
, value
);
101 replace
.close(false);
106 * Decode the value back into the supported object type.
113 * @throws IOException
114 * in case of I/O error
116 public Object
decode(InputStream in
) throws IOException
{
117 ReplaceInputStream replace
= new ReplaceInputStream(in
, //
118 new String
[] { "\\\\", "\\n" }, //
119 new String
[] { "\\", "\n" });
122 NextableInputStream stream
= new NextableInputStream(
123 replace
.open(), new NextableInputStreamStep('^'));
125 if (!stream
.next()) {
126 throw new IOException(
127 "Cannot find the first custom^ element");
130 String custom
= IOUtils
.readSmallStream(stream
);
131 if (!"custom".equals(custom
)) {
132 throw new IOException(
133 "Cannot find the first custom^ element, it is: "
137 if (!stream
.next()) {
138 throw new IOException("Cannot find the second custom^"
139 + getType() + " element");
142 String type
= IOUtils
.readSmallStream(stream
);
143 if (!getType().equals(type
)) {
144 throw new IOException("Cannot find the second custom^"
145 + getType() + " element, it is: custom^" + type
149 if (!stream
.nextAll()) {
150 throw new IOException("Cannot find the third custom^"
151 + getType() + "^value element");
154 return fromStream(stream
);
159 replace
.close(false);
163 public static boolean isCustom(String encodedValue
) {
164 int pos1
= encodedValue
.indexOf('^');
165 int pos2
= encodedValue
.indexOf('^', pos1
+ 1);
167 return pos1
>= 0 && pos2
>= 0 && encodedValue
.startsWith("custom^");
170 public static String
typeOf(String encodedValue
) {
171 int pos1
= encodedValue
.indexOf('^');
172 int pos2
= encodedValue
.indexOf('^', pos1
+ 1);
173 String type
= encodedValue
.substring(pos1
+ 1, pos2
);
178 public static String
contentOf(String encodedValue
) {
179 int pos1
= encodedValue
.indexOf('^');
180 int pos2
= encodedValue
.indexOf('^', pos1
+ 1);
181 String encodedContent
= encodedValue
.substring(pos2
+ 1);
183 return encodedContent
;