Skip to content

Commit 2f7977c

Browse files
Merge branch 'feature-appendable-toString' into dev
2 parents 5385b4e + ded1c7f commit 2f7977c

File tree

22 files changed

+285
-217
lines changed

22 files changed

+285
-217
lines changed

SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import static java.lang.Boolean.*;
44
import static org.ugp.serialx.Utils.equalsLowerCase;
55

6+
import java.io.IOException;
7+
68
/**
79
* This converter is capable of converting {@link String}.
810
* Its case insensitive!
@@ -76,10 +78,14 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args)
7678
}
7779

7880
@Override
79-
public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args)
81+
public Appendable toString(Appendable source, ParserRegistry myHomeRegistry, Object obj, Object... args) throws IOException
8082
{
8183
if (obj instanceof Boolean)
82-
return isShorten() ? (boolean) obj ? "T" : "F" : (boolean) obj ? "true" : "false";
84+
{
85+
if (isShorten())
86+
return source.append((boolean) obj ? 'T' : 'F');
87+
return source.append((boolean) obj ? "true" : "false");
88+
}
8389
return CONTINUE;
8490
}
8591

SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.ugp.serialx.converters;
22

3+
import java.io.IOException;
4+
35
/**
46
* This converter is capable of converting {@link Character}.
57
* Its case sensitive!
@@ -52,10 +54,10 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args)
5254
}
5355

5456
@Override
55-
public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args)
57+
public Appendable toString(Appendable source, ParserRegistry myHomeRegistry, Object obj, Object... args) throws IOException
5658
{
5759
if (obj instanceof Character)
58-
return "'"+(int) (char) obj+"'";
60+
return source.append("'"+(int) (char) obj+"'");
5961
return CONTINUE;
6062
}
6163

SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.ugp.serialx.converters;
22

3+
import java.io.IOException;
4+
35
/**
46
* This is DataParser with extended functionality! {@link DataConverter} can also parse data like DataParser but is also capable of converting them back to string!
57
* This to string convertation is performed by {@link DataConverter#toString(Object)} and result of this convertation supposed to be parsable by {@link DataConverter#parse(String, Object...)} meaning one converter supposed to be parsing and converting via the same string format!
@@ -18,11 +20,37 @@ public interface DataConverter extends DataParser
1820
* @param args | Some additional args. This can be anything and it demands on implementation of DataConverter. Default SerialX API implementation will provide some flags about formating (2 ints)!
1921
*
2022
* @return Object converted to string. Easiest way to do this is obj.toString() but you most likely want some more sofisticated formating.
21-
* Return {@link DataParser#CONTINUE} to tell that this converter is not suitable for converting this object! You most likely want to do this when obtained obj is not suitable instance!
23+
* <br>Return {@link DataParser#CONTINUE} to tell that this converter is not suitable for converting this object! You most likely want to do this when obtained obj is not suitable instance!
2224
*
2325
* @since 1.3.0
2426
*/
25-
CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args);
27+
default CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args)
28+
{
29+
try
30+
{
31+
return (CharSequence) toString(new StringBuilder(), myHomeRegistry, obj, args);
32+
}
33+
catch (IOException e)
34+
{
35+
throw new RuntimeException(e); // Rare...
36+
}
37+
}
38+
39+
/**
40+
* @param source | Source to append the properly stringified object (obj) into. Should be treated as only and only {@link Appendable}, no casting!
41+
* @param myHomeRegistry | Registry where this parser is registered provided by {@link ParserRegistry#parse(String, boolean, Class, Object...)} otherwise it demands on implementation (it should not be null)!
42+
* @param obj | Object to convert into string!
43+
* @param args | Some additional args. This can be anything and it demands on implementation of DataConverter. Default SerialX API implementation will provide some flags about formating (2 ints)!
44+
*
45+
* @return The source appendable after stringified object (obj) was appropriately appended into it. Alternatively you can return null to signify error or that everything necessary was already appended and no further chars should be appended immediately after this obj's stringification.
46+
* <br>Return {@link DataParser#CONTINUE} to tell that this converter is not suitable for converting this object! You most likely want to do this when obtained obj is not suitable instance!
47+
* <br>Note: It is highly discouraged to append into this return!
48+
*
49+
* @throws IOException When appending into source throws it...
50+
*
51+
* @since 1.3.9
52+
*/
53+
Appendable toString(Appendable source, ParserRegistry myHomeRegistry, Object obj, Object... args) throws IOException;
2654

2755
/**
2856
* @param myHomeRegistry | Registry of parsers (might be null)!

SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.ugp.serialx.converters;
22

3+
import java.io.IOException;
34
import java.util.Collection;
45

56
import org.ugp.serialx.LogProvider;
@@ -29,10 +30,11 @@ public interface DataParser
2930

3031
/**
3132
* This is connected with {@link DataParser#parse(String, Object...)} and {@link DataParser#parseObj(String, Object...)}! And its a way to tell that this parser is not suitable for parsing obtained string and search for optimal one should continue.
33+
* Should not be modified under any circumstances, always treat as immutable!
3234
*
3335
* @since 1.3.0
3436
*/
35-
public static final String CONTINUE = new String();
37+
public static final Appendable CONTINUE = new StringBuilder(0);
3638

3739
/**
3840
* This is DataParser registry. Here your parser implementations should be registered in order to work properly!
@@ -80,7 +82,7 @@ public static class ParserRegistry extends Registry<DataParser> implements DataP
8082
private static final long serialVersionUID = -2598324826689380752L;
8183

8284
protected DataParser[] parsingCache;
83-
protected DataParser[] convertingCache;
85+
protected DataConverter[] convertingCache;
8486

8587
/**
8688
* Constructs an {@link ParserRegistry} with the specified initial capacity.
@@ -151,7 +153,7 @@ public DataParser getParserFor(String str, Object... args)
151153
public DataConverter getConverterFor(Object obj, Object... args)
152154
{
153155
for (DataParser parser : this)
154-
if (parser instanceof DataConverter && ((DataConverter)parser).toString(this, obj, args) != CONTINUE)
156+
if (parser instanceof DataConverter && ((DataConverter) parser).toString(this, obj, args) != CONTINUE)
155157
return (DataConverter) parser;
156158
return null;
157159
}
@@ -167,25 +169,50 @@ public DataConverter getConverterFor(Object obj, Object... args)
167169
*/
168170
public CharSequence toString(Object obj, Object... args)
169171
{
170-
CharSequence str;
172+
try
173+
{
174+
return (CharSequence) toString(new StringBuilder(), obj, args);
175+
}
176+
catch (IOException e)
177+
{
178+
throw new RuntimeException(e);
179+
}
180+
}
181+
182+
/**
183+
* @param source | Source to append the properly stringified object (obj) into. Should be treated as only and only {@link Appendable}, no casting!
184+
* @param obj | Object to convert into string!
185+
* @param args | Additional arguments that will be obtained in {@link DataParser#toString(String, Object...)}!
186+
*
187+
* @return The source appendable after stringified object (obj) was appropriately appended into it. Alternatively you can return null to signify error or that everything necessary was already appended and no further chars should be appended immediately after this obj's stringification.
188+
* <br>Return {@link DataParser#CONTINUE} to tell that this converter is not suitable for converting this object! You most likely want to do this when obtained obj is not suitable instance!
189+
* <br>Note: It is highly discouraged to append into this return!
190+
*
191+
* @throws IOException When appending into source throws it...
192+
*
193+
* @since 1.3.9
194+
*/
195+
public Appendable toString(Appendable source, Object obj, Object... args) throws IOException
196+
{
197+
Appendable str;
171198
if (convertingCache != null)
172-
for (DataParser parser : convertingCache)
173-
if (parser != null && (str = ((DataConverter) parser).toString(this, obj, args)) != CONTINUE)
199+
for (DataConverter parser : convertingCache)
200+
if (parser != null && (str = parser.toString(source, this, obj, args)) != CONTINUE)
174201
return str;
175202

176203
for (int i = 0, size = size(); i < size; i++)
177204
{
178205
DataParser parser = get(i);
179-
if (parser instanceof DataConverter && (str = ((DataConverter) parser).toString(this, obj, args)) != CONTINUE)
206+
if (parser instanceof DataConverter && (str = ((DataConverter) parser).toString(source, this, obj, args)) != CONTINUE)
180207
{
181208
if (convertingCache != null && i < convertingCache.length)
182-
convertingCache[i] = parser;
209+
convertingCache[i] = (DataConverter) parser;
183210
return str;
184211
}
185212
}
186213

187214
LogProvider.instance.logErr("Unable to convert \"" + (obj == null ? "null" : obj.getClass().getName()) + "\" to string because none of registered converters were aplicable for this object!", null);
188-
return null;
215+
return source.append("null");
189216
}
190217

191218
/**
@@ -299,9 +326,9 @@ public int[] preCache(Class<? extends DataParser> classOfParserToPrecache)
299326
ret[0] = i;
300327
}
301328

302-
if (i < convertingCache.length)
329+
if (i < convertingCache.length && parser instanceof DataConverter)
303330
{
304-
convertingCache[i] = parser;
331+
convertingCache[i] = (DataConverter) parser;
305332
ret[1] = i;
306333
}
307334

@@ -319,7 +346,7 @@ public int[] preCache(Class<? extends DataParser> classOfParserToPrecache)
319346
public void resetCache()
320347
{
321348
int size = size();
322-
resetCache(new DataParser[size], new DataParser[size]);
349+
resetCache(new DataParser[size], new DataConverter[size]);
323350
}
324351

325352
/**
@@ -330,7 +357,7 @@ public void resetCache()
330357
*
331358
* @since 1.3.5
332359
*/
333-
public void resetCache(DataParser[] parsingCache, DataParser[] convertingCache)
360+
public void resetCache(DataParser[] parsingCache, DataConverter[] convertingCache)
334361
{
335362
if (parsingCache != null)
336363
this.parsingCache = parsingCache;
@@ -363,7 +390,7 @@ public DataParser[] getParsingCache()
363390
*
364391
* @since 1.3.5
365392
*/
366-
public DataParser[] getConverterCache()
393+
public DataConverter[] getConverterCache()
367394
{
368395
return convertingCache;
369396
}

SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import static org.ugp.serialx.Utils.equalsLowerCase;
44

5+
import java.io.IOException;
6+
57
/**
68
* This converter is capable of converting "nothing" otherwise known as null and {@link DataParser#VOID}.
79
* Its case insensitive!
@@ -49,10 +51,10 @@ public Object parse(ParserRegistry registry, String str, Object... args)
4951
}
5052

5153
@Override
52-
public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args)
54+
public Appendable toString(Appendable source, ParserRegistry myHomeRegistry, Object obj, Object... args) throws IOException
5355
{
5456
if (obj == null)
55-
return "null";
57+
return source.append("null");
5658
return CONTINUE;
5759
}
5860

SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import static org.ugp.serialx.Utils.contains;
44

5+
import java.io.IOException;
6+
57
/**
68
* This converter is capable of converting {@link Number} including all common implementations like {@link Double}, {@link Float}, {@link Integer} and others. They are determine by suffixes like in java!
79
* Its case insensitive!
@@ -106,22 +108,23 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args)
106108
}
107109

108110
@Override
109-
public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args)
111+
public Appendable toString(Appendable source, ParserRegistry myHomeRegistry, Object obj, Object... args) throws IOException
110112
{
111113
if (obj instanceof Number)
112114
{
113-
StringBuilder str = new StringBuilder(format((Number) obj));
115+
String str;
116+
source.append(str = format((Number) obj));
114117
if (obj instanceof Double && !contains(str, '.'))
115-
str.append('D');
118+
source.append('D');
116119
else if (obj instanceof Float)
117-
str.append('F');
120+
source.append('F');
118121
else if (obj instanceof Long)
119-
str.append('L');
122+
source.append('L');
120123
else if (obj instanceof Short)
121-
str.append('S');
124+
source.append('S');
122125
else if (obj instanceof Byte)
123-
str.append('Y');
124-
return str;
126+
source.append('Y');
127+
return source;
125128
}
126129
return CONTINUE;
127130
}

SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static org.ugp.serialx.Utils.indexOfNotInObj;
55
import static org.ugp.serialx.Utils.splitValues;
66

7+
import java.io.IOException;
78
import java.io.Serializable;
89
import java.lang.reflect.InvocationTargetException;
910
import java.util.ArrayList;
@@ -166,24 +167,24 @@ protected Object parse(ParserRegistry myHomeRegistry, Class<?> objClass, String
166167
}
167168

168169
@Override
169-
public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args)
170+
public Appendable toString(Appendable source, ParserRegistry myHomeRegistry, Object obj, Object... args) throws IOException
170171
{
171-
return toString(myHomeRegistry, obj, null, args);
172+
return toString(source, myHomeRegistry, obj, null, args);
172173
}
173174

174175
/**
176+
* @param source | Source to append the properly stringified object (obj) into. Should be treated as only and only {@link Appendable}, no casting!
175177
* @param myHomeRegistry | Registry where this parser is registered provided by {@link ParserRegistry#parse(String, boolean, Class, Object...)} otherwise it demands on implementation (it should not be null)!
176178
* @param obj | Object to convert into string!
177179
* @param preferedProtocol | Protocol to use preferably.
178180
* @param args | Some additional args. This can be anything and it demands on implementation of DataConverter. Default SerialX API implementation will provide some flags about formating (2 ints)!
179181
*
180-
* @return Object converted to string. Easiest way to do this is obj.toString() but you most likely want some more sofisticated formating.
181-
* Return {@link DataParser#CONTINUE} to tell that this converter is not suitable for converting this object! You most likely want to do this when obtained obj is not suitable instance!
182+
* @return In accordance with {@link DataConverter#toString(Appendable, org.ugp.serialx.converters.DataParser.ParserRegistry, Object, Object...)}.
182183
*
183184
* @since 1.3.5
184185
*/
185186
@SuppressWarnings("unchecked")
186-
public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, SerializationProtocol<Object> preferedProtocol, Object... args)
187+
public Appendable toString(Appendable source, ParserRegistry myHomeRegistry, Object obj, SerializationProtocol<Object> preferedProtocol, Object... args)
187188
{
188189
if (obj == null)
189190
return CONTINUE;
@@ -205,42 +206,45 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Serializ
205206
{
206207
Object[] objArgs = preferedProtocol.serialize(obj);
207208
final int len = objArgs.length;
209+
210+
boolean wrap;
211+
if (wrap = index > 0 && len != 0)
212+
source.append('{');
208213

209-
StringBuilder sb = new StringBuilder(ImportsProvider.getAliasFor(args[0], obj.getClass()));
214+
source.append(ImportsProvider.getAliasFor(args[0], obj.getClass()));
210215
args = args.clone();
211216
if (args[5] instanceof Byte && (byte) args[5] != 0) // Format
212217
{
213-
for (int i = 0, sizeEndl = 10000; i < len; i++)
218+
for (int i = 0; i < len; i++)
214219
{
215-
if (sb.length() > sizeEndl)
220+
if (i != 0 && i % 1000 == 0)
216221
{
217-
sb.append('\n');
222+
source.append('\n');
218223
for (int j = 0; j < tabs+1; j++)
219-
sb.append('\t');
220-
sizeEndl += 10000;
224+
source.append('\t');
221225
}
222226
else
223-
sb.append(' ');
227+
source.append(' ');
224228

225229
if (args.length > 2)
226230
args[2] = index + 1; // DO NOT TOUCH
227-
sb.append(myHomeRegistry.toString(objArgs[i], args));
231+
myHomeRegistry.toString(source, objArgs[i], args);
228232
}
229233
}
230234
else
231235
{
232236
for (int i = 0; i < len; i++)
233237
{
234-
sb.append(' ');
238+
source.append(' ');
235239

236240
if (args.length > 2)
237241
args[2] = index + 1; // DO NOT TOUCH
238-
sb.append(myHomeRegistry.toString(objArgs[i], args));
242+
myHomeRegistry.toString(source, objArgs[i], args);
239243
}
240244
}
241245

242246
args[4] = oldObjectClass;
243-
return index > 0 && len != 0 ? sb.insert(0, '{').append('}') : sb;
247+
return wrap ? source.append('}') : source;
244248
}
245249
catch (Exception e)
246250
{

0 commit comments

Comments
 (0)