Skip to content

Commit 6743767

Browse files
Small refactor of ArrConv, improving performance and security of
OpGroups, DataRegi is now DataParser
1 parent c50659d commit 6743767

File tree

4 files changed

+98
-60
lines changed

4 files changed

+98
-60
lines changed

SerialX-core/src/main/java/org/ugp/serialx/Utils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -820,8 +820,8 @@ public static String showPosInString(CharSequence str, int pos)
820820
*/
821821
public static Object castArray(Object[] sourceArray, Class<?> toType)
822822
{
823-
int len = sourceArray.length;
824-
Object arr = Array.newInstance(ToClasses(toType)[0], len);
823+
int len;
824+
Object arr = Array.newInstance(ToClasses(toType)[0], len = sourceArray.length);
825825
for (int i = 0; i < len; i++)
826826
Array.set(arr, i, sourceArray[i]);
827827
return arr;

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

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public static Object parseObj(String str, Object... args)
7575
*
7676
* @since 1.3.5
7777
*/
78-
public static class ParserRegistry extends Registry<DataParser>
78+
public static class ParserRegistry extends Registry<DataParser> implements DataParser
7979
{
8080
private static final long serialVersionUID = -2598324826689380752L;
8181

@@ -167,11 +167,11 @@ public DataConverter getConverterFor(Object obj, Object... args)
167167
*/
168168
public CharSequence toString(Object obj, Object... args)
169169
{
170-
CharSequence str = null;
170+
CharSequence str;
171171
if (convertingCache != null)
172172
for (DataParser parser : convertingCache)
173173
if (parser != null && (str = ((DataConverter) parser).toString(this, obj, args)) != CONTINUE)
174-
return str;
174+
return str;
175175

176176
for (int i = 0, size = size(); i < size; i++)
177177
{
@@ -188,6 +188,28 @@ public CharSequence toString(Object obj, Object... args)
188188
return null;
189189
}
190190

191+
/**
192+
* @param parentRegistry | Registry provided by caller, but remember that {@link Registry} is also a {@link DataParser} and therefore this registry will be used instead of this argument.
193+
* @param str | Source string to parse using suitable parser from registry.
194+
* @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}!
195+
*
196+
* @return Object that was parsed from obtained string using suitable parser. This method will iterate registry and try to parse string using each registered parser until suitable return is obtained by parse method of parser, first suitable result will be returned!
197+
* If no suitable parser/result was found, {@link DataParser#CONTINUE} will be returned, as it means that this {@link Registry} was not suitable as parser!<br>
198+
* Note: If this registry contains it self as parser (which should not happen) it will attempt to skip it self in order to not cause possible infinite recursion!
199+
*
200+
* @see DataParser#parseObj(String, Object...)
201+
*
202+
* @since 1.3.7
203+
*/
204+
@Override
205+
public Object parse(ParserRegistry parentRegistry, String str, Object... args)
206+
{
207+
Object result;
208+
if ((result = parse(str, true, this == parentRegistry ? getClass() : null, args)) == str)
209+
return CONTINUE;
210+
return result;
211+
}
212+
191213
/**
192214
* @param str | Source string to parse using suitable parser from registry.
193215
* @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}!
@@ -204,7 +226,7 @@ public Object parse(String str, Object... args)
204226

205227
/**
206228
* @param str | Source string to parse using suitable parser from registry.
207-
* @param returnAsStringIfNotFound | If true, inserted string will be returned instead of null and error message!
229+
* @param returnAsStringIfNotFound | If true, inserted string will be returned instead of null and error message in case of suitable parser not found!
208230
* @param ignore | {@link DataParser} class to ignore!
209231
* @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}!
210232
*
@@ -215,7 +237,7 @@ public Object parse(String str, Object... args)
215237
*/
216238
public Object parse(String str, boolean returnAsStringIfNotFound, Class<? extends DataParser> ignore, Object... args)
217239
{
218-
Object obj = null;
240+
Object obj;
219241
if (parsingCache != null)
220242
for (DataParser parser : parsingCache)
221243
if (parser != null && (ignore == null || ignore != parser.getClass()) && (obj = parser.parse(this, str, args)) != CONTINUE)
@@ -345,5 +367,6 @@ public DataParser[] getConverterCache()
345367
{
346368
return convertingCache;
347369
}
370+
348371
}
349372
}

SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,32 +51,35 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args)
5151
{
5252
if (indexOfNotInObj(str, ' ') > 0)
5353
{
54-
boolean findArrType = true;
55-
if (args.length > 1 && args[1] instanceof Boolean)
56-
findArrType = (boolean) args[1];
57-
5854
String[] strObjs = tokenize(str);
59-
int len = strObjs.length;
60-
Object[] objs = new Object[len];
55+
int len, i = 0;
56+
Object[] objs = new Object[len = strObjs.length];
6157

62-
Class<?> arrClass = null;
63-
for (int i = 0; i < len; i++)
58+
if (args.length < 2 || !(args[1] instanceof Boolean) || (boolean) args[1])
6459
{
65-
Object obj = objs[i] = myHomeRegistry.parse(strObjs[i], args);
66-
if (obj != null)
67-
if (arrClass == null)
68-
arrClass = obj.getClass();
69-
else if (arrClass != obj.getClass())
70-
arrClass = Object.class;
71-
}
72-
73-
if (findArrType && arrClass != null && !arrClass.equals(Object.class))
74-
try
60+
Class<?> arrClass = null;
61+
for (; i < len; i++)
7562
{
76-
return castArray(objs, arrClass);
63+
Object obj = objs[i] = myHomeRegistry.parse(strObjs[i], args);
64+
if (obj != null)
65+
if (arrClass == null)
66+
arrClass = obj.getClass();
67+
else if (arrClass != obj.getClass())
68+
arrClass = Object.class;
7769
}
78-
catch (IllegalArgumentException e)
79-
{}
70+
71+
if (arrClass != null && arrClass != Object.class)
72+
try
73+
{
74+
return castArray(objs, arrClass);
75+
}
76+
catch (IllegalArgumentException e)
77+
{}
78+
return objs;
79+
}
80+
81+
for (; i < len; i++)
82+
objs[i] = myHomeRegistry.parse(strObjs[i], args);
8083
return objs;
8184
}
8285
return CONTINUE;

SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.util.Map;
88

99
import org.ugp.serialx.LogProvider;
10-
import org.ugp.serialx.Serializer;
1110
import org.ugp.serialx.converters.DataParser;
1211

1312
/**
@@ -27,46 +26,59 @@
2726
public class OperationGroups implements DataParser
2827
{
2928
/**
29+
* @deprecated (since 1.3.7) DO NOT USE, USE {@link OperationGroups#groupMark} instead! <br>
30+
*
3031
* Opening and closing of group mark!
3132
*
3233
* @since 1.3.0
3334
*/
34-
public static final String GROUP_MARK_OP = new String(new char[] {127, 128, 129}), GROUP_MARK_CLS = new String(new char[] {129, 128, 127});
35+
@Deprecated
36+
public static final char[] GROUP_MARK_OP = new char[] {127, 128, 129}, GROUP_MARK_CLS = new char[] {129, 128, 127};
37+
38+
/**
39+
* Character marking the opening of {@link OperationGroups} mark in processed string, closing should be marked as this character -1.<br>
40+
* This character is generated in sami-random fashion but it will never be an ASCII character.
41+
*
42+
* @since 1.3.7
43+
*/
44+
protected final char groupMark = (char) (System.nanoTime() | 128);
3545

3646
@SuppressWarnings("unchecked")
3747
@Override
38-
public Object parse(ParserRegistry myHomeRegistry, String str, Object... args)
48+
public Object parse(ParserRegistry myHomeRegistry, String str, Object... args)
3949
{
4050
if (str.length() > 1)
4151
{
42-
int opIndex = indexOfOpening(str, 0, '('), clsIndex = -1;
52+
int opIndex = indexOfOpening(str, 0, '('), clsIndex;
4353
if (opIndex > -1 && (clsIndex = indexOfClosing(str, opIndex, new char[] {'('}, ')')) > -1)
4454
{
45-
Map<String, String> runtimeGroupStack = new HashMap<>();
55+
Map<Integer, String> runtimeGroups;
4656
if (args.length > 2 && args[2] instanceof Map)
47-
runtimeGroupStack = (Map<String, String>) args[2];
57+
runtimeGroups = (Map<Integer, String>) args[2];
4858
else
4959
{
5060
if (args.length < 3)
5161
args = Arrays.copyOf(args, 3);
52-
args[2] = runtimeGroupStack;
62+
args[2] = runtimeGroups = new HashMap<>();
5363
}
54-
String mark = GROUP_MARK_OP + runtimeGroupStack.size() + GROUP_MARK_CLS;
55-
runtimeGroupStack.put(mark, str.substring(opIndex+1, clsIndex).trim());
5664

57-
StringBuilder sb = new StringBuilder(str).replace(opIndex, clsIndex+1, mark);
58-
return myHomeRegistry.parse(sb.toString(), args);
65+
int groupId;
66+
runtimeGroups.put(groupId = runtimeGroups.size(), str.substring(opIndex+1, clsIndex).trim());
67+
68+
StringBuilder newStr = new StringBuilder(str).replace(opIndex, clsIndex+1, new StringBuilder().append(groupMark).append(groupId).append((char) (groupMark-1)).toString());
69+
return myHomeRegistry.parse(newStr.toString(), args);
5970
}
6071

61-
if (isGroupMark(str))
72+
int groupId;
73+
if ((groupId = isGroupMark(str, groupMark)) != -1)
6274
{
6375
if (args.length > 2 && args[2] instanceof Map)
6476
{
65-
Map<String, String> runtimeGroupStack = (Map<String, String>) args[2];
77+
Map<Integer, String> runtimeGroups = (Map<Integer, String>) args[2];
6678

6779
Object[] newArgs = args.clone();
68-
newArgs[2] = new HashMap<String, String>();
69-
return myHomeRegistry.parse(runtimeGroupStack.get(str), newArgs);
80+
newArgs[2] = new HashMap<Integer, String>();
81+
return myHomeRegistry.parse(runtimeGroups.get(groupId), newArgs);
7082
}
7183
LogProvider.instance.logErr("Runtime group stack is trying to be accessed using " + str + " however it was not provided yet!", null);
7284
return null;
@@ -78,38 +90,38 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args)
7890

7991
/**
8092
* @param s | Char sequence to check!
93+
* @param groupMark | Opening character identifying this group mark, closing should be this character -1
8194
*
82-
* @return Return true if inserted CharSequence match the runtime group mark wrapper!
95+
* @return Id of the group mark if inserted CharSequence matches the runtime group mark wrapper format! -1 otherwise.<br>
8396
* This is used for internal purposes of {@link OperationGroups}.
8497
*
8598
* @since 1.3.0
8699
*/
87-
public static boolean isGroupMark(CharSequence s)
100+
public static int isGroupMark(CharSequence s, char groupMark)
88101
{
89-
String op = GROUP_MARK_OP, cls = GROUP_MARK_CLS;
90-
int lo = op.length(), lc = cls.length(), len = s.length();
91-
if (len < lo + lc + 1)
92-
return false;
93-
for (int i = 0; i < lo; i++)
94-
if (s.charAt(i) != op.charAt(i))
95-
return false;
102+
int i = s.length()-1;
103+
if (i < 2 || s.charAt(0) != groupMark-- || s.charAt(i--) != groupMark)
104+
return -1;
96105

97-
for (int i = lo, ch; i < len - lc; i++)
106+
int groupId;
107+
if ((groupId = s.charAt(i--) - '0') < 0 || groupId > 9)
108+
return -1;
109+
for (int ch, baseCof = 10; i >= 1; i--, baseCof *= 10)
110+
{
98111
if ((ch = s.charAt(i)) < '0' || ch > '9')
99-
return false;
112+
return -1;
113+
groupId += (ch - '0') * baseCof;
114+
}
100115

101-
for (int i = 0; i < lc; i++)
102-
if (s.charAt(len-i-1) != cls.charAt(lc-i-1))
103-
return false;
104-
return true;
116+
return groupId;
105117
}
106118

107119
/**
108120
* @param str | CharSequence to search!
109121
* @param from | Beginning index of search!
110122
* @param openings | Openings to find!
111123
*
112-
* @return Return index of first opening char found if is not in object or -1 if there is no opening found similar to {@link Serializer#indexOfNotInObj(CharSequence, char...)}!
124+
* @return Return index of first opening char found if is not in object or -1 if there is no opening found similar to {@link org.ugp.serialx.Utils#indexOfNotInObj(CharSequence, char...)}!
113125
*
114126
* @since 1.3.0
115127
*/
@@ -145,7 +157,7 @@ else if (brackets == 0 && isOneOf(ch, openings))
145157
* @param openings | Openings to count with!
146158
* @param closing | Closings to find!
147159
*
148-
* @return Return index of first closing char found if is not in object or -1 if no closing is found similar to {@link Serializer#indexOfNotInObj(CharSequence, char...)}!
160+
* @return Return index of first closing char found if is not in object or -1 if no closing is found similar to {@link org.ugp.serialx.Utils#indexOfNotInObj(CharSequence, char...)}!
149161
*
150162
* @since 1.3.0
151163
*/

0 commit comments

Comments
 (0)