From 6ef25563dda068239891364daacec88617d842bd Mon Sep 17 00:00:00 2001 From: Programmer001 <39063786+SimplyProgrammer@users.noreply.github.com> Date: Sun, 7 Aug 2022 14:02:35 +0200 Subject: [PATCH 01/48] Delete examples directory --- examples/Bar.java | 85 --------------- examples/Foo.java | 142 -------------------------- examples/GeneralExample.java | 114 --------------------- examples/Message.java | 35 ------- examples/ReadingJsonFromInternet.java | 31 ------ examples/SimpleCalculator.java | 66 ------------ examples/commentedExample.juss | 131 ------------------------ 7 files changed, 604 deletions(-) delete mode 100644 examples/Bar.java delete mode 100644 examples/Foo.java delete mode 100644 examples/GeneralExample.java delete mode 100644 examples/Message.java delete mode 100644 examples/ReadingJsonFromInternet.java delete mode 100644 examples/SimpleCalculator.java delete mode 100644 examples/commentedExample.juss diff --git a/examples/Bar.java b/examples/Bar.java deleted file mode 100644 index 2b05406..0000000 --- a/examples/Bar.java +++ /dev/null @@ -1,85 +0,0 @@ -package examples; - -import java.util.List; - -public final class Bar extends Foo //Sample object that inheres -{ - byte by0 = (byte) 142; - short s0 = 555; - double d2 = 5; - Object sampleParent; - - @Override - public String toString() - { - return "Bar[" + a + " " + b + " " + c + " " + d + " " + f + " " + ch + " " + s + " " + nah + " " + l + " " + by0 + " " + s0 + " " + sampleParent+"]"; - } - - public static class BarProtocol extends FooProtocol //Protocol to serialize Bar - { - @Override - public Object[] serialize(Foo object) - { - return new Object[] {object.a, object.b, object.c, object.d, object.f, object.ch, object.s, object.nah, object.l, ((Bar) object).by0, ((Bar) object).s0, "${$parent}" /*If serialized with JussSerializer this will try to get value of parent property from certain scope!*/}; - } - - @SuppressWarnings("unchecked") - @Override - public Foo unserialize(Class objectClass, Object... args) - { - Bar f = new Bar(); - f.a = (int) args[0]; - f.b = (int) args[1]; - f.c = (int) args[2]; - f.d = (double) args[3]; - f.f = (float) args[4]; - f.ch = (char) args[5]; - f.s = (String) args[6]; - f.nah = (boolean) args[7]; - f.l = (List) args[8]; - f.by0 = (byte) args[9]; - f.s0 = (short) args[10]; - f.sampleParent = args[11]; - - return f; - } - - @Override - public Class applicableFor() - { - return Bar.class; - } - } - - public byte getBy0() { - return by0; - } - - public void setBy0(byte by0) { - this.by0 = by0; - } - - public short getS0() { - return s0; - } - - public void setS0(short s0) { - this.s0 = s0; - } - - public double getD2() { - return d2; - } - - public void setD2(double d2) { - this.d2 = d2; - } - - public Object getSampleParent() { - return sampleParent; - } - - public void setSampleParent(Object sampleParent) { - this.sampleParent = sampleParent; - } -} diff --git a/examples/Foo.java b/examples/Foo.java deleted file mode 100644 index 51f1451..0000000 --- a/examples/Foo.java +++ /dev/null @@ -1,142 +0,0 @@ -package examples; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.ugp.serialx.protocols.SerializationProtocol; - -public class Foo //Sample object to be serialized using its protocol! -{ - int a = 8, b = 1, c = 456; - double d = 5; - float f = 1453.364564564132454654511324f; - char ch = 'l'; - String s = "a"; - boolean nah = false; - List l = new CopyOnWriteArrayList(Arrays.asList(6, 45, 464654, 9.9, 56f)); - - public Foo() - { - l.add(6); - l.add(9); - l.add(13); - l.add(new Random()); - l.add(new ArrayList<>(Arrays.asList(4, 5, 6d, new ArrayList<>(), "hi"))); - } - - @Override - public String toString() - { - return "Foo[" + a + " " + b + " " + c + " " + d + " " + f + " " + ch + " " + s + " " + nah + " " + l + "]"; - } - - public static class FooProtocol extends SerializationProtocol //Protocol to serialize Foo - { - @Override - public Object[] serialize(Foo object) - { - return new Object[] {object.a, object.b, object.c, object.d, object.f, object.ch, object.s, object.nah, object.l}; - } - - @SuppressWarnings("unchecked") - @Override - public Foo unserialize(Class objectClass, Object... args) - { - Foo f = new Foo(); - f.a = (int) args[0]; - f.b = (int) args[1]; - f.c = (int) args[2]; - f.d = (double) args[3]; - f.f = (float) args[4]; - f.ch = (char) args[5]; - f.s = (String) args[6]; - f.nah = (boolean) args[7]; - f.l = (List) args[8]; - - return f; - } - - @Override - public Class applicableFor() - { - return Foo.class; - } - } - - public int getA() { - return a; - } - - public void setA(int a) { - this.a = a; - } - - public int getB() { - return b; - } - - public void setB(int b) { - this.b = b; - } - - public int getC() { - return c; - } - - public void setC(int c) { - this.c = c; - } - - public double getD() { - return d; - } - - public void setD(double d) { - this.d = d; - } - - public float getF() { - return f; - } - - public void setF(float f) { - this.f = f; - } - - public char getCh() { - return ch; - } - - public void setCh(char ch) { - this.ch = ch; - } - - public String getS() { - return s; - } - - public void setS(String s) { - this.s = s; - } - - public boolean isNah() { - return nah; - } - - public void setNah(boolean nah) { - this.nah = nah; - } - - public List getL() { - return l; - } - - public void setL(List l) { - this.l = l; - }; - - public static void a() {}; -} diff --git a/examples/GeneralExample.java b/examples/GeneralExample.java deleted file mode 100644 index d939136..0000000 --- a/examples/GeneralExample.java +++ /dev/null @@ -1,114 +0,0 @@ -package examples; - -import java.io.File; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Random; -import java.util.concurrent.atomic.AtomicLong; - -import org.ugp.serialx.JussSerializer; -import org.ugp.serialx.Scope; -import org.ugp.serialx.protocols.SerializationProtocol; - -/** - * This example is overview of general SerialX API functionalities! - * We will look at how to serialize and deserialize objects using file. We will also create protocols for our objects as well as for already existing ones! - * This example is also for benchmarking! - * - * @author PETO - * - * @since 1.0.0 - */ -public class GeneralExample -{ - public static void main(String[] args) throws Exception - { - //Protocol registration - SerializationProtocol.REGISTRY.addAll(new Bar.BarProtocol(), new Foo.FooProtocol(), new SerializationProtocol() //Sample custom protocol to serialized Random. - { //Random will be serialized also without protocol via classic Java Base64 because it implements java.io.Serializable! - @Override - public Object[] serialize(Random object) - { - try - { - Field f = Random.class.getDeclaredField("seed"); - f.setAccessible(true); - return new Object[] {((AtomicLong) f.get(object)).get()}; - } - catch (Exception e) - { - e.printStackTrace(); - return new Object[] {-1}; - } - } - - @Override - public Random unserialize(Class objectClass, Object... args) - { - return new Random(((Number) args[0]).longValue()); - } - - @Override - public Class applicableFor() - { - return Random.class; - } - }); - - File f = new File("test.juss"); //File to write and read from! - - //Sample objects - Random r = new Random(); - List list = new ArrayList<>(); - for (int i = 0; i < 8; i++) - list.add(r.nextBoolean() ? r.nextInt(i+1) : r.nextBoolean()); - - HashMap vars = new HashMap<>(); //Variables to serialize - vars.put("yourMom", "is heavier than sun..."); - vars.put("num", 6); - - int[][] ints = {{1, 2, 3}, {4, 5, 4}, {3, 2, 1}}; - - //-------------------------------------------Serializing------------------------------------------- - - JussSerializer serializer = new JussSerializer(vars); //Creating an instance of Serializer that will serialize objects using Juss! Serializer is instance of scope so it behaves like so! - //Adding independent values Invokation of static members of this class (calling method "println" and obtaining "hello" field as argument! - serializer.addAll("some string", r, list, serializer.Comment("Size of array"), serializer.Var("arrSize", list.size()), new Bar(), 1, 2.2, 3, 'A', true, false, null, ints, serializer.Code("$num"), new Scope(), serializer.StaticMember(GeneralExample.class, "println", serializer.StaticMember(GeneralExample.class, "hello"))); - //This will insert an comment Another way to add variable except Map $ is used to obtain value from variable - serializer.setGenerateComments(true); //Enabling comment generation - - double t0 = System.nanoTime(); - serializer.SerializeTo(f); //Saving content of serializer to file (serializing) - double t = System.nanoTime(); - System.out.println("Write: " + (t-t0)/1000000 + " ms"); //Write benchmark - - //-------------------------------------------Deserializing------------------------------------------- - - SerializationProtocol.REGISTRY.setActivityForAll(true); //Enabling all protocols, just in case... - - JussSerializer deserializer = new JussSerializer(); //Creating instance of Serializer that will deserialize objects serialized in Juss (same class is responsible for serializing and deserializing)! - deserializer.setParsers(JussSerializer.JUSS_PARSERS_AND_OPERATORS); - deserializer.put("parent", "father"); //Setting global variables - - t0 = System.nanoTime(); - deserializer.LoadFrom(f); //Loading content of file in to deserializer! - t = System.nanoTime(); - System.out.println("Read: " + (t-t0)/1000000 + " ms"); //Read benchmark - - //deserializer = (JussSerializer) deserializer.filter(obj -> obj != null); //This will filter away every null value and variable! - - //Printing values and variables of scope! - System.out.println(deserializer.variables()); - System.out.println(deserializer.values()); - } - - //We can invoke static members in JUSS! - public static String hello = "Hello world!"; - - public static void println(String str) - { - System.out.println(str); - } -} diff --git a/examples/Message.java b/examples/Message.java deleted file mode 100644 index ed534da..0000000 --- a/examples/Message.java +++ /dev/null @@ -1,35 +0,0 @@ -package examples; - -import org.ugp.serialx.protocols.SelfSerializable; - -/** - * Example of self-serializable object! - * - * @author PETO - * - * @see SelfSerializable - * - * @since 1.3.2 - */ -public class Message implements SelfSerializable -{ - public String str; - public int date; - - public Message(String str, int date) - { - this.str = str; - this.date = date; - } - - @Override - public String toString() { - return "Message["+str+", "+date+"]"; - } - - @Override - public Object[] serialize() - { - return new Object[] {str, date}; - } -} diff --git a/examples/ReadingJsonFromInternet.java b/examples/ReadingJsonFromInternet.java deleted file mode 100644 index bb36f97..0000000 --- a/examples/ReadingJsonFromInternet.java +++ /dev/null @@ -1,31 +0,0 @@ -package examples; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -import org.ugp.serialx.JsonSerializer; - -/** - * In this example we can see how to perform json reading from remote web url! - * Note: Internet connection is required for this example to work! - * - * @author PETO - * - * @since 1.3.2 - */ -public class ReadingJsonFromInternet -{ - public static void main(String[] args) throws IOException - { - //Creating JsonSerializer that can parse json! - JsonSerializer reader = new JsonSerializer(); - - InputStream urlInput = new URL("https://jsonplaceholder.typicode.com/users").openStream(); //Establishing connection with https://jsonplaceholder.typicode.com/users and getting stream of received data! - reader.LoadFrom(urlInput); //Parsing url stream content into json! - - String user = "Glenna Reichert"; //User we want to get (Glenna Reichert)! - String glennasCompany = reader.getScopesWith("name", user).get(0).getScope("company").getString("name"); //Obtaining first scope that contains variable with users name and getting name of his company as string from it! - System.out.println(user + " is working for " + glennasCompany); //Printing results! - } -} diff --git a/examples/SimpleCalculator.java b/examples/SimpleCalculator.java deleted file mode 100644 index e29cd7a..0000000 --- a/examples/SimpleCalculator.java +++ /dev/null @@ -1,66 +0,0 @@ -package examples; - -import java.util.Scanner; - -import org.ugp.serialx.Registry; -import org.ugp.serialx.converters.DataParser; -import org.ugp.serialx.converters.NumberConverter; -import org.ugp.serialx.converters.OperationGroups; -import org.ugp.serialx.converters.operators.ArithmeticOperators; - -/** - * This example will show you simple implementation of SerialX latest feature the recursive data parser! - * In this example we will be creating simple evaluator of mathematical expressions! - * - * @author PETO - * - * @since 1.3.0 - */ -public class SimpleCalculator -{ - static Scanner scIn = new Scanner(System.in); - - public static void main(String[] args) - { - /* - * We could easily just use DataParser.REGISTRY but there is tone of stuff we do not need and it will just slow it down! - */ - Registry parsersRequiredToEvaluateMath = new Registry<>(new OperationGroups(), new ArithmeticOperators(), new NumberConverter()); - - /* - * This is an example of simple custom parser this one will allow us to reuse answers of out previous evaluations! - * We will access this old answer using 'ans' word! - * Old ans must be provided as first one of args! - */ - DataParser ansParser = new DataParser() - { - @Override - public Object parse(Registry myHomeRegistry, String str, Object... args) - { - if (str.equalsIgnoreCase("ans")) - { - if (args.length > 0) - return args[0]; //First arg is old answer! - return null; - } - return CONTINUE; - } - }; - parsersRequiredToEvaluateMath.add(ansParser); - - Object oldAns = null; - while (true) - { - System.out.print("Please insert your math problem: "); //Ask for input! - String input = scIn.nextLine() ;//Read console input - if (!(input = input.trim()).isEmpty()) //Avoiding empty input! - { - double t0 = System.nanoTime(); //Performing simple benchmark - oldAns = DataParser.parseObj(parsersRequiredToEvaluateMath, input, oldAns); //Notice that we are inserting oldAns as compiler arguments for parseObj which are then picked up by our ansParser as well as every other registered DataParser. - double t = System.nanoTime(); - - System.out.println(input + " = " + oldAns +"\n" + (t-t0)/1000000 + "ms \n"); //Parsing input! - } - } - } -} diff --git a/examples/commentedExample.juss b/examples/commentedExample.juss deleted file mode 100644 index ed6085c..0000000 --- a/examples/commentedExample.juss +++ /dev/null @@ -1,131 +0,0 @@ -/* THIS IS HOW RESULT OF SERIALX (Juss) REAL LIFE IMPLEMENTATION MIGHT LOOK LIKE */ - -name = "app"; - -dependencies = -{ - //This is scope, the Juss representation of ugp.org.SerialX.Scope! - //Each scope can have its own variables with values and independant values! - - //Every scope can read and write parent scopes variables however by changing them, it will only affect local one and not parents one! - $name; //"app" ($ obtains value from variable, in this case "app") - $name = "no longer app lol!"; - - composition-api = "1.0.0 (beta)", //This is one of the variables of this scope... - bootstrap = "4.5.3", - version = "2.3.4", - something = - { - dataStorage = - { - //This is "dataStorage" (stored by variable "dataStorage") sub-scope aka nested skope of its parent scope "something" which is subscope of "dependencies", - xml = - { - version = "2.8.0" - }, - yaml = - { - version = "1.10.5" - }, - josn = - { - version = "4.0.0" - }, - serialx = - { - version = "The best version!" - } - }, - ppl = - { - //This is "ppl" (stored by variable "ppl") sub-scope aka nested skope of its parent scope "something" which is subscope of "dependencies". - //All of these scopes are sub-scopes of "ppl", there can be infinite number of variables and independent values together in one Scope! - vladimir = - { - age = 37; - residence = "russia"; - }, - ivan = - { - age = 19; - residence = "russia"; - }, - filip = - { - age = 17; - residence = "slovak"; - }, - peter = - { - age = 17; - residence = "slovak"; - }, - lukas = - { - age = 17; - residence = "slovak"; - }, - hans = - { - age = 51; - residence = "germany"; - }, - pierre = - { - age = 44; - residence = "france"; - } - } - }, - "lololoolollool"; //This is independent value of this scope. -}, -$dependencies.something.dataStorage.serialx.version; //Obtaining value of "serialx" variable in "dependencies" sub-scopes! - -devDependencies = -{ - //Variables in this scope have nothing to do with variables from "dependencies" because they are in diffrent scope! - $name = "absolutely not app!"; - - composition-api = "1.0.0 (alpha)", - bootstrap = "2.2.3", - version = "1.2.3", - something = - { - dataStorage = {}, - ppl = {} - } -}; -//Setting variable of scope from outer world (possible since 1.3.2) -devDependencies.something.ppl.ludvig = -{ - age = 60; - residence = "russia"; -}; - -//Since 1.2.5 Serializer fully supports Json and JavaScript object! -jsonCrossover = -{ - "hello" : "Hello world I am Javascript object notation!", - "jsonObject" : - { - name: "John", - age: 31, - city: "New York" - }, - "jsonArray" : [1, 2, 3, 4] -}, - -//$bullshit <-- No this is not possible, variable "bullshit" cannot be accessed here because it was not initialized yet! -bullshit = -{ - //This scope cant access variable that is stored by (bullshit), because variable is always created after its value (Scope in this case) is constructed! - server = "service server", - build = "service build", - sql = "service sql"; -}, -$bullshit; //Now we can access variable "bullshit" - -$name; //"name" is still "app" in this scope! - -arr = {1, 2, 3, 4, 5}; //This is scope with only values! So lets call it... array I guess! -superArr = {$arr, $arr, $arr, $arr::new /*creates clone of arr*/, {1, 2, 3, 4, 5}}; //Yes... this is completely normal and possible in Juss but keep in mind that first, second and third element will refere to same instance in this case! From 4714f4344a9d856a315d505c483ba82a2b285dad Mon Sep 17 00:00:00 2001 From: Programmer001 <39063786+SimplyProgrammer@users.noreply.github.com> Date: Sun, 7 Aug 2022 14:11:38 +0200 Subject: [PATCH 02/48] Update README.md --- README.md | 136 +----------------------------------------------------- 1 file changed, 2 insertions(+), 134 deletions(-) diff --git a/README.md b/README.md index f0b7292..8f0b6c0 100644 --- a/README.md +++ b/README.md @@ -1,134 +1,2 @@ -# Java-SerialX -SerialX is a powerful utility library to serialize objects in Java. Serialization means storing Java objects and values into file.
-SerialX is improving regular Java Base64 serialization and adding serialization protocols that you can create for objects that cant be serialized using regular way. For example final non-serializable objects, 3rd party objects and others. SerialX API is storing objects into JSON like "programming" language (data format) called JUSS (Java universal serial script) which shares common functionality with JSON and provides more customizability and extended functionality! This allows you to serialize multiple objects into one string or also into file. But unlike to JSON, JUSS general conception is based on determinate order of arguments or values we can say. Latest versions also provides variable system (keys, values) similar to JSON. But in JUSS these variables can be overided and can interact with each other and can be used multiple times. Nowadays SerialX provides recursive descent parser that can be modified so you can create your own data structures! In other words SerialX allows you to serialize **anything**, it's pretty simple to use and practically limitless! -## Brief overview of working concept and advantages compared to regular serialization: -**Regular java serialization** is strongly based on some kind of "magic" or we can say "godly reflection" which will reflectivly read all fields of object includeing private and final ones and then interprets it as Base64 string. And during deserialization it will create an empty instance of object absolutly ignoring its constructors by using some "magic" compilator process to create it instad, and then it will violently write all serialized field again includeing private and final ones which is realy not the best aproach! Also this alows you to serialize only instances of java.io.Serializable and all field must be instances of Serializable as well which is also not the most usefull thing!
-Compare to this, **SerialX API** is doing everything programmatically. SerialX API uses ``SerializationProtocol``s that are registred in ``ProtocolRegistry``, each working for certain class! ``SerializationProtocol`` contains 2 methods, ``serialize(T object)`` and ``unserialize(Object[] args)``. ``serialize(T object)`` method obtains certain object to serialize and its job is to turn this object into array of objects that we can then reconstruct this exact object from, such as constructor arguments! These arguments are then paste into ``Serializer`` and ``Serializer`` serialize them into mentioned SerialX API data storage format. During deserialization, ``Serializer`` first takes givven data serialized in SerialX, unserialize them into array of objects and this array is then paste into ``unserialize(Object[] args)`` method of certain ``SerializationProtocol`` as argument. Job of ``unserialize(Object[] args)`` method is to create an new instance of serialized object ``T`` from givven arguments! Evrything in this function is controlled by you and you can write them by your self which gives you an absolute control!
-Note: Since 1.3.0, protocols are operated by DataParsers and are mainly used for more complex objects. Also Object to String conversion is now done by DataConverter and String - Object is done by DataParsers and further by protocols! -**Advantages and goals:** -* Overcoming most of regular serialization problems such as bypassing constructor! -* Powerful and highly costomizable/opinionated, you have control over stuff via protocols and recursive descent parser! -* Programmaticall, meaning you can decide how objects will be serialized and deserialized! -* Fast, SerialX solution is almost always far more faster than regular serialization! -* Readable, It depends but SerialX formats are supposed to be pretty readable for humans and should be also pretty intuitive for learning and writing! -* Data types recognision, SerialX defaultly supports all primitve datatypes from java and also objects (done with protocols) compare to Json for instance! -* Small storage requirements, as you can see belove SerialX is often times far smaller than Json not even mentioning XML! -* Quantity, SerialX can serialize multiple objects into one file or string! -* Fully compatible with JSON! -* Very easy to use, at the begining all what you need to know is ``Serializer.SerializeTo(file, objects)`` for serializing and ``Serializer.LoadFrom(file)`` for deserializing! -* Recursive descent parser that is fully customizable and can be used to parse and convert potentialy anything from JSON to CSS! - -## Comparison: XML (.xml) vs Json (.json) vs YAML (.yml) vs JUSS (.juss or .srlx) -Sample object: -``` -public class Foo -{ - double val1 = 55, val2 = 455.45; - float val3 = 236.12F; - boolean flag = true; - - public double getVal1() - { - return val1; - } - public void setVal1(double val1) - { - this.val1 = val1; - } - public double getVal2() - { - return val2; - } - public void setVal2(double val2) - { - this.val2 = val2; - } - public float getVal3() - { - return val3; - } - public void setVal3(float val3) - { - this.val3 = val3; - } - public boolean isFlag() - { - return flag; - } - public void setFlag(boolean flag) - { - this.flag = flag; - } -} -``` -## -Serialized via **XMLDecoder for XML:** -``` - - - - - 55 - - - 455.45 - - - 236.12 - - - true - - - -``` -
Serialized via **JACKSONE (hypothetical) for Json:** -``` -... -{ - "val1" : 55.0, - "val2" : 455.45, - "val3" : 236.12, - "flag" : true -} -``` -
Serialized via **(hypothetical) YAML:** -``` -val1: 55.0 -val2: 455.45 -val3: 236.12 -flag: true -``` -
Serialized via **SerialX for JUSS (protocol):** -``` -some.package.Foo 55D 455.45 236.12F T; -``` -## After introduction of variables in 1.1.5 and scope in 1.2.0:
-Serialized via **SerialX for JUSS (protocol + scope):** -``` -some.package.Foo { - val1 = 55D, - val2 = 455.45, - val3 = 236.12F, - flag = T -} -``` -
Serialized via **SerialX for JUSS (scope only):** -``` -{ - val1 = 55D, - val2 = 455.45, - val3 = 236.12F, - flag = T -} -``` -
Maybe it is a question of formating but JUSS with protocol will be the shortest one anyway. Because, in this case, instead of having some sort of key to the value you simply have its order (index)! -And value's data type is specified by suffix if it is a primitive data type or simply by package name as the first argument in case of an object! Other arguments (count, order, type) are then specified by a SerializationProtocol! Generally, one line means one object, one value (separated by spaces) means one argument!

-Note: Since there is variable system in 1.1.5, the order of values is now not the only option to obtain an object or value!
-
-## Info -* If you want to add or see issues just click on [Issues section](https://github.com/PetoPetko/Java-SerialX/issues) in up. -* If you want to comment or suggest an feature use [Discussions section](https://github.com/PetoPetko/Java-SerialX/discussions). -* If you want to see or learn some things about library then see the documentation or Sample Open Source Implementation. -* If you want to download library, dont use commits section, use [Releases section](https://github.com/PetoPetko/Java-SerialX/releases) or click that big green button "Clone or download" to download the latest version. -* And if you want to see changelog open [changelog file](Changelog.md) or use [Releases section](https://github.com/PetoPetko/Java-SerialX/releases) too. +# Java-SerialX dev +This branch is used for testing and stuff! From eded64bd6f7caec39a93674d2ce2eef008f80055 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Mon, 19 Jun 2023 14:37:43 +0200 Subject: [PATCH 03/48] gegining of modularisation --- .gitignore | 37 + .project | 17 + .settings/org.eclipse.m2e.core.prefs | 4 + SerialX-core/.classpath | 38 + SerialX-core/.project | 23 + .../.settings/org.eclipse.jdt.core.prefs | 8 + .../.settings/org.eclipse.m2e.core.prefs | 4 + SerialX-core/pom.xml | 13 + .../java/org/ugp/serialx/GenericScope.java | 911 ++++++++ .../java/org/ugp/serialx/JussSerializer.java | 864 ++++++++ .../java/org/ugp/serialx/LogProvider.java | 63 + .../main/java/org/ugp/serialx/Registry.java | 404 ++++ .../src/main/java/org/ugp/serialx/Scope.java | 1285 +++++++++++ .../ugp/serialx/SerializationDebugger.java | 400 ++++ .../main/java/org/ugp/serialx/Serializer.java | 1880 +++++++++++++++++ .../serialx/converters/ArrayConverter.java | 199 ++ .../serialx/converters/BooleanConverter.java | 89 + .../converters/CharacterConverter.java | 69 + .../ugp/serialx/converters/DataConverter.java | 103 + .../ugp/serialx/converters/DataParser.java | 427 ++++ .../ugp/serialx/converters/NullConverter.java | 61 + .../serialx/converters/NumberConverter.java | 205 ++ .../serialx/converters/ObjectConverter.java | 525 +++++ .../serialx/converters/OperationGroups.java | 185 ++ .../SerializableBase64Converter.java | 150 ++ .../serialx/converters/StringConverter.java | 101 + .../serialx/converters/VariableConverter.java | 222 ++ .../serialx/converters/imports/Import.java | 129 ++ .../converters/imports/ImportConverter.java | 267 +++ .../converters/imports/ImportsProvider.java | 130 ++ .../operators/ArithmeticOperators.java | 495 +++++ .../operators/ComparisonOperators.java | 184 ++ .../ConditionalAssignmentOperators.java | 123 ++ .../operators/LogicalOperators.java | 152 ++ .../operators/NegationOperator.java | 81 + .../ugp/serialx/protocols/AutoProtocol.java | 235 +++ .../ugp/serialx/protocols/EnumProtocol.java | 33 + .../ugp/serialx/protocols/ListProtocol.java | 44 + .../ugp/serialx/protocols/MapProtocol.java | 50 + .../ugp/serialx/protocols/ScopeProtocol.java | 47 + .../serialx/protocols/SelfSerializable.java | 22 + .../protocols/SelfSerializableProtocol.java | 31 + .../protocols/SerializationProtocol.java | 450 ++++ .../ugp/serialx/protocols/StringProtocol.java | 62 + .../UniversalObjectInstantiationProtocol.java | 61 + SerialX-json/.classpath | 38 + SerialX-json/.project | 23 + .../.settings/org.eclipse.jdt.core.prefs | 8 + .../.settings/org.eclipse.m2e.core.prefs | 4 + SerialX-json/pom.xml | 21 + .../org/ugp/serialx/json/JsonSerializer.java | 403 ++++ .../converters/JsonCharacterConverter.java | 28 + .../json/converters/JsonNumberConverter.java | 14 + .../json/converters/JsonObjectConverter.java | 48 + pom.xml | 58 + 55 files changed, 11528 insertions(+) create mode 100644 .gitignore create mode 100644 .project create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 SerialX-core/.classpath create mode 100644 SerialX-core/.project create mode 100644 SerialX-core/.settings/org.eclipse.jdt.core.prefs create mode 100644 SerialX-core/.settings/org.eclipse.m2e.core.prefs create mode 100644 SerialX-core/pom.xml create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/Registry.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/Scope.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/SerializationDebugger.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/Serializer.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/SerializableBase64Converter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportConverter.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/protocols/EnumProtocol.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/protocols/ListProtocol.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializable.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializableProtocol.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/protocols/StringProtocol.java create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java create mode 100644 SerialX-json/.classpath create mode 100644 SerialX-json/.project create mode 100644 SerialX-json/.settings/org.eclipse.jdt.core.prefs create mode 100644 SerialX-json/.settings/org.eclipse.m2e.core.prefs create mode 100644 SerialX-json/pom.xml create mode 100644 SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java create mode 100644 SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java create mode 100644 SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java create mode 100644 SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java create mode 100644 pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..04f470d --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Specifies intentionally untracked files to ignore when using Git +# http://git-scm.com/docs/gitignore + +*~ +*.sw[mnpcod] +.tmp +*.tmp +*.tmp.* +*.sublime-project +*.sublime-workspace +.DS_Store +Thumbs.db +UserInterfaceState.xcuserstate +$RECYCLE.BIN/ + +*.log +log.txt +npm-debug.log* + +/.idea +/.ionic +/.sass-cache +/.sourcemaps +/.versions +/.vscode +/coverage +/dist +/node_modules +/platforms +/plugins +/www + +bin/ +tmp/ +.metadata + +target/ diff --git a/.project b/.project new file mode 100644 index 0000000..bbfcc34 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + SerialXDev + + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/SerialX-core/.classpath b/SerialX-core/.classpath new file mode 100644 index 0000000..002ad57 --- /dev/null +++ b/SerialX-core/.classpath @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SerialX-core/.project b/SerialX-core/.project new file mode 100644 index 0000000..75fcc6c --- /dev/null +++ b/SerialX-core/.project @@ -0,0 +1,23 @@ + + + SerialX-core + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/SerialX-core/.settings/org.eclipse.jdt.core.prefs b/SerialX-core/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..2f5cc74 --- /dev/null +++ b/SerialX-core/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/SerialX-core/.settings/org.eclipse.m2e.core.prefs b/SerialX-core/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/SerialX-core/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/SerialX-core/pom.xml b/SerialX-core/pom.xml new file mode 100644 index 0000000..d26d70a --- /dev/null +++ b/SerialX-core/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + + org.ugp + serialx + 1.3.7 + + org.ugp.serialx + core + + SerialX-core + Core of SerialX + \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java new file mode 100644 index 0000000..0cd2c1f --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -0,0 +1,911 @@ +package org.ugp.serialx; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.ugp.serialx.converters.ArrayConverter; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.protocols.SerializationProtocol; +import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; + + +/** + * This is some kind of hybrid between {@link List} and {@link Map} which allow you to have both variables and independent values managed by one Object.
+ * Note: Variables are managed and accessed classically via {@link Map} methods such as put(KeyT key, Object) and array of independent values is accessed by via {@link List} methods such as add(Object) and get(int)
+ * Also this is java representation of JUSS GenericScope group such as: + *
+ * 
+ * {
+ *     //This is generic scope in JUSS! Variable keys are generic!
+ * }
+ * 
+ * 
+ * + * @author PETO + * + * @since 1.2.0 + * + * @param generic type of variables key. + * @param generic type of variables value and independent value. + */ +public class GenericScope implements Iterable, Cloneable, Serializable +{ + private static final long serialVersionUID = 5717775602991055386L; + + protected Map variables; + protected List values; + protected GenericScope parent; + + /** + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.2.0 + */ + @SafeVarargs + public GenericScope(ValT... values) + { + this(null, values); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.2.0 + */ + @SafeVarargs + public GenericScope(Map variablesMap, ValT... values) + { + this(variablesMap, values == null ? null : Arrays.asList(values), null); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.2.0 + */ + public GenericScope(Map variablesMap, Collection values) + { + this(variablesMap, values, null); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * @param parent | Parent of this scope. + + * @since 1.2.0 + */ + public GenericScope(Map variablesMap, Collection values, GenericScope parent) + { + if (variablesMap != null) + this.variables = new LinkedHashMap<>(variablesMap); + if (values != null) + this.values = new ArrayList<>(values); + this.parent = parent; + } + + @Override + public boolean equals(Object obj) + { + if (obj instanceof GenericScope) + return values().equals(((GenericScope) obj).values()) && variables().equals(((GenericScope) obj).variables()); + else if (obj instanceof Collection) + return variablesCount() <= 0 && values().equals(obj); + else if (obj instanceof Map) + return valuesCount() <= 0 && variables().equals(obj); + else if (obj != null && obj.getClass().isArray()) + return variablesCount() <= 0 && Objects.deepEquals(toValArray(), ArrayConverter.fromAmbiguous(obj)); + return super.equals(obj); + } + + @Override + public String toString() + { + String name = getClass().getSimpleName(); + if (variablesCount() > 0 ^ valuesCount() > 0) + return name + (variablesCount() > 0 ? variables() : values()); + else + return name + toUnifiedList(); + } + + @SuppressWarnings("unchecked") + @Override + public GenericScope clone() + { + try + { + return clone(getClass()); + } + catch (Exception e) + { + return new GenericScope<>(variables(), values(), getParent()); + } + } + + /** + * @param typeOfClone | Class representing type of scope that will be created. + * @return Copy of this scope converted to instance of typeOfClone. + * + * @throws Exception | When program was unable to create instance of typeOfClone. + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public > S clone(Class typeOfClone) throws Exception + { + S clone = Serializer.Instantiate(typeOfClone); + clone.values = (List) toValList(); + clone.variables = (Map) toVarMap(); + clone.parent = getParent(); + return (S) clone; + } + + /** + * @param newType | Type of new scope. + * @return Original scope retyped/casted into instance of newType. Similar to {@link GenericScope#clone(Class)} but this will share same instances of values list and variables map with original! + * + * @throws Exception | When program was unable to create instance of newType. + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public > S castTo(Class newType) throws Exception + { + if (getClass() == newType) + return (S) this; + + GenericScope clone = (GenericScope) Serializer.Instantiate(newType); + clone.values = (List) values(); + clone.variables = (Map) variables(); + clone.parent = getParent(); + return (S) clone; + } + + /** + * @return Iterator of independent values. + * + * @since 1.2.0 + */ + @Override + public Iterator iterator() + { + return values().iterator(); + } + + /** + * Insert new variable. + * + * @param variableKey | Name of variable. + * @param variableValue | Variables value. + * + * @return Old value of variable with given name or null is there was no this variable before! + * + * @since 1.2.0 + */ + public ValT put(KeyT variableKey, ValT variableValue) + { + if (variableValue instanceof GenericScope && ((GenericScope) variableValue).getParent() == null) + ((GenericScope) variableValue).parent = this; + return variables().put(variableKey, variableValue); + } + + /** + * @param kVkVkV | kV array with keys and values to insert into this map. Elements with even indexes are values and the ones with odd indexes are keys... + * + * @return Array of values previously at keys from kv array. + * + * @since 1.3.7 + */ + @SuppressWarnings("unchecked") + public ValT[] putAllKv(Object... kVkVkV) + { + ValT[] oldValues = (ValT[]) new Object[kVkVkV.length/2]; + for (int i = 1; i < kVkVkV.length; i+=2) { + oldValues[i/2] = put((KeyT) kVkVkV[i-1], (ValT) kVkVkV[i]); + } + return oldValues; + } + + /** + * @param index | Index of variable! + * + * @return Value of variable at required index or null if index was not found! + * + * @since 1.2.5 + */ + public V getVarAt(int index) + { + return getVarAt(index, null); + } + + /** + * @param index | Index of variable! + * @param defaultValue | Default value to return. + * + * @return Value of variable at required index or defaultValue if index was not found! + * + * @since 1.2.5 + */ + @SuppressWarnings("unchecked") + public V getVarAt(int index, V defaultValue) + { + int i = 0; + for (Map.Entry ent : varEntrySet()) + if (i++ == index) + return (V) ent.getValue(); + return defaultValue; + } + + /** + * @param variableKey | Variables name. + * + * @return Value of variable with name or null if there is no such a one! + * + * @since 1.2.0 + */ + public V get(KeyT variableKey) + { + return get(variableKey, null); + } + + /** + * @param variableKey | Variables name. + * @param defaultValue | Default value to return. + * + * @return Value of variable with name or defaultValue if there is no such a one! + * + * @since 1.2.5 + */ + @SuppressWarnings("unchecked") + public V get(KeyT variableKey, V defaultValue) + { + V obj = (V) variables().get(variableKey); + if (obj == null) + return (V) defaultValue; + return obj instanceof Serializer.NULL ? null : obj; + } + + /** + * @param variableKey | Variables name to search for. + * + * @return True if variable with given name was found in this scope. + * + * @since 1.2.0 + */ + public boolean containsVariable(KeyT variableKey) + { + for (Map.Entry ent : varEntrySet()) + if (ent.getKey().equals(variableKey)) + return true; + return false; + } + + /** + * @param value | Objecthe value. + * + * @return True if independent value was found in this scope. + * + * @since 1.2.0 + */ + public boolean containsIndependentValue(ValT value) + { + return values().contains(value); + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Independent value with valueIndex. + * + * @since 1.2.0 + */ + @SuppressWarnings("unchecked") + public V get(int valueIndex) + { + V obj = (V) values().get(valueIndex < 0 ? valuesCount() + valueIndex : valueIndex); + return obj instanceof Serializer.NULL ? null : obj; + } + + /** + * @param value | Independent value to add into array of values. + * + * @return {@link ArrayList#add(Object)} + * + * @since 1.2.0 + */ + public boolean add(ValT value) + { + boolean result = values().add(value); + if (result && value instanceof GenericScope && ((GenericScope) value).getParent() == null) + ((GenericScope) value).parent = this; + return result; + } + + /** + * @param values | List of independent value or values to add into array of values. + * + * @return {@link ArrayList#add(Object)} + * + * @since 1.2.0 + */ + public boolean addAll(Collection values) + { + if (values.isEmpty()) + return false; + return values().addAll(values); + } + + /** + * @param values | Array of independent value or values to add into array of values. + * + * @return {@link GenericScope#addAll(Object...)} + * + * @since 1.3.2 + */ + public boolean addAll(@SuppressWarnings("unchecked") ValT... values) + { + return addAll(Arrays.asList(values)); + } + + /** + * @param scopeValueIndex | Index of sub-scopes value. + * + * @return Sub-scope on required index or null if there is no scope on required index!
+ * Note: Keep in mind that you need to insert valid index according to other values. Scopes share same index order with other values! + * Note: Also remember that this function will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope}) + * + * @since 1.2.0 + */ + @SuppressWarnings("unchecked") + public GenericScope getGenericScope(int scopeValueIndex) + { + GenericScope obj = (GenericScope) get(scopeValueIndex); + if (obj instanceof GenericScope) + return (GenericScope) obj; + return null; + } + + /** + * @param scopesPath | Array with variables creating path to required scope. + * + * @return Sub-scope stored by variable with required name (last element) in inserted path or null if there is no such a one in inserted path. If there is more than one result, the first one found will be returned! + * This search will also includes sub-scopes of scope but variables from lower ones are prioritize!
+ * If this function is called with no arguments then self will be returned! + * Note: Remember that this search includes variables only, no values!
+ * Note: Also remember that this function will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope}) + * + * @since 1.2.0 + */ + @SuppressWarnings("unchecked") + public GenericScope getGenericScope(K... scopesPath) + { + try + { + if (scopesPath.length <= 0) + return (GenericScope) this; + Object obj = get((KeyT) scopesPath[0]); + if (obj instanceof GenericScope) + return ((GenericScope) obj).getGenericScope(scopesPath = Arrays.copyOfRange(scopesPath, 1, scopesPath.length)); + for (Map.Entry var : varEntrySet()) + if (var.getValue() instanceof GenericScope) + try + { + GenericScope sc = (GenericScope) var.getValue(); + if ((sc = sc.getGenericScope(scopesPath[0])) != null) + return sc.getGenericScope(scopesPath = Arrays.copyOfRange(scopesPath, 1, scopesPath.length)); + } + catch (Exception e) {} + + if (containsVariable((KeyT) scopesPath[0])) + LogProvider.instance.logErr("Variable with name \"" + scopesPath[0] + "\" does exists! However its value is not instance of scope, use \"get\" function instead if possible!", null); + } + catch (ClassCastException e) + {} + return null; + } + + /** + * @param objClass | Object of class to create. + * + * @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}! + * + * @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! + * + * @since 1.2.5 + */ + public T toObject(Class objClass) throws Exception + { + return toObject(objClass, SerializationProtocol.REGISTRY); + } + + /** + * @param objClass | Object of class to create using protocols. + * @param protocolsToUse | Registry of protocols to use. + * + * @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}! + * + * @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! + * + * @since 1.3.2 + */ + public T toObject(Class objClass, ProtocolRegistry protocolsToUse) throws Exception + { + SerializationProtocol pro = protocolsToUse == null ? null : protocolsToUse.GetProtocolFor(objClass, SerializationProtocol.MODE_DESERIALIZE); + if (pro != null) + { + T obj = pro.unserialize(objClass, this.variablesCount() > 0 ? new Object[] {this} : this.toValArray()); + if (obj != null) + return obj; + } + return null; + } + + /** + * @param predicate | Predicate object with filter condition in test method! + * + * @return Original scope after filtration using inserted predicate! If some object can't be casted to {@link Predicate#test(Object)} argument, it will be treated as invalid and will be filtered away! Sub-scopes are not included! + * + * @since 1.2.5 + */ + public GenericScope filter(Predicate predicate) + { + return filter(predicate, false); + } + + /** + * @param predicate | Predicate object with filter condition in test method! + * @param includeSubScopes | If true filtration will be also applied on sub-scopes, if false sub-scopes will be treated as other things (parsed in to {@link Predicate#test(Object)}). + * If sub-scope is empty after filtration it will not be included in result! + * Note: Remember that this will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope})! + * + * @return Original scope after filtration using inserted predicate! If some object can't be casted to {@link Predicate#test(Object)} argument, it will be treated as invalid and will be filtered away! + * + * @since 1.2.5 + */ + @SuppressWarnings("unchecked") + public GenericScope filter(Predicate predicate, boolean includeSubScopes) + { + return (GenericScope) transform(new Function() + { + @Override + public Object apply(ValT t) + { + return predicate.test(t) ? t : DataParser.VOID; + } + }, includeSubScopes); + } + + /** + * @param trans | Function to transform objects of this scope! + * + * @return Original scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! Sub-scopes are not included! + * + * @since 1.2.5 + */ + public GenericScope transform(Function trans) + { + return transform(trans, false); + } + + /** + * @param trans | Function to transform objects of this scope! + * @param includeSubScopes | If true transformation will be also applied on sub-scopes, if false sub-scopes will be treated as other things (parsed in to {@link Function#apply(Object)}). + * If sub-scope is empty after transformation it will not be included in result! + * Note: Remember that this will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope})! + * + * @return Original scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! + * + * @since 1.2.5 + */ + @SuppressWarnings("unchecked") + public GenericScope transform(Function trans, boolean includeSubScopes) + { + if (trans == null || isEmpty()) + return (GenericScope) this; + + List fltVals = map(trans, includeSubScopes); + LinkedHashMap fltVars = new LinkedHashMap<>(); + + for (Entry ent : this.varEntrySet()) + try + { + Object obj = ent.getValue(); + obj = obj instanceof Serializer.NULL ? null : obj; + if (obj instanceof GenericScope && includeSubScopes) + { + GenericScope sc = ((GenericScope) obj).transform(trans, includeSubScopes); + if (!sc.isEmpty()) + fltVars.put(ent.getKey(), (V) sc); + } + else if ((obj = trans.apply((ValT) obj)) != DataParser.VOID) + fltVars.put(ent.getKey(), trans.apply((ValT) obj)); + } + catch (ClassCastException e) + {} + + try + { + GenericScope clone = Serializer.Instantiate(getClass()); + clone.values = fltVals; + clone.variables = fltVars; + clone.parent = getParent(); + return clone; + } + catch (Exception e) + { + return new GenericScope<>(fltVars, fltVals, getParent()); + } + } + + /** + * @param trans | Function to transform objects of this scope! + * + * @return Original scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! + * + * @since 1.3.5 + */ + public List map(Function trans) + { + return map(trans, false); + } + + /** + * @param trans | Function to transform objects of this scope! + * @param includeSubScopes | If true transformation will be also applied on sub-scopes, if false sub-scopes will be treated as other things (parsed in to {@link Function#apply(Object)}). + * If sub-scope is empty after transformation it will not be included in result! + * Note: Remember that this will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope})! + * + * @return Original scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public List map(Function trans, boolean includeSubScopes) + { + List fltVals = new ArrayList<>(); + for (Object obj : this) + try + { + obj = obj instanceof Serializer.NULL ? null : obj; + if (obj instanceof GenericScope && includeSubScopes) + { + GenericScope sc = ((GenericScope) obj).transform(trans, includeSubScopes); + if (!sc.isEmpty()) + fltVals.add((V) sc); + } + else if ((obj = trans.apply((ValT) obj)) != DataParser.VOID) + fltVals.add((V) obj); + } + catch (ClassCastException e) + {} + + return fltVals; + } + + /** + * @param valueIndex | Index of independent value to remove! + * + * @return Removed independent value! + * + * @since 1.3.2 + */ + public ValT remove(int valueIndex) + { + return values().remove(valueIndex < 0 ? valuesCount() + valueIndex : valueIndex); + } + + /** + * @param variableKey | Name of variable to remove! + * + * @return Value of variable that was removed! + * + * @since 1.3.2 + */ + public ValT remove(KeyT variableKey) + { + return variables().remove(variableKey); + } + + /** + * Removes all independent values and variables of this scope! + *
+ * Basically it just calls variables().clear() and values().clear()! + * + * @since 1.3.5 + */ + public void clear() + { + variables().clear(); + values().clear(); + } + + /** + * @return This scope after inheriting variables of its parent (return this)! + * + * @since 1.3.2 + */ + @SuppressWarnings("unchecked") + public GenericScope inheritParent() + { + GenericScope parent = getParent(); + if (parent != null) + variables().putAll((Map) parent.variables()); + return this; + } + + /** + * @param scope | GenericScope whose content will be added! + * + * @return This scope... + * + * @since 1.3.0 + */ + public GenericScope addAll(GenericScope scope) + { + values().addAll(scope.values()); + variables().putAll(scope.variables()); + return this; + } + + /** + * @return Entry set of variables! + * + * @since 1.2.0 + */ + public Set> varEntrySet() + { + return variables().entrySet(); + } + + /** + * @return Count of keyless values of this scope! (values().size()) + * + * @since 1.2.0 + */ + public int valuesCount() + { + return values().size(); + } + + /** + * @return Count of variables! (variables().size()) + * + * @since 1.2.0 + */ + public int variablesCount() + { + return variables().size(); + } + + /** + * @return Total number of variables and independent values of this scope! (vvaluesCount() + variablesCount()) + */ + public int totalSize() + { + return valuesCount() + variablesCount(); + } + + /** + * @return True if this scope is completely empty, meaning there are no variables or values. + * + * @since 1.2.0 + */ + public boolean isEmpty() + { + return totalSize() <= 0; + } + + /** + * @return The parent scope of this scope or null if this scope has no parent such as default one in file. + * + * @since 1.2.0 + */ + public GenericScope getParent() + { + return getParent(false); + } + + /** + * @param absoluteParent | If true, absolute parent of this scope will be returned (parent of parent of parent...)! + * + * @return The parent scope of this scope or null if this scope has no parent such as default one in file. + * + * @since 1.3.2 + */ + public GenericScope getParent(boolean absoluteParent) + { + if (!absoluteParent) + return parent; + GenericScope parent = this.parent; + for (GenericScope tmpPar; parent != null && (tmpPar = parent.getParent()) != null; parent = tmpPar); + return parent; + } + + /** + * @return New {@link LinkedHashMap} with variables of this a in defined order! Key is a KeyT of variable and value is its value!
+ * Modifying this map will not affect this GenericScope object! + * + * @since 1.2.0 + */ + public LinkedHashMap toVarMap() + { + return new LinkedHashMap<>(variables()); + } + + /** + * @return New {@link ArrayList} with independent values of this {@link GenericScope}. These values have nothing to do with values of variables, they are independent! + * Modifying this list will not affect this GenericScope object! + * + * @since 1.2.0 + */ + public List toValList() + { + return new ArrayList<>(values()); + } + + /** + * @return Primitive array with independent values of this {@link GenericScope}. These values have nothing to do with values of variables, they are independent! + * Modifying this list will not affect this {@link GenericScope} object! + * + * @since 1.2.0 + */ + public Object[] toValArray() + { + return values().toArray(); + } + + /** + * @param vals | Array to store independent values into! + * + * @return Primitive array with independent values of this {@link GenericScope}. These values have nothing to do with values of variables, they are independent! + * Modifying this list will not affect this {@link GenericScope} object! + * + * @since 1.3.5 + */ + public V[] toValArray(V[] vals) + { + return values().toArray(vals); + } + + /** + * @return List with both variables and values! Variables will be added as {@link Entry}! + * Variables will be always first! + * Modifying this map will not affect this GenericScope object! + * + * @since 1.3.0 + */ + @SuppressWarnings("unchecked") + public List toUnifiedList() + { + List list = (List) toValList(); + list.addAll(0, varEntrySet()); + return list; + } + + /** + * @return Values of this scope. These are not the values of keys these are values that have no key. You can access them via {@link GenericScope#get(int)}! + * Note: Editing this List will affect this scope! + * + * @since 1.2.0 + */ + public List values() + { + if (values == null) + values = new ArrayList<>(); + return values; + } + + /** + * @return Variables of this scope. Objecthis variables has nothing to do with values. Key is a KeyT name of variable and value is value of variable. + * Note: Editing this Map will affect this scope! + * + * @since 1.2.0 + */ + public Map variables() + { + if (variables == null) + variables = new LinkedHashMap<>(); + return variables; + } + + /** + * @param variablesMap | Variables map to use! + * + * @return New scope that is bidirectional with given data structures (list and map), which means that changing these data structures will affect scope and changing scope will affect data structures. This is behavior that regular constructor created scopes do not possess! + * + * @since 1.3.5 + */ + public static GenericScope newBidirectional(Map variablesMap) + { + return newBidirectional(variablesMap, null); + } + + /** + * @param variablesMap | Variables map to use! + * @param values | Values list to use! + * + * @return New scope that is bidirectional with given data structures (list and map), which means that changing these data structures will affect scope and changing scope will affect data structures. This is behavior that regular constructor created scopes do not possess! + * + * @since 1.3.5 + */ + public static GenericScope newBidirectional(Map variablesMap, List values) + { + return newBidirectional(variablesMap, values, null); + } + + /** + * @param variablesMap | Variables map to use! + * @param values | Values list to use! + * @param parent | Parent of scope! + * + * @return New scope that is bidirectional with given data structures (list and map), which means that changing these data structures will affect scope and changing scope will affect data structures. This is behavior that regular constructor created scopes do not possess! + * + * @since 1.3.5 + */ + public static GenericScope newBidirectional(Map variablesMap, List values, GenericScope parent) + { + return intoBidirectional(new GenericScope<>(null, null, null), variablesMap, values, parent); + } + + /** + * @param scopeToMakeBidirectional | GenericScope to make bidirectional! + * @param variablesMap | Variables map to use! + * @param values | Values list to use! + * + * @return Inserted scope that is bidirectional with given data structures (list and map), which means that changing these data structures will affect scope and changing scope will affect data structures. This is behavior that regular constructor created scopes do not possess! + * + * @since 1.3.5 + */ + public static GenericScope intoBidirectional(GenericScope scopeToMakeBidirectional, Map variablesMap, List values) + { + return intoBidirectional(scopeToMakeBidirectional, variablesMap, values, null); + } + + /** + * @param scopeToMakeBidirectional | GenericScope to make bidirectional! + * @param variablesMap | Variables map to use! + * @param values | Values list to use! + * @param parent | Parent of scope! + * + * @return Inserted scope that is bidirectional with given data structures (list and map), which means that changing these data structures will affect scope and changing scope will affect data structures. This is behavior that regular constructor created scopes do not possess! + * + * @since 1.3.5 + */ + public static GenericScope intoBidirectional(GenericScope scopeToMakeBidirectional, Map variablesMap, List values, GenericScope parent) + { + scopeToMakeBidirectional.variables = variablesMap; + scopeToMakeBidirectional.values = values; + scopeToMakeBidirectional.parent = parent; + return scopeToMakeBidirectional; + } + + /** + * @param map | Map to populate from kV array. + * @param kVkVkV | kV array with keys and values to insert into this map. Elements with even indexes are values and the ones with odd indexes are keys... + * + * @return Same map populated with kV array. + * + * @since 1.3.7 + */ + @SuppressWarnings("unchecked") + public static Map mapKvArray(Map map, Object... kVkVkV) + { + for (int i = 1; i < kVkVkV.length; i+=2) + map.put((K) kVkVkV[i-1], (V) kVkVkV[i]); + return map; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java b/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java new file mode 100644 index 0000000..05e85fd --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java @@ -0,0 +1,864 @@ +package org.ugp.serialx; + +import static org.ugp.serialx.converters.DataParser.VOID; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.io.BufferedReader; +import java.io.File; +import java.io.Flushable; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.net.URL; +import java.net.URLConnection; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.ugp.serialx.converters.DataConverter; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.converters.DataParser.ParserRegistry; +import org.ugp.serialx.converters.ObjectConverter; +import org.ugp.serialx.converters.StringConverter; +import org.ugp.serialx.converters.imports.ImportConverter; +import org.ugp.serialx.converters.operators.ArithmeticOperators; +import org.ugp.serialx.converters.operators.ComparisonOperators; +import org.ugp.serialx.converters.operators.ConditionalAssignmentOperators; +import org.ugp.serialx.converters.operators.LogicalOperators; +import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; + +import javafx.beans.binding.When; + +/** + * This is implementation of {@link Serializer} for serializing in default SerialX API implementation known as JUSS (Java universal serial script) which is Json like domain specific language that has extended functionality! + * It should generate and work with .juss or .srlx files! + * + * @author PETO + * + * @since 1.3.2 + */ +@SuppressWarnings("serial") +public class JussSerializer extends Serializer +{ + public static final ParserRegistry JUSS_PARSERS = DataParser.REGISTRY.clone(), JUSS_PARSERS_AND_OPERATORS; + + static + { + JUSS_PARSERS.add(0, new ImportConverter()); + JUSS_PARSERS_AND_OPERATORS = JUSS_PARSERS.clone(); + JUSS_PARSERS_AND_OPERATORS.addAllBefore(StringConverter.class, true, new ConditionalAssignmentOperators(), new LogicalOperators(), new ComparisonOperators(), new ArithmeticOperators()); + } + + /** + * Set this on true and program will generate comments and report!
+ * Note: Keep this on false to achieve the best performance! + * + * @since 1.0.5 + */ + protected boolean generateComments = false; + + /** + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public JussSerializer(Object... values) + { + this(null, values); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public JussSerializer(Map variablesMap, Object... values) + { + this(variablesMap, values == null ? null : new ArrayList<>(Arrays.asList(values))); + } + + /** + * @param sourceScope | Scope with initial content! + * + * @since 1.3.5 + */ + public JussSerializer(GenericScope sourceScope) + { + this(sourceScope == null ? null : sourceScope.variables(), sourceScope == null ? null : sourceScope.values()); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public JussSerializer(Map variablesMap, Collection values) + { + this(null, variablesMap, values); + } + + /** + * @param parsers | Registry of parsers to use! + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public JussSerializer(Registry parsers, Map variablesMap, Collection values) + { + this(parsers, null, variablesMap, values, null); + } + + /** + * @param parsers | Registry of parsers to use! + * @param protocols | Registry of protocols to use! + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * @param parent | Parent of this scope. + * + * @since 1.3.2 + */ + public JussSerializer(Registry parsers, ProtocolRegistry protocols, Map variablesMap, Collection values, Scope parent) + { + super(parsers, protocols, variablesMap, values, parent); + } + + @Override + public Scope clone() + { + Scope scope = super.clone(); + if (scope instanceof JussSerializer) + { + ((JussSerializer) scope).setGenerateComments(isGenerateComments()); + ((JussSerializer) scope).setParsers(getParsers()); + ((JussSerializer) scope).setProtocols(getProtocols()); + } + return scope; + } + + @Override + public JussSerializer emptyClone(Scope parent) + { + JussSerializer srl = emptyClone(new JussSerializer(), parent); + srl.setGenerateComments(isGenerateComments()); + return srl; + } + + @Override + public ParserRegistry getParsers() + { + return parsers != null ? parsers : (parsers = JUSS_PARSERS.clone()); + } + + /** + * @param absoluteClone | If true this scope will be cloned using {@link Serializer#Clone(Object, Registry, Object[], Object...)}, if false {@link Scope#clone()}! + * + * @return Clone of this scope! + * + * @since 1.3.2 + */ + public Scope clone(boolean absoluteClone) + { + if (absoluteClone) + return Clone(this, getParsers(), new Object[] {-9999, 0, this, getProtocols(), isGenerateComments()}, this, null, null, getProtocols()); + return super.clone(); + } + + /** + * @param name | Name of variable. + * @param value | Value of variable. + * + * @return Variable in JUSS form to serialize as [name] = [value]. + * + * @since 1.1.5 + */ + @Override + public String Var(String name, T value) + { + return Var(name, value, false); + } + + /** + * @param name | Name of variable. + * @param value | Value of variable. + * @param isValue | True if variables value supposed to by visible also during value loading. + * + * @return Variable in JUSS form to serialize as [name] = [value]. + * + * @since 1.1.5 + */ + public String Var(String name, T value, boolean isValue) + { + return Code((isValue ? "$" : "") + name + " = " + getParsers().toString(value, 0, 0, this, getProtocols(), isGenerateComments()) + (generateComments ? "; //Object of " + value.getClass().getName() + ": \"" + value + "\" inserted manually! Stored by \"" + name + "\" variable!" : "")); + } + + /** + * @param cls | Class to invoke static member on! + * @param staticMethodName | Name of static member! + * @param args | Arguments of method (use this only if you are invoking method no field)! + * + * @return Static member invocation in JUSS form to serialize as [class]::[method | field] [args]... + *

Note: This will not invoke member from class directly, it will be invoked during unserialization, also no checks are performed here so this will not notify you if member or class does not exist!
+ * Also this will work only in combination {@link ObjectConverter}! + * + * @since 1.2.2 + */ + public String StaticMember(Class cls, String staticMethodName, Object... args) + { + StringBuilder sb = new StringBuilder(); + for (int i = 0, len = args.length; i < len; i++) + sb.append(getParsers().toString(args[i], 0, 0, this, getProtocols(), isGenerateComments())).append(i < len-1 ? " " : ""); + return Code(cls.getName() + "::" + staticMethodName + (args.length <= 0 ? "" : " ") + sb); + } + + /** + * @param source | Source {@link Appendable} to serialize variables and objects into! + * @param args | Additional arguments to use, in case of {@link JussSerializer} this should be array of length 6 with 0. argument being this pointer to this serializer, argument 1. and 2. being integers signifying number of tabs and index of parsing iteration (used primarily by {@link ObjectConverter}), argument 3. containing {@link ProtocolRegistry} of this {@link Serializer}, argument 4. being of type {@link Class} containing information about class that is curently being serialized (used primarily by {@link ObjectConverter}), and argument 5. being boolean signifying whether or not code comments are supposed to be generated! + * + * @return Source {@link Appendable} with variables and objects serialized in specific format. + * + * @since 1.3.2 + */ + @SuppressWarnings("unchecked") + @Override + public A SerializeTo(A source, Object... args) throws IOException + { + Map variables = variables(); + List objs = values(); + int valuesLen = objs.size(), varLen = variables.size(), i = 0, tabs = 0; + + if (args.length < 6) + args = Arrays.copyOf(args, 6); + args[0] = this; + if (args[1] == null) + args[1] = tabs; //tabs + else if (args[1] instanceof Integer) + tabs = (int) args[1]; + if (args[2] == null) + args[2] = 0; //index + if (args[3] == null) + args[3] = getProtocols(); + if (args[5] == null) + args[5] = isGenerateComments(); + + source = source == null ? (A) new StringBuilder() : source; + if (generateComments && varLen + valuesLen > 0) //Gen scope comment + { + if (tabs <= 0) + source.append("//Date created: ").append(new SimpleDateFormat("MM-dd-yyyy 'at' HH:mm:ss z \n\n").format(new Date())); + source.append(multilpy('\t', tabs)).append("//Scope serialization summary:\n"); + if (varLen > 0) + source.append(multilpy('\t', tabs)).append("//").append(varLen+"").append(" variables!\n"); + + if (valuesLen > 0) + source.append(multilpy('\t', tabs)).append("//").append(valuesLen+"").append(" values!\n"); + if (tabs > -1) + source.append('\n'); + } + + ParserRegistry reg = getParsers(); + + if (varLen > 0) + { + for (Entry var : variables.entrySet()) //Vars + { + appandVar(source, reg.toString(var, args), var, tabs, i >= varLen-1 && valuesLen <= 0); + if (generateComments && (!(var.getValue() instanceof Scope) || ((Scope) var.getValue()).isEmpty())) + GenerateComment(source, reg, var); + + if (i++ < varLen-1 || valuesLen > 0) + source.append('\n'); + } + } + + for (i = 0; i < valuesLen; i++) //Values + { + Object obj = objs.get(i); + CharSequence serialized = reg.toString(obj, args); + + appandVal(source, serialized, obj, tabs, i >= valuesLen-1); + if (generateComments && (!(obj instanceof Scope) || ((Scope) obj).isEmpty())) + GenerateComment(source, reg, obj); + + if (i < valuesLen-1) + source.append('\n'); + } + + if (source instanceof Flushable) + ((Flushable) source).flush(); + if (tabs == 0) + getImports().removeImportsOf(this); + return source; + } + + /** + * This should append serializedVar into source based on arguments, add separator and return source! + * + * @since 1.3.2 + */ + protected Appendable appandVar(Appendable source, CharSequence serializedVar, Entry var, int tabs, boolean isLast) throws IOException + { + source.append(multilpy('\t', tabs)).append(serializedVar); + if (isLast && var.getValue() instanceof Scope) + return source; + return source.append(';'); + } + + /** + * This should append serializedVal into source based on arguments, add separator and return source! + * + * @since 1.3.2 + */ + protected Appendable appandVal(Appendable source, CharSequence serializedVal, Object value, int tabs, boolean isLast) throws IOException + { + source.append(multilpy('\t', tabs)).append(serializedVal); + if (isLast && value instanceof Scope || serializedVal != null && indexOfNotInObj(serializedVal, '/') != -1) + return source; + return source.append(';'); + } + + /** + * @return Generated description for obj, appended in source! + * + * @since 1.3.2 + */ + public Appendable GenerateComment(Appendable source, ParserRegistry registry, Object obj) throws IOException + { + try + { + CharSequence comment = registry.getConverterFor(obj).getDescription(registry, obj); + if (comment.length() > 0) + return source.append(" //").append(comment); + } + catch (Exception e) + { + return source.append(" //").append(DataConverter.getDefaultDescriptionFor(obj)); + } + return source; + } + + /** + * @param reader | Reader to read from! + * @param formatingArgs | Additional arguments to use. In case of JussSerializer, this should be array of length 4 with 0. argument will being this pointer of this scope (it can be also boolean signifying if formating is required), 1. and 2. argument are null (they are used by JUSS parsers) and argument 3. will be {@link ProtocolRegistry} used by this {@link Serializer}, and additional argument 4. being of type {@link Class} containing information about class that is curently being serialized (used primarily by {@link ObjectConverter}). + * + * @return This scope after loading data from reader (you most likely want to return "this")! + * + * @since 1.3.2 + */ + @SuppressWarnings("unchecked") + @Override + public S LoadFrom(Reader reader, Object... args) + { + boolean formatRequired = true; + + if (args.length < 4) + args = Arrays.copyOf(args, 4); + if (args[0] instanceof Boolean) + formatRequired = (boolean) args[0]; + args[0] = this; + if (args[3] == null) + args[3] = getProtocols(); + + String str = readAndFormat(reader, formatRequired); + List objs = splitAndParse(str, 0, args); + addAll(objs); + + //double t0 = System.nanoTime(); + /*Registry reg = DataParser.REGISTRY; + String lastLine = null; + int quote = 0, multLineCom = -1, brackets = 0; + try + { + BufferedReader lineReader = new BufferedReader(reader); + //String blanks = new String(new char[] {32, 9, 10, 12, 13}); + for (String line = lineReader.readLine(); line != null; line = lineReader.readLine()) + { + for (int i = 0, len = line.length(), com = -1, lastIndex = 0; i < len; i++) + { + char ch = line.charAt(i); + if (ch == '/' && i < len-1 && line.charAt(i+1) == '/') + com++; + else if (multLineCom <= -1 && ch == '"') + quote++; + + boolean notString = quote % 2 == 0; + if (multLineCom > -1 || com > -1) //Is comment + { + if (multLineCom > 0 && ch == '*' && i < len-1 && line.charAt(++i) == '/') + com = multLineCom = -1; + } + else if (notString && ch == '/' && i < len-1 && line.charAt(i+1) == '*') + i += multLineCom = 1; + /*else if (notString && blanks.indexOf(ch) > -1) + { + if ((chBefore = i > 0 ? line.charAt(i-1) : 0) != ';' && chBefore != '{' && blanks.indexOf(chBefore) <= -1) + sb.append(" "); + }*/ + /*else if (notString && i < str.length()-1 && (ch == '!' && str.charAt(i+1) == '!' || ch == '-' && str.charAt(i+1) == '-' || ch == '+' && str.charAt(i+1) == '+')) + i++;* + else + { + if (notString) + { + if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing opening bracket in: " + line); + } + else if (brackets == 0 && (ch == ';' || ch == ',')) + { + //System.out.println(lastIndex + " " + i); + String str = line.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i); + //System.out.println(str); + if (!(str = str.trim()).isEmpty()) + { + Object obj = ParseObjectHandleNull(reg, str, true, result); + if (obj != VOID) + result.add(obj); + } + } + } + } + } + lastLine = line; + } + lineReader.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + //double t = System.nanoTime(); + //System.out.println((t-t0)/1000000); + + if (lastLine != null && indexOfNotInObj(lastLine, ';', ',') <= -1) + { + if (!(lastLine = lastLine.trim()).isEmpty()) + { + Object obj = ParseObjectHandleNull(reg, lastLine, true, result); + if (obj != VOID) + result.add(obj); + } + }*/ + + if (parent == null) + getImports().removeImportsOf(this); + else + for (Map.Entry ent : parent.varEntrySet()) + if (variables().get(ent.getKey()) == ent.getValue()) + variables().remove(ent.getKey()); + return (S) this; + } + + /** + * @return Formated content of reader ready to parse! + * + * @since 1.3.2 + */ + protected String readAndFormat(Reader reader, boolean format) + { + int quote = 0, multLineCom = -1; + //int brackets = 0, lastIndex = 0, delChars = 0; + StringBuilder sb = new StringBuilder(); + + try + { + BufferedReader lineReader = new BufferedReader(reader); + //String blanks = new String(new char[] {32, 9, 10, 12, 13}); + for (String line = lineReader.readLine(); line != null; line = lineReader.readLine()) + { + if (format) + { + int lastNotBlank = -1; + for (int i = 0, com = -1, len = line.length(); i < len; i++) + { + char ch = line.charAt(i); + + boolean notString = quote % 2 == 0; + if (multLineCom > -1 || com > -1) //Is comment + { + if (multLineCom > 0 && ch == '*' && i < len-1 && line.charAt(++i) == '/') + com = multLineCom = -1; + } + else if (notString && ch == '/' && i < len-1) + { + if (line.charAt(i+1) == '*') + i += multLineCom = 1; + else if (line.charAt(i+1) == '/') + com++; + else + sb.append('/'); + } + else if (notString && ch >= 9 && ch <= 13) + sb.append(' '); + else + { + /*if (notString) + { + if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing opening bracket in: " + line); + } + else if (brackets == 0 && isOneOf(ch, ';', ',')) + { + System.out.println(sb); + sb = new StringBuilder(); + continue; + } + }*/ + if (ch > 32) + { + lastNotBlank = ch; + if (ch == '"') + quote++; + } + sb.append(ch); + } + } + sb.append(lastNotBlank == '}' || lastNotBlank == ']' ? ';' : ' '); + } + else + sb.append(line).append('\n'); + } + lineReader.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + + return sb.toString(); + } + + /** + * @return List of objects parsed from given formatted string! + * + * @since 1.3.2 + */ + protected List splitAndParse(String formattedStr, int offset, Object... parserArgs) + { + List result = new ArrayList<>(); + + ParserRegistry reg = getParsers(); + + //DataParser[] parsers = new DataParser[DataParser.REGISTRY.size()]; + int brackets = 0, quote = 0, lastIndex = 0; + //boolean isBracketSplit = false; + for (int i = 0, len = formattedStr.length(); i < len; i++) + { + char ch = formattedStr.charAt(i); + if (ch == '"') + quote++; + + if (quote % 2 == 0) + { + /*if (isBracketSplit) + add = 0; + isBracketSplit = false;*/ + if (brackets == 0 && (ch == ';' || ch == ',')/* || (brackets == 1 && (isBracketSplit = ch == '}' || ch == ']'))*/) + { + String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i /*+ (isBracketSplit ? 1 : 0)*/); + if (!(str = str.trim()).isEmpty()) + { + Object obj = parseObject(reg, str, parserArgs); + if (obj != VOID) + result.add(obj); + } + //add = 1; + } + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing opening bracket in: " + formattedStr); + } + } + } + + if (quote % 2 != 0) + throw new IllegalArgumentException("Unclosed or missing quotes in: " + formattedStr); + else if (brackets > 0) + throw new IllegalArgumentException("Unclosed brackets in: " + formattedStr); + else + { + String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, formattedStr.length()); + if (!(str = str.trim()).isEmpty()) + { + Object obj = parseObject(reg, str, parserArgs); + if (obj != VOID) + result.add(obj); + } + } + + return result; + } + +// /** +// * @return Object converted to string! +// *

+// * Note: Used by {@link JussSerializer#SerializeTo(Appendable, Object...)}! +// * +// * @see DataConverter#objToString(Registry, String, Object...) +// * +// * @since 1.3.5 +// */ +// public CharSequence objectToStr(Registry registry, Object obj, Object... parserArgs) +// { +// return +// } + + /** + * @return Object parsed from str! + *

+ * Note: Used by {@link JussSerializer#splitAndParse(String, int, Object...)}! + * + * @see DataParser#parseObj(Registry, String, Object...) + * + * @since 1.3.2 + */ + protected Object parseObject(ParserRegistry registry, String str, Object... parserArgs) + { + return NULL.toOopNull(registry.parse(str, parserArgs)); + } + + /** + * @param variable | Variable to clone! + * + * @return Clone of value stored by variable with inserted name or null if there is no such a one! + *

+ * Note: Cloning is done by {@link Serializer#Clone(Object, Registry, Object[], Object...))}! + * + * @since 1.3.2 + */ + public T cloneOf(String variableName) + { + return cloneOf(variableName, null); + } + + /** + * @param variable | Variable to clone! + * @param defaultValue | Default value to return. + * + * @return Clone of value stored by variable with inserted name or defaultValue if there is no such a one! + *

+ * Note: Cloning is done by {@link Serializer#Clone(Object, Registry, Object[], Object...))}! + * + * @since 1.3.2 + */ + public T cloneOf(String variableName , T defaultValue) + { + T obj = get(variableName , defaultValue); + if (obj == defaultValue) + return defaultValue; + return Serializer.Clone(obj, getParsers(), new Object[] {-99999, 0, this, getProtocols(), isGenerateComments()}, this, null, null, getProtocols()); + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Clone of independent value with valueIndex! + *

+ * Note: Cloning is done by {@link Serializer#Clone(Object, Registry, Object[], Object...))}! + * + * @since 1.3.2 + */ + public T cloneOf(int valueIndex) + { + T obj = get(valueIndex); + return Serializer.Clone(obj, getParsers(), new Object[] {-99999, 0, this, getProtocols(), isGenerateComments()}, this, null, null, getProtocols()); + } + + /** + * @return True if comment supposed to be generated! + * + * @since 1.3.2 + */ + public boolean isGenerateComments() + { + return generateComments; + } + + /** + * @param generateComments | If true, comments will be generated during serialization! + * + * @since 1.3.2 + */ + public void setGenerateComments(boolean generateComments) + { + this.generateComments = generateComments; + } + +// /** +// * @return True if used parsers and converters are cached during individual serializations and deserializations! This can improve performance a lot but in some cases might cause some strange artifacts! +// * +// * @since 1.3.5 +// * +// * @see ParserRegistry#resetCache() +// */ +// public boolean isSerializationAutoCaching() +// { +// return serializationAutoCaching; +// } +// +// /** +// * @param serializationAutoCaching | Set this on true to allow caching of used parsers and converters during individual serializations and deserializations! This can improve performance a lot but in some cases might cause some strange artifacts! +// * +// * @since 1.3.5 +// * +// * @see ParserRegistry#resetCache() +// * @see ParserRegistry#destroyCache() +// */ +// public void setSerializationAutoCaching(boolean serializationAutoCaching) +// { +// if (!(this.serializationAutoCaching = serializationAutoCaching)) +// getParsers().destroyCache(); +// } + + /** + * @param fromObj | Object to create serializer from! + * + * @return {@link JussSerializer} created from given fromObj by mapping obj's fields into variables of created serializer via given fields (fieldNamesToUse) and conversion rules listed below!!

+ * Table of specific Object --> JussSerializer conversions: + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Object (fromObj) typeObtained serializer content (return)
{@link CharSequence}{@link Serializer#LoadFrom(CharSequence)}
{@link CharSequence} (as http address)Serializer (newInstance) will open connection with url and get + deserialize the content from it if possible!
{@link File}{@link Serializer#LoadFrom(File)}
{@link Reader}{@link Serializer#LoadFrom(Reader)}
{@link InputStream}{@link Serializer#LoadFrom(InputStream)}
{@link URL}Serializer (newInstance) will open connection with {@link URL} and get + deserialize the content from it if possible!
{@link URLConnection}Serializer (newInstance) will attempt to get + deserialize the content from given {@link URLConnection} if possible!
Others (default){@link Scope#from(Object, String...)} (return description)
+ * + * @throws When something went wrong during deserialization! + * + * @since 1.3.5 + */ + public static JussSerializer from(Object fromObj) throws Exception + { + try + { + return from(fromObj, new String[0]); + } + catch (IntrospectionException e) + { + return new JussSerializer(fromObj); + } + } + + /** + * @param fromObj | Object to create serializer from! + * @param fieldNamesToUse | Array of obj field names to map into scopes variables using getters (read method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link GenericScope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! + * + * @return {@link JussSerializer} created from given fromObj by mapping obj's fields into variables of created serializer via given fields (fieldNamesToUse) and conversion rules listed below!!

+ * Table of specific Object --> JussSerializer conversions: + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Object (fromObj) typeObtained serializer content (return)
{@link CharSequence}{@link Serializer#LoadFrom(CharSequence)}
{@link CharSequence} (as http address)Serializer (newInstance) will open connection with url and get + deserialize the content from it if possible!
{@link File}{@link Serializer#LoadFrom(File)}
{@link Reader}{@link Serializer#LoadFrom(Reader)}
{@link InputStream}{@link Serializer#LoadFrom(InputStream)}
{@link URL}Serializer (newInstance) will open connection with {@link URL} and get + deserialize the content from it if possible!
{@link URLConnection}Serializer (newInstance) will attempt to get + deserialize the content from given {@link URLConnection} if possible!
Others (default){@link Scope#from(Object, String...)} (return description)
+ * + * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often) or when something went wrong during deserialization! + * @throws IntrospectionException when there were no PropertyDescriptor found for obj class! + * + * @since 1.3.5 + */ + public static JussSerializer from(Object fromObj, String... fieldNamesToUse) throws IntrospectionException, Exception + { + return (JussSerializer) Serializer.from(new JussSerializer(), fromObj, fieldNamesToUse); + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java b/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java new file mode 100644 index 0000000..79c3039 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java @@ -0,0 +1,63 @@ +package org.ugp.serialx; + +/** + * Log provider used for logging in SerialX. + * You can use to to easily implement log4j or other logging utilities. + * + * @author PETO + * + * @since 1.3.5 + */ +public class LogProvider +{ + protected boolean reThrowException; + + public static LogProvider instance = new LogProvider(); + + /** + * @param object | Object to log in normal mode! + * + * @since 1.3.5 + */ + public void logOut(Object object) + { + System.out.println(object); + } + + /** + * @param object | Object to log in error mode! + * @param ex | Exception that cause the error! + * + * @since 1.3.5 + */ + public void logErr(Object obj, Throwable ex) + { + if (reThrowException) + { + if (ex == null) + throw new RuntimeException(obj.toString()); + throw new RuntimeException(ex); + } + System.err.println(obj); + } + + /** + * @return If true, exception or error object will be rethrown as {@link RuntimeException} by {@link LogProvider#logErr(Object, Throwable)}! + * + * @since 1.3.5 + */ + public boolean isReThrowException() + { + return reThrowException; + } + + /** + * @param reThrowException | If true, exception or error object will be rethrown as {@link RuntimeException} by {@link LogProvider#logErr(Object, Throwable)}! + * + * @since 1.3.5 + */ + public void setReThrowException(boolean reThrowException) + { + this.reThrowException = reThrowException; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Registry.java b/SerialX-core/src/main/java/org/ugp/serialx/Registry.java new file mode 100644 index 0000000..ba26bc7 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/Registry.java @@ -0,0 +1,404 @@ +package org.ugp.serialx; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * This is list that can contains only one element per class! Trying to add 2 elements with same class will cause old one to be removed and new one will be added! + * + * @author PETO + * + * @param | The type of elements held in this collection + * + * @since 1.3.0 + */ +public class Registry extends ArrayList +{ + private static final long serialVersionUID = 1L; + + /** + * Constructs an {@link Registry} with the specified initial capacity. + * + * @param initialSize | Initial capacity. + * + * @since 1.3.0 + */ + public Registry(int initialSize) + { + super(initialSize); + } + + /** + * Constructs an {@link Registry} with content of c. + * + * @param c | Initial content of registry. + * + * @since 1.3.0 + */ + public Registry(Collection c) + { + super(c); + } + + /** + * Constructs an {@link Registry} with objs. + * + * @param objs | Initial content of registry. + * + * @since 1.3.0 + */ + @SafeVarargs + public Registry(E... objs) + { + addAll(objs); + } + + @Override + public Registry clone() + { + return new Registry<>(this); + } + + @Override + public boolean addAll(Collection c) + { + return addAll(size(), c); + } + + @Override + public boolean addAll(int index, Collection c) + { + for (E s : c) + add(index++, s); + return true; + } + + @Override + public boolean add(E e) + { + add(size(), e); + return true; + } + + @SuppressWarnings("unchecked") + @Override + public void add(int index, E element) + { + E contained = get((Class) element.getClass()); + if (contained != null) + remove(contained); + super.add(index, element); + } + + /** + * @param exclude | Class of elements to exclude! + * + * @return Clone of this registry, excluding elements of inserted classes! + * + * @since 1.3.0 + */ + public Registry clone(Class... exclude) + { + Registry clone = clone(); + + for (int i = clone.size() - 1; i >= 0; i--) + { + E e = clone.get(i); + for (Class cls : exclude) + if (e.getClass() == cls) + clone.remove(e); + } + return clone; + } + + /** + * Similar to regular add however this one will not remove existing element if duplicate (should not be public)! + * Essentially it will simply do super.add(index, element)! + * + * @param index | Index at which the specified element is to be inserted! + * @param element | Element to add! + * + * @since 1.3.0 + */ + protected void addDuplicatively(int index, E element) + { + super.add(index, element); + } + + /** + * @param elms | Array o elements to add! + * + * @return {@link Registry#addAll(int, Object...)} + * + * @since 1.3.0 + */ + public void addAll(@SuppressWarnings("unchecked") E... elms) + { + addAll(size(), elms); + } + + /** + * @param elms | Array o elements to add! + * + * @return {@link Registry#addAll(int, Collection)} + * + * @since 1.3.0 + */ + public void addAll(int index, @SuppressWarnings("unchecked") E... elms) + { + for (E s : elms) + add(index++, s); + } + + /** + * @param elm | Class of element to add! + * + * @return Instantiated obj of inserted class that was added. Empty constructor required! + * + * @throws Exception + * + * @since 1.3.0 + */ + public E add(Class elm) throws Exception + { + E inst = elm.getConstructor().newInstance(); + add(inst); + return inst; + } + + /** + * @param elms | Array of classes to be instantiated and added! + * + * @throws Exception + * + * @since 1.3.0 + */ + public void addAll(@SuppressWarnings("unchecked") Class... elms) throws Exception + { + for (Class cls : elms) + add(cls); + } + + /** + * @param cls | Class to find! + * @param element | Element to insert before index of required class! + * + * @since 1.3.0 + */ + public void addBefore(Class cls, E element) + { + addBefore(cls, false, element); + } + + /** + * @param cls | Class to find! + * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! + * @param element | Element to insert before index of required class! + * + * @since 1.3.0 + */ + public void addBefore(Class cls, boolean includeChildrens, E element) + { + int index = indexOf(cls); + if (index <= -1) + add(element); + else + add(index, element); + } + + /** + * @param cls | Class to find! + * @param element | Element to insert after index of required class! + * + * @since 1.3.0 + */ + public void addAllBefore(Class cls, @SuppressWarnings("unchecked") E... element) + { + addAllBefore(cls, false, element); + } + + /** + * @param cls | Class to find! + * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! + * @param element | Element to insert after index of required class! + * + * @since 1.3.0 + */ + public void addAllBefore(Class cls, boolean includeChildrens, @SuppressWarnings("unchecked") E... element) + { + int index = indexOf(cls); + if (index <= -1) + addAll(element); + else + addAll(index, element); + } + + /** + * @param cls | Class to find! + * @param element | Element to insert after index of required class! + * + * @since 1.3.0 + */ + public void addAfter(Class cls, E element) + { + addAfter(cls, false, element); + } + + /** + * @param cls | Class to find! + * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! + * @param element | Element to insert after index of required class! + * + * @since 1.3.0 + */ + public void addAfter(Class cls, boolean includeChildrens, E element) + { + int index = indexOf(cls, includeChildrens); + if (index <= -1) + add(element); + else + add(index + 1, element); + } + + /** + * @param cls | Class to find! + * @param element | Element to insert after index of required class! + * + * @since 1.3.0 + */ + public void addAllAfter(Class cls, @SuppressWarnings("unchecked") E... element) + { + addAllAfter(cls, false, element); + } + + /** + * @param cls | Class to find! + * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! + * @param element | Element to insert after index of required class! + * + * @since 1.3.0 + */ + public void addAllAfter(Class cls, boolean includeChildrens, @SuppressWarnings("unchecked") E... element) + { + int index = indexOf(cls, includeChildrens); + if (index <= -1) + addAll(element); + else + addAll(index + 1, element); + } + + /** + * @param cls | Class to get instance for! + * + * @return Element of class or null if there is no such a one! + * + * @since 1.3.0 + */ + public C get(Class cls) + { + return get(cls, false); + } + + /** + * @param cls | Class to get instance for! + * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! + * + * @return Element of class according to includeChildrens flag or null if there is no such a one! + * + * @since 1.3.0 + */ + @SuppressWarnings("unchecked") + public C get(Class cls, boolean includeChildrens) + { + C obj = null; + for (int i = 0, size = size(); i < size; i++) + { + C elm = (C) get(i); + Class objCls = elm.getClass(); + if (objCls == cls) + return elm; + else if (includeChildrens && cls.isAssignableFrom(objCls)) + obj = elm; + } + return obj; + } + + /** + * @param cls | Instances class to get index of! + * + * @return Index of element with required class or -1 if there is no such a one! + * + * @since 1.3.0 + */ + public int indexOf(Class cls) + { + return indexOf(cls, false); + } + + /** + * @param cls | Instances class to get index of! + * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! + * + * @return Index of element with class according to includeChildrens flag or -1 if there is no such a one! + * + * @since 1.3.0 + */ + public int indexOf(Class cls, boolean includeChildrens) + { + int index = -1; + for (int i = 0; i < size(); i++) + { + Class objCls = get(i).getClass(); + if (objCls == cls) + return i; + else if (includeChildrens && cls.isAssignableFrom(objCls)) + index = i; + } + return index; + } + + /** + * @param cls | Class of element to remove! + * + * @return Removed element itself! + * + * @since 1.3.0 + */ + public E remove(Class cls) + { + return remove(cls, false); + } + + + /** + * @param cls | Class of element to remove! + * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! + * + * @return Removed element itself or null if there is no element with cls! + * + * @since 1.3.0 + */ + public E remove(Class cls, boolean includeChildrens) + { + int i = indexOf(cls, includeChildrens); + if (i > -1) + return remove(i); + return null; + } + + + /** + * @param newContent | New content to set, old one will be deleted! + * + * @return Registry with previous content! + * + * @since 1.3.0 + */ + public Registry setTo(Registry newContent) + { + Registry old = clone(); + clear(); + addAll(newContent); + return old; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java new file mode 100644 index 0000000..baa1551 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java @@ -0,0 +1,1285 @@ +package org.ugp.serialx; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Map.Entry; +import java.util.function.Predicate; + +import org.ugp.serialx.converters.ArrayConverter; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.protocols.SerializationProtocol; +import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; + + +/** + * This is some kind of hybrid between {@link List} and {@link Map} which allow you to have both variables and independent values managed by one Object.
+ * Note: Variables are managed and accessed classically via {@link Map} methods such as put(String key, Object) and array of independent values is accessed by via {@link List} methods such as add(Object) and get(int)
+ * Also this is java representation of JUSS Scope group such as: + *
+ * 
+ * {
+ *     //This is scope in JUSS!
+ * }
+ * 
+ * 
+ * + * @author PETO + * + * @since 1.2.0 and since 1.3.5 splitted to {@link Scope} and {@link GenericScope} + */ +public class Scope extends GenericScope +{ + private static final long serialVersionUID = 4693418156224566721L; + + /** + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.5 + */ + @SafeVarargs + public Scope(Object... values) + { + this(null, values); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.5 + */ + @SafeVarargs + public Scope(Map variablesMap, Object... values) + { + this(variablesMap, values == null ? null : Arrays.asList(values)); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.5 + */ + public Scope(Map variablesMap, Collection values) + { + this(variablesMap, values, null); + } + + /** + * @param sourceScope | Scope with initial content! + * + * @since 1.3.5 + */ + public Scope(GenericScope sourceScope) + { + this(sourceScope == null ? null : sourceScope.variables(), sourceScope == null ? null : sourceScope.values()); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * @param | Parent of this scope. + + * @since 1.3.5 + */ + public Scope(Map variablesMap, Collection values, GenericScope parent) + { + super(variablesMap, values, parent); + } + + @Override + public Scope clone() + { + return (Scope) super.clone(); + } + + /** + * @param variableName | Variables name. + * + * @return Byte value of variable with name or 0 if there is no such a one! + * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public byte getByte(String variableName) + { + return getByte(variableName, (byte) 0); + } + + /** + * @param variableName | Variables name. + * @param defaultValue | Default value to return. + * + * @return Byte value of variable with name or defaultValue if there is no such a one! + * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public byte getByte(String variableName, byte defaultValue) + { + return (byte) getInt(variableName, defaultValue); + } + + /** + * @param variableName | Variables name. + * + * @return Byte value of variable with name or 0 if there is no such a one! + * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public short getShort(String variableName) + { + return getShort(variableName, (short) 0); + } + + /** + * @param variableName | Variables name. + * @param defaultValue | Default value to return. + * + * @return Byte value of variable with name or defaultValue if there is no such a one! + * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public short getShort(String variableName, short defaultValue) + { + return (short) getInt(variableName, defaultValue); + } + + /** + * @param variableName | Variables name. + * + * @return Int value of variable with name or 0 if there is no such a one! + * Int will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public int getInt(String variableName) + { + return getInt(variableName, 0); + } + + /** + * @param variableName | Variables name. + * @param defaultValue | Default value to return. + * + * @return Int value of variable with name or defaultValue if there is no such a one! + * Int will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public int getInt(String variableName, int defaultValue) + { + return (int) getLong(variableName, defaultValue); + } + + /** + * @param variableName | Variables name. + * + * @return Long value of variable with name or 0 if there is no such a one! + * Long will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public int getLong(String variableName) + { + return getInt(variableName, 0); + } + + /** + * @param variableName | Variables name. + * @param defaultValue | Default value to return. + * + * @return Long value of variable with name or defaultValue if there is no such a one! + * Long will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public long getLong(String variableName, long defaultValue) + { + return (long) getDouble(variableName, defaultValue); + } + + /** + * @param variableName | Variables name. + * + * @return Float value of variable with name or 0 if there is no such a one! + * Float will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public float getFloat(String variableName) + { + return getFloat(variableName, 0); + } + + /** + * @param variableName | Variables name. + * @param defaultValue | Default value to return. + * + * @return Float value of variable with name or defaultValue if there is no such a one! + * Float will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public float getFloat(String variableName, float defaultValue) + { + return (float) getDouble(variableName, defaultValue); + } + + /** + * @param variableName | Variables name. + * + * @return Double value of variable with name or 0 if there is no such a one! + * Double will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public double getDouble(String variableName) + { + return getDouble(variableName, 0); + } + + /** + * @param variableName | Variables name. + * @param defaultValue | Default value to return. + * + * @return Double value of variable with name or defaultValue if there is no such a one! + * Double will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public double getDouble(String variableName, double defaultValue) + { + Object obj = get(variableName, defaultValue); + if (obj instanceof Number) + return ((Number) obj).doubleValue(); + else if (obj instanceof Character) + return (double) (char) obj; + else if (obj instanceof CharSequence) + return Double.parseDouble(obj.toString()); + return (double) obj; + } + + /** + * @param variableName | Variables name. + * + * @return String value of variable with name or null if there is no such a one! + * String will be also parsed from any object using {@link Object#toString()}! + * + * @since 1.2.5 + */ + public String getString(String variableName) + { + return getString(variableName, null); + } + + /** + * @param variableName | Variables name. + * @param defaultValue | Default value to return. + * + * @return String value of variable with name or defaultValue if there is no such a one! + * String will be also parsed from any object using {@link Object#toString()}! + * + * @since 1.2.5 + */ + public String getString(String variableName, String defaultValue) + { + Object obj = get(variableName, defaultValue); + return obj == null ? null : obj.toString(); + } + + /** + * @param variableName | Variables name. + * + * @return Char value of variable with name or {@code (char) 0} if there is no such a one! + * Char will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public char getChar(String variableName) + { + return getChar(variableName, (char) 0); + } + + /** + * @param variableName | Variables name. + * @param defaultValue | Default value to return. + * + * @return Char value of variable with name or defaultValue if there is no such a one! + * Char will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public char getChar(String variableName, char defaultValue) + { + Object obj = get(variableName, defaultValue); + if (obj instanceof Character) + return (char) obj; + else if (obj instanceof CharSequence) + return ((CharSequence) obj).charAt(0); + else if (obj instanceof Number) + return (char) ((Number) obj).intValue(); + return (char) obj; + } + + /** + * @param variableName | Variables name. + * + * @return Boolean value of variable with name or false if there is no such a one! + * Boolean will be also parsed from {@link Number}, or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public boolean getBool(String variableName) + { + return getBool(variableName, false); + } + + /** + * @param variableName | Variables name. + * @param defaultValue | Default value to return. + * + * @return Boolean value of variable with name or defaultValue if there is no such a one! + * Boolean will be also parsed from {@link Number}, or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public boolean getBool(String variableName, boolean defaultValue) + { + Object obj = get(variableName, defaultValue); + if (obj instanceof Boolean) + return (boolean) obj; + else if (obj instanceof Number) + return ((Number) obj).doubleValue() > 0; + else + { + String str = obj.toString(); + if (str.equalsIgnoreCase("t")) + return true; + else if (str.equalsIgnoreCase("f")) + return false; + return Boolean.parseBoolean(obj.toString()); + } + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Independent byte value with valueIndex. + * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public byte getByte(int valueIndex) + { + return (byte) getInt(valueIndex); + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Independent short value with valueIndex. + * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public short getShort(int valueIndex) + { + return (short) getInt(valueIndex); + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Independent int value with valueIndex. + * Int will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public int getInt(int valueIndex) + { + return (int) getLong(valueIndex); + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Independent long value with valueIndex. + * Long will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public long getLong(int valueIndex) + { + return (long) getDouble(valueIndex); + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Independent float value with valueIndex. + * Float will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public float getFloat(int valueIndex) + { + return (float) getDouble(valueIndex); + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Independent double value with valueIndex. + * Double will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public double getDouble(int valueIndex) + { + Object obj = get(valueIndex); + if (obj instanceof Number) + return ((Number) obj).doubleValue(); + else if (obj instanceof Character) + return (double) (char) obj; + else if (obj instanceof CharSequence) + return Double.parseDouble(obj.toString()); + return (double) obj; + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Independent string value with valueIndex. + * String will be also parsed from any object using {@link Object#toString()}! + * + * @since 1.2.5 + */ + public String getString(int valueIndex) + { + Object obj = get(valueIndex); + return obj == null ? null : obj.toString(); + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Independent char value with valueIndex. + * Char will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public char getChar(int valueIndex) + { + Object obj = get(valueIndex); + if (obj instanceof Character) + return (char) obj; + else if (obj instanceof CharSequence) + return ((CharSequence) obj).charAt(0); + else if (obj instanceof Number) + return (char) ((Number) obj).intValue(); + return (char) obj; + } + + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * + * @return Independent boolean value with valueIndex. + * Boolean will be also parsed from {@link Number}, or {@link CharSequence} if possible! + * + * @since 1.2.5 + */ + public boolean getBool(int valueIndex) + { + Object obj = get(valueIndex); + if (obj instanceof Boolean) + return (boolean) obj; + else if (obj instanceof Number) + return ((Number) obj).doubleValue() > 0; + else + { + String str = obj.toString(); + if (str.equalsIgnoreCase("t")) + return true; + else if (str.equalsIgnoreCase("f")) + return false; + return Boolean.parseBoolean(obj.toString()); + } + } + + /** + + + * @param scopeValueIndex | Index of sub-scopes value. + * + * @return Sub-scope on required index or null if there is no scope on required index!
+ * Note: Keep in mind that you need to insert valid index according to other values. Scopes share same index order with other values! + * + * @since 1.2.0 + */ + public Scope getScope(int scopeValueIndex) + { + try + { + return (Scope) this.getGenericScope(scopeValueIndex); + } + catch (ClassCastException e) + { + return null; + } + } + + /** + * @param scopesOrderIndex | Order index of sub-scope. + * + * @return Sub-scope with required number. Similar to {@link Scope#getScope(int)} however this will ignore non scope values. + *

+ * For instance getSubScope(1) in context:
+ *
+	 * 
+	 * variable = "something";
+	 * "something";
+	 * {
+	 *      "Scope0"
+	 * };
+	 * 123;
+	 * null;
+	 * {
+	 *      "Scope1" <- This one will be returned!
+ * }; + * 4; + * 5; + * 6; + * { + * "Scope2" + * } + *
+ *
+ * + * @since 1.2.0 + */ + public Scope getSubScope(int subscopesOrderIndex) + { + for (int i = 0, j = 0; i < valuesCount(); i++) + { + Scope scope = getScope(i); + if (scope != null && j++ == subscopesOrderIndex) + return scope; + } + return null; + } + + /** + * @param scopesPath | Array with variable names creating path to required scope. + * + * @return Sub-scope stored by variable with required name (last element) in inserted path or null if there is no such a one in inserted path. If there is more than one result, the first one found will be returned! + * This search will also includes sub-scopes of scope but variables from lower ones are prioritize!
+ * If this function is called with no arguments then self will be returned! + *
+ *
+	 * 
+	 * variable = "something";
+	 * scope1 = 
+	 * {
+	 *      subScope = 
+	 *      {
+	 *          scopeObjectoFind = {...}; <- this one will be returned if getScope("scope1", "scopeObjectoFind") is issued!
+	 *          7;...
+	 *      }
+	 * };
+	 * scopeObjectoFind = {...} <- this one will be returned if getScope("scopeObjectoFind") is issued!
+	 * 
+	 * 
+ * Note: Remember that this search includes variables only, no values! + * + * @since 1.2.0 + */ + public Scope getScope(String... scopesPath) + { + try + { + return (Scope) getGenericScope(scopesPath); + } + catch (ClassCastException e) + { + return null; + } + } + + /** + * @param scopesValueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * {@link IndexOutOfBoundsException} will be thrown if index is too big! + * @param objClass | Object of class to create. + * + * @return Object of objClass constructed from independent value with scopesValueIndex! If there is no Scope stored at scopesValueIndex this function behaves same as {@link GenericScope#get(int)}! + * If independent value is {@link GenericScope} like it supposed to, then values of scope are parsed to {@link SerializationProtocol} of objClass. + * Note: Scopes are searched via regular independent value index no scope index like {@link Scope#getScope(int)}. + * + * @see Serializer#PROTOCOL_REGISTRY + * @see GenericScope#toObject(Class) + * + * @throws Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! + * + * @since 1.2.5 + */ + @SuppressWarnings("unchecked") + public T toObjectOf(int scopesValueIndex, Class objClass) throws Exception + { + Object obj = get(scopesValueIndex); + if (obj instanceof GenericScope) + return ((GenericScope) obj).toObject(objClass); + return (T) obj; + } + + /** + * @param variableWithScope | Variable that supposed to contains scope. + * @param objClass | Object of class to create. + * + * @return Value of variable with name or null if there is no such a one! If there is no Scope stored by variableWithScope this function behaves same as {@link Scope#get(String, Object)}! + * If variableWithScope contains {@link GenericScope} like it supposed to, then values of scope are parsed to {@link SerializationProtocol} of objClass. + * + * @see Serializer#PROTOCOL_REGISTRY + * @see GenericScope#toObject(Class) + * + * @throws Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! + * + * @since 1.2.5 + */ + public T toObjectOf(String variableWithscope, Class objClass) throws Exception + { + return toObjectOf(variableWithscope, objClass, null); + } + + /** + * @param variableWithScope | Variable that supposed to contains scope. + * @param objClass | Object of class to create. + * @param defaultValue | Default value to return. + * + * @return Value of variable with name or defaultValue if there is no such a one! If there is no Scope stored by variableWithScope this function behaves same as {@link Scope#get(String, Object)}! + * If variableWithScope contains {@link GenericScope} like it supposed to, then values of scope are parsed to {@link SerializationProtocol} of objClass. + * + * @see Serializer#PROTOCOL_REGISTRY + * @see GenericScope#toObject(Class) + * + * @throws Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! + * + * @since 1.2.5 + */ + public T toObjectOf(String variableWithscope, Class objClass, T defaultValue) throws Exception + { + return toObjectOf(variableWithscope, objClass, defaultValue, SerializationProtocol.REGISTRY); + } + + /** + * @param variableWithScope | Variable that supposed to contains scope. + * @param objClass | Object of class to create. + * @param defaultValue | Default value to return. + * @param protocolsToUse | Registry of protocols to use. + * + * @return Value of variable with name or defaultValue if there is no such a one! If there is no Scope stored by variableWithScope this function behaves same as {@link Scope#get(String, Object)}! + * If variableWithScope contains {@link GenericScope} like it supposed to, then values of scope are parsed to {@link SerializationProtocol} of objClass. + * + * @see Serializer#PROTOCOL_REGISTRY + * @see GenericScope#toObject(Class) + * + * @throws Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! + * + * @since 1.3.2 + */ + @SuppressWarnings("unchecked") + public T toObjectOf(String variableWithscope, Class objClass, T defaultValue, ProtocolRegistry protocolsToUse) throws Exception + { + T obj = get(variableWithscope, defaultValue); + if (obj instanceof GenericScope) + return ((GenericScope) obj).toObject(objClass, protocolsToUse); + return obj; + } + + /** + * @param varName | Variable with name to search! + Expected generic type of possible results, {@link ClassCastException} will be thrown is some variable contains value that can't be cast to this! + * + * @return Values stored by variable with inserted name collected from this scope! + * + * @since 1.3.0 + */ + public List getAllStoredBy(String varName) + { + return getAllStoredBy(varName, true); + } + + /** + * @param varName | Variable with name to search! + * @param includeSubScopes | If true, this search will include sub-scopes as well (variables are iterated first values second)! + * Expected generic type of possible results, {@link ClassCastException} will be thrown is some variable contains value that can't be cast to this! + * + * @return Values stored by variable with inserted name collected from this scope! + * + * @since 1.3.2 + */ + @SuppressWarnings("unchecked") + public List getAllStoredBy(String varName, boolean includeSubScopes) + { + List result = new ArrayList<>(); + + for (Entry var : varEntrySet()) + if (var.getKey().equals(varName)) + result.add((V) var.getValue()); + else if (includeSubScopes && var.getValue() instanceof Scope) + result.addAll(((Scope) var.getValue()).getAllStoredBy(varName, includeSubScopes)); + + for (Object object : this) + if (object instanceof Scope) + result.addAll(((Scope) object).getAllStoredBy(varName, includeSubScopes)); + + return result; + } + + /** + * @param varName | Variable with name to search! + * @param value | Value of variable to search! + * + * @return Scope containing all sub-scopes of this scope that contains variable with required name that is set to required value! + * + * @since 1.3.2 + */ + public Scope getScopesWith(String varName, Object value) + { + return getScopesWith(varName, value, true); + } + + /** + * @param varName | Variable with name to search! + * @param value | Value of variable to search! + * @param includeSubScopes | If true, this search will include sub-scopes as well (variables are iterated first values second)! + * + * @return Scope containing all sub-scopes of this scope that contains variable with required name that is set to required value! + * + * @since 1.3.2 + */ + public Scope getScopesWith(String varName, Object value, boolean includeSubScopes) + { + return getScopesWith(varName, obj -> Objects.deepEquals(obj, value)); + } + + /** + * @param varName | Variable with name to search! + * @param condition | Condition that will be tested for value of each variable! + * + * @return Scope containing all sub-scopes of this scope that contains variable which meets inserted condition! + * + * @since 1.3.2 + */ + public Scope getScopesWith(String varName, Predicate condition) + { + return getScopesWith(varName, condition, true); + } + + /** + * @param varName | Variable with name to search! + * @param condition | Condition that will be tested for value of each variable! + * @param includeSubScopes | If true, this search will include sub-scopes as well (variables are iterated first values second)! + * + * @return Scope containing all sub-scopes of this scope that contains variable which meets inserted condition! + * + * @since 1.3.2 + */ + public Scope getScopesWith(String varName, Predicate condition, boolean includeSubScopes) + { + Scope result = new Scope(null, null, getParent()); + + for (Entry myVar : varEntrySet()) + if (myVar.getValue() instanceof Scope) + try + { + Scope scope = (Scope) myVar.getValue(); + if (scope.containsVariable(varName) && condition.test(scope.get(varName))) + result.add(scope); + else if (includeSubScopes) + result.addAll(scope.getScopesWith(varName, condition, includeSubScopes)); + } + catch (ClassCastException e) + {} + for (Object object : this) + if (object instanceof Scope) + try + { + Scope scope = (Scope) object; + if (scope.containsVariable(varName) && condition.test(scope.get(varName))) + result.add(scope); + else if (includeSubScopes) + result.addAll(scope.getScopesWith(varName, condition, includeSubScopes)); + } + catch (ClassCastException e) + {} + return result; + } + + /** + * @param objClass | Object of class to create using protocols. + * @param protocolsToUse | Registry of protocols to use. + * + * @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}! + * If there were no suitable deserialization protocols found, {@link Scope#into(Class, String...)} will be used! + * + * @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! + * + * @see Scope#into(Class, String...) + * @see Scope#intoNew(Class, GenericScope, String...) + * + * @since 1.3.5 + */ + public T toObject(Class objClass, ProtocolRegistry protocolsToUse) throws Exception + { + T obj = super.toObject(objClass, protocolsToUse); + if (obj != null) + return obj; + + try + { + return into(objClass); + } + catch (Exception e) + { + LogProvider.instance.logErr("Unable to create new instance of " + objClass.getName() + " because none of provided protocols were suitable and class introspection has failed as well!", e); + return null; + } + } + + /** + * @param objCls | Class of object to instantiate! + * @param fieldNamesToUse | Array of objCls field names to map/populate instantiated object from scopes variables using setters (write method)! PropertyDescriptors of these fields will be obtained using Scope.getPropertyDescriptorsOf(Class, String)! This is used only as a last (default) option! + * + * @return New instance of object according to {@link GenericScope#intoNew(Class, GenericScope, String...)} similarly to {@link GenericScope#toObject(Class)} except this one will not use any protocols! + * + * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often)! + * @throws IntrospectionException when there were no {@link PropertyDescriptor} found for obj class! + * + * @see Scope#intoNew(Class, GenericScope, String...) + * + * @since 1.3.5 + */ + public T into(Class objCls, String... fieldNamesToUse) throws IntrospectionException, Exception + { + return (T) intoNew(objCls, this, fieldNamesToUse); + } + + /** + * @param obj | Object to map this scopes variables into! + * @param fieldNamesToUse | Array of objCls field names to map/populate instantiated object from scopes variables using setters (write method)! PropertyDescriptors of these fields will be obtained using Scope.getPropertyDescriptorsOf(Class, String)! This is used only as a last (default) option! + * + * @return New instance of object according to {@link GenericScope#intoNew(Class, GenericScope, String...)} similarly to {@link GenericScope#toObject(Class)} except this one will not use any protocols! + * + * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often)! + * @throws IntrospectionException when there were no {@link PropertyDescriptor} found for obj class! + * + * @see Scope#intoNew(Class, GenericScope, String...) + * + * @since 1.3.5 + */ + public T into(Object obj, String... fieldNamesToUse) throws IntrospectionException, Exception + { + return into(obj, this, fieldNamesToUse); + } + + /** + * @param obj | Object to create scope from! + * @param fieldNamesToUse | Array of obj field names to map into scopes variables using getters (read method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link GenericScope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! + * + * @return Scope created from given obj by mapping obj's fields into variables of created scope via given fields (fieldNamesToUse) and conversion rules listed below!!

+ * Table of specific Object --> Scope conversions: + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Object (obj) typeObtained scope (return)
nullnew Scope<>()
{@link Array} (primitive)Array elements will become independent values of new scope
{@link GenericScope}Clone of scope {@link GenericScope#clone()}
{@link Collection}Element of collection will become independent values of new scope
{@link Map}Entries of map will become variables of new scope
Others (default){@link Scope#from(Object, List)} (return description)
+ * + * @throws Exception if calling of some {@link PropertyDescriptor}s read method fails! + * @throws IntrospectionException when there were no {@link PropertyDescriptor} found for obj class! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public static Scope from(Object obj, String... fieldNamesToUse) throws Exception, IntrospectionException + { + if (obj == null) + return new Scope(); + + if (obj.getClass().isArray()) + return new Scope(ArrayConverter.fromAmbiguous(obj)); + + if (obj instanceof Scope) + { + Scope scope = ((Scope) obj).clone(); + if (fieldNamesToUse != null && fieldNamesToUse.length > 0) + scope.variables().keySet().retainAll(Arrays.asList(fieldNamesToUse)); + return scope; + } + + if (obj instanceof Collection) + return new Scope(null, (Collection) obj); + + if (obj instanceof Map) + { + if (fieldNamesToUse != null && fieldNamesToUse.length > 0) + ((Map) obj).keySet().retainAll(Arrays.asList(fieldNamesToUse)); + return new Scope((Map) obj, (Collection) null); + } + + return from(obj, getPropertyDescriptorsOf(obj.getClass(), fieldNamesToUse)); + } + + /** + * @param obj | Object to create scope from! + * @param fieldsToUse | List of {@link PropertyDescriptor}s representing fields of object to map into scopes variables using getters (read method)! + * + * @return Scope created from given obj by mapping obj's fields into variables of created scope via given {@link PropertyDescriptor}s (fieldsToUse)! + * + * @throws Exception if calling of some {@link PropertyDescriptor}s read method fails (should not happen often)! + * + * @since 1.3.5 + */ + public static Scope from(Object obj, List fieldsToUse) throws Exception + { + return from(new Scope(), obj, fieldsToUse); + } + + /** + * @param newInstance | New instance of specific {@link Scope}! + * @param obj | Object to create scope from! + * @param fieldsToUse | List of {@link PropertyDescriptor}s representing fields of object to map into scopes variables using getters (read method)! + * + * @return Scope (newInstance) structured from given obj by mapping obj's fields into variables of created scope via given {@link PropertyDescriptor}s (fieldsToUse)! + * + * @throws Exception if calling of some {@link PropertyDescriptor}s read method fails (should not happen often)! + * + * @since 1.3.5 + */ + public static Scope from(Scope newInstance, Object obj, List fieldsToUse) throws Exception + { + //if (variablesToUse != null) + //variablesToUse = AutoProtocol.getPropertyDescriptorsOf(obj.getClass()); + for (PropertyDescriptor var : fieldsToUse) + newInstance.put(var.getName(), var.getReadMethod().invoke(obj)); + return newInstance; + } + + /** + * @param objCls | Class of object to instantiate! + * @param fromScope | Source scope with data to instantiate from! + * @param fieldNamesToUse | Array of objCls field names to map/populate instantiated object from scopes variables using setters (write method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link Scope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! + * + * @return Instantiated object populated/mapped with required variables of fromScope (fieldNamesToUse) and conversion rules listed below! {@link Serializer#Instantiate(Class)} will be used for object instantiation!

+ * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Class/type (objCls)New object instance (return)
nullnull
{@link Array} (primitive)New primitive array populated with all independent values of fromScope
{@link GenericScope}Clone of fromScope
{@link Collection}New collection instance with all independent values of fromScope
{@link Map}New map instance with all variables of fromScope
Others (default){@link Scope#into(Object, GenericScope, List)} (return description)
+ * + * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often)! + * @throws IntrospectionException when there were no {@link PropertyDescriptor} found for obj class! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public static T intoNew(Class objCls, GenericScope fromScope, String... fieldNamesToUse) throws IntrospectionException, Exception + { + if (objCls == null) + return null; + + if (objCls.isArray()) + { + if (objCls.getComponentType() == Object.class) + return (T) fromScope.toValArray(); + + return (T) into(Array.newInstance(objCls.getComponentType(), fromScope.valuesCount()), fromScope, fieldNamesToUse); + } + + if (GenericScope.class.isAssignableFrom(objCls)) + { + GenericScope result = ((GenericScope) fromScope).clone((Class>)objCls); + if (fieldNamesToUse != null && fieldNamesToUse.length > 0) + result.variables().keySet().retainAll(Arrays.asList(fieldNamesToUse)); + return (T) result; + } + + if (objCls.isInterface()) + { + if (Collection.class.isAssignableFrom(objCls)) + { + return (T) fromScope.toValList(); + } + + if (Map.class.isAssignableFrom(objCls)) + { + Map map = fromScope.toVarMap(); + if (fieldNamesToUse != null && fieldNamesToUse.length > 0) + map.keySet().retainAll(Arrays.asList(fieldNamesToUse)); + return (T) map; + } + } + + return into(Serializer.Instantiate(objCls), fromScope, fieldNamesToUse); + } + + /** + * @param obj | Object to map scopes variables into! + * @param fromScope | Source scope with variables to use for mapping! + * @param fieldNamesToUse | Array of obj field names to map/populate from scopes variables using setters (write method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link Scope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! + * + * @return Same obj after being populated/mapped by variables of given scope via requested fields (fieldNamesToUse) and conversion rules listed below!

+ * Table of specific Scope --> Object conversions: + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Object (obj) typeAction with obj (return)
nullnull
{@link Array} (primitive)Independent values of fromScope will be injected into array
{@link GenericScope}Content of fromScope will be added into Scope
{@link Collection}Independent values of fromScope will be added to Collection
{@link Map}Variables of fromScope will be added to Map
Others (default){@link Scope#into(Object, GenericScope, List)} (return description)
+ * + * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often)! + * @throws IntrospectionException when there were no {@link PropertyDescriptor} found for obj class! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public static T into(Object obj, GenericScope fromScope, String... fieldNamesToUse) throws IntrospectionException, Exception + { + if (obj == null) + return null; + if (obj.getClass().isArray()) + { + for (int i = 0, arrLen = Array.getLength(obj), scSize = fromScope.valuesCount(); i < arrLen && i < scSize; i++) + Array.set(obj, i, fromScope.get(i)); + return (T) obj; + } + + if (obj instanceof GenericScope) + { + ((GenericScope) obj).addAll(fromScope); + if (fieldNamesToUse != null && fieldNamesToUse.length > 0) + ((GenericScope) obj).variables().keySet().retainAll(Arrays.asList(fieldNamesToUse)); + return (T) obj; + } + + if (obj instanceof Collection) + { + ((Collection) obj).addAll(fromScope.values()); + return (T) obj; + } + + if (obj instanceof Map) + { + ((Map) obj).putAll(fromScope.variables()); + if (fieldNamesToUse != null && fieldNamesToUse.length > 0) + ((Map) obj).keySet().retainAll(Arrays.asList(fieldNamesToUse)); + return (T) obj; + } + + return (T) into(obj, fromScope, getPropertyDescriptorsOf(obj.getClass(), fieldNamesToUse)); + } + + /** + * @param obj | Object to map scopes variables into! + * @param fromScope | Source scope with variables to use for mapping! + * @param fieldsToUse | List of {@link PropertyDescriptor}s representing fields of object to map/populate from scopes variables using setters (write method)! + * + * @return Same obj after being populated/mapped by variables of given scope via requested {@link PropertyDescriptor}s (fieldsToUse)! + * + * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often)! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public static T into(T obj, GenericScope fromScope, List fieldsToUse) throws Exception + { + for (PropertyDescriptor var : fieldsToUse) + { + Object varValue = ((GenericScope) fromScope).get(var.getName(), DataParser.VOID); + if (varValue != DataParser.VOID) + var.getWriteMethod().invoke(obj, varValue); + } + return obj; + } + + /** + * @param cls | Class to inspect! + * @param fieldNames | Names of fields to get descriptors for, if this array is empty or null, descriptors for all fields with public getters and setters will be obtained! + * + * @return List of {@link PropertyDescriptor}s of cls representing access methods of required fields! Only descriptors of fields that have valid and public getter and setter will be returned! + * + * @throws IntrospectionException when there are no suitable fields with valid and public getters and setters. + * + * @see PropertyDescriptor + * + * @since 1.3.5 + */ + public static List getPropertyDescriptorsOf(Class cls, String... fieldNames) throws IntrospectionException + { + return getPropertyDescriptorsOf(cls, null, fieldNames); + } + + + /** + * @param cls | Class to inspect! + * @param cache | Cache to store generated results into! + * @param fieldNames | Names of fields to get descriptors for, if this array is empty or null, descriptors for all fields with public getters and setters will be obtained! + * + * @return List of {@link PropertyDescriptor}s of cls representing access methods of required fields! Only descriptors of fields that have valid and public getter and setter will be returned! + * + * @throws IntrospectionException when there are no suitable fields with valid and public getters and setters. + * + * @see PropertyDescriptor + * + * @since 1.3.5 + */ + public static List getPropertyDescriptorsOf(Class cls, Map, List> cache, String... fieldNames) throws IntrospectionException + { + List fieldDescriptors = new ArrayList<>(), cached = cache == null ? null : cache.get(cls); + if (cached != null) + return cached; + + if (fieldNames == null || fieldNames.length <= 0) + { + for (Class c = cls; c != Object.class; c = c.getSuperclass()) + for (Field field : c.getDeclaredFields()) + if (!Modifier.isStatic(field.getModifiers())) + try + { + fieldDescriptors.add(new PropertyDescriptor(field.getName(), cls)); + } + catch (Exception e) + {} + + if (cache != null && !fieldDescriptors.isEmpty()) + { + cache.put(cls, fieldDescriptors); + } + } + else + { + for (int i = 0; i < fieldNames.length; i++) + try + { + fieldDescriptors.add(new PropertyDescriptor(fieldNames[i], cls)); + } + catch (Exception e) + {} + } + + if (fieldDescriptors.isEmpty()) + throw new IntrospectionException("No suitable fields with valid and public getters and setters to use in " + cls.getSimpleName()); + return fieldDescriptors; + } +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/SerializationDebugger.java b/SerialX-core/src/main/java/org/ugp/serialx/SerializationDebugger.java new file mode 100644 index 0000000..e19307c --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/SerializationDebugger.java @@ -0,0 +1,400 @@ +package org.ugp.serialx; + +import java.util.Arrays; + +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +import org.ugp.serialx.converters.DataConverter; +import org.ugp.serialx.converters.DataParser; + +/** + * Use this for debugging during parsing and converting by adding new instance of it into your parser {@link Registry} or in case of {@link Serializer} use !
+ * During parsing, type __debug or __debug_yourObject into your code!
+ * During converting/serializing, serialize your object using {@link DebugWrapper} with your object as argument! + * + * @author PETO + * + * @since 1.3.5 + */ +public class SerializationDebugger implements DataConverter +{ + public static final String DEBUG_MARK = new String("__debug"); + + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + synchronized (this) { + if (str.toLowerCase().startsWith(DEBUG_MARK)) + return printDebugs(myHomeRegistry instanceof DebugParserRegistry ? (DebugParserRegistry) myHomeRegistry : new DebugParserRegistry(myHomeRegistry), null, str, args); + return CONTINUE; + } + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (obj instanceof DebugWrapper) + return printDebugs(myHomeRegistry instanceof DebugParserRegistry ? (DebugParserRegistry) myHomeRegistry : new DebugParserRegistry(myHomeRegistry), ((DebugWrapper) obj).obj, null, args).toString(); + return CONTINUE; + } + + /** + * Print and return debug results of parsing or converting! + * + * @return Parsed object or object converted to string! + * + * @since 1.3.5 + */ + public Object printDebugs(DebugParserRegistry myHomeRegistry, Object objToSerialize, String strToParse, Object... args) + { + String action = objToSerialize == null && strToParse != null ? "Parsing" : "Converting"; + System.err.println("--------------------------------------------- " + action + " Debug ---------------------------------------------"); + if (args == null) + System.err.println("------- Available args (args): none (args = null)!"); + else + print("------- Available args (args):", Arrays.asList(args), 0); + + if (myHomeRegistry == null) + System.err.println("\n------- Available parsers (myHomeRegistry: null): none!"); + else + print("\n------- Available parsers (myHomeRegistry: " + myHomeRegistry.getClass().getName() + "):", myHomeRegistry, 0); + + if (strToParse != null && (strToParse = strToParse.substring(DEBUG_MARK.length())).length() > 0 && (strToParse = strToParse.substring(1)).length() > 0) + { + if (args.length < 100) + { + myHomeRegistry.getRegistryIterationStackTrace().clear(); + args = Arrays.copyOf(args, 100); + args[99] = 0; + } + else if (args[99] instanceof Integer && (int) args[99] > 0) + { + myHomeRegistry = myHomeRegistry.clone(); + myHomeRegistry.iterationStackTrace = new TreeMap<>(); + } + + double t0 = System.nanoTime(); + objToSerialize = myHomeRegistry.parse(strToParse, args); + double t = System.nanoTime(); + + if (myHomeRegistry.getParsingCache() == null) + System.err.println("\n------- Paring cache (after process): null (none)"); + else + print("\n------- Paring cache (after process):", Arrays.asList(myHomeRegistry.getParsingCache()), 0); + print("\n------- Registry iterations (" + myHomeRegistry.getRegistryIterationStackTrace().size() + " in total, total time " + (t-t0)/1000000 + "ms):", myHomeRegistry.getRegistryIterationStackTrace(), 0); + System.err.println("\n--------------------------------------------- " + action + " Results ---------------------------------------------"); + System.err.println("String \"" + strToParse + "\" was parsed into:\n\t" + toStringAndCls(objToSerialize)); + System.err.println("\n"); + return objToSerialize; + } + + if (objToSerialize != null) + { + if (args.length < 100) + { + myHomeRegistry.getRegistryIterationStackTrace().clear(); + args = Arrays.copyOf(args, 100); + args[99] = 0; + } + else if (args[99] instanceof Integer && (int) args[99] > 0) + { + myHomeRegistry = myHomeRegistry.clone(); + myHomeRegistry.iterationStackTrace = new TreeMap<>(); + } + + double t0 = System.nanoTime(); + strToParse = myHomeRegistry.toString(objToSerialize, args).toString(); + double t = System.nanoTime(); + + if (myHomeRegistry.getConverterCache() == null) + System.err.println("\n------- Converting cache (after process): null (none)"); + else + print("\n------- Converting cache (after process):", Arrays.asList(myHomeRegistry.getConverterCache()), 0); + print("\n------- Registry iterations (" + myHomeRegistry.getRegistryIterationStackTrace().size() + " in total, total time " + (t-t0)/1000000 + "ms):", myHomeRegistry.getRegistryIterationStackTrace(), 0); + System.err.println("\n--------------------------------------------- " + action + " Results ---------------------------------------------"); + System.err.println("Object " + toStringAndCls(objToSerialize) + " was converted to string:\n" + (strToParse.contains("\n") ? strToParse : "\t" + strToParse)); + System.err.println("\n"); + return strToParse; + } + + if (myHomeRegistry.getParsingCache() == null) + System.err.println("\n------- Current parsing cache: null (none)"); + else + print("\n------- Current parsing cache:", Arrays.asList(myHomeRegistry.getParsingCache()), 0); + + if (myHomeRegistry.getConverterCache() == null) + System.err.println("\n------- Current parsing cache: null (none)"); + else + print("\n------- Current parsing cache:", Arrays.asList(myHomeRegistry.getConverterCache()), 0); + System.err.println("\n--------------------------------------------- No Results ---------------------------------------------"); + System.err.println("\n"); + return VOID; + } + + /** + * @param serializer | Serializer to debug! + * + * @return Serializer capable of debugging its serialization and deserialization! + * + * @since 1.3.5 + */ + public static T debug(T serializer) + { + return debug(serializer, new SerializationDebugger()); + } + + /** + * @param serializer | Serializer to debug! + * @param debuger | Specific debugger to use! + * + * @return Serializer capable of debugging its serialization and deserialization! + * + * @since 1.3.5 + */ + public static T debug(T serializer, SerializationDebugger debugger) + { + serializer.getParsers().add(0, debugger); + serializer.setParsers(new DebugParserRegistry(serializer.getParsers())); + return serializer; + } + + /** + * @param objToSerializeAndDebug | Object you want to serialize and see the debug of serialization! + * + * @return Object wrapped for debugger to debug! + * + * @since 1.3.5 + */ + public static DebugWrapper wrapForDebug(Object objToSerializeAndDebug) + { + return new DebugWrapper(objToSerializeAndDebug); + } + + /** + * @return obj + " (" + obj.getClass().getName() + ")" + * Note: Used internally by debugger! + * + * @since 1.3.5 + */ + public static String toStringAndCls(Object obj) + { + if (obj == null) + return "null"; + else + return obj + " (" + obj.getClass().getName() + ")"; + } + + /** + * This will print list into console in somewhat more readable form with tabs and introduction text! + * + * @since 1.3.5 + */ + public static void print(String text, List objs, int tabs) + { + System.err.println(text); + for (int i = 0, i2 = 0; i < objs.size(); i++) + { + Object o = objs.get(i); + String strTbs = Serializer.multilpy('\t', tabs).toString(); + if (o instanceof List) + print(strTbs + (i2++) + ":\t" + o.getClass().getName() + ":", (List) o, tabs+1); + else if (o instanceof Map) + print(strTbs + (i2++) + ":\t" + o.getClass().getName() + ":", (Map) o, tabs+1); + else + System.err.println(Serializer.multilpy('\t', tabs).toString() + (i2++) + ":\t" + String.valueOf(o)); + } + } + + /** + * This will print map into console in somewhat more readable form with tabs and introduction text! + * + * @since 1.3.5 + */ + public static void print(String text, Map map, int tabs) + { + System.err.println(text); + for (Entry entry : map.entrySet()) + { + Object o = entry.getValue(); + String strTbs = Serializer.multilpy('\t', tabs).toString(); + if (o instanceof List) + print(strTbs + (entry.getKey()) + ":\t" + o.getClass().getName() + ":", (List) o, tabs+1); + else if (o instanceof Map) + print(strTbs + (entry.getKey()) + ":\t" + o.getClass().getName() + ":", (Map) o, tabs+1); + else + System.err.println(strTbs + entry.getKey() + ":\t" + String.valueOf(o)); + } + } + + /** + * Use this during converting/serializing! + * + * @author PETO + * + * @since 1.3.5 + * + * @see SerializationDebugger + */ + protected static class DebugWrapper + { + public final Object obj; + + /** + * @param yourObject | Your object to serialize in debug mode! + * + * @since 1.3.5 + */ + public DebugWrapper(Object yourObject) + { + obj = yourObject; + } + } + + /** + * Special {@link ParserRegistry} that keeps track of its actions! Use only for debugging! + * + * @author PETO + * + * @since 1.3.5 + */ + public static class DebugParserRegistry extends ParserRegistry + { + /** + * + */ + private static final long serialVersionUID = 3445967263611388142L; + + protected Map iterationStackTrace = new TreeMap<>(); + + public DebugParserRegistry(ParserRegistry registry) + { + super(registry); + resetCache(registry.getParsingCache(), registry.getConverterCache()); + } + + @Override + public DebugParserRegistry clone() + { + DebugParserRegistry reg = new DebugParserRegistry(this); + reg.iterationStackTrace = this.iterationStackTrace; + return reg; + } + + @Override + public CharSequence toString(Object obj, Object... args) { + int iterationIndex = 0; + if (args.length > 99 && args[99] instanceof Integer) + { + iterationIndex = (int) args[99]; + args[99] = iterationIndex + 1; + } + + CharSequence str = null; + if (convertingCache != null) + for (int i = 0; i < convertingCache.length; i++) + { + DataParser parser = convertingCache[i]; + if (parser != null) + { + double t0 = System.nanoTime(); + str = ((DataConverter) parser).toString(this, obj, args); + double t = System.nanoTime(); + if (str != CONTINUE) + { + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms (from cache)\n>>\t" + toStringAndCls(obj) + "\t -->\t\"" + str + "\""); + return str; + } + } + } + + for (int i = 0, size = size(); i < size; i++) + { + DataParser parser = get(i); + if (parser instanceof DataConverter) + { + double t0 = System.nanoTime(); + str = ((DataConverter) parser).toString(this, obj, args); + double t = System.nanoTime(); + if(str != CONTINUE) + { + if (convertingCache != null && i < convertingCache.length) + convertingCache[i] = parser; + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms\n>>\t" + toStringAndCls(obj) + "\t -->\t\"" + str + "\""); + return str; + } + } + } + + LogProvider.instance.logErr(DataConverter.class.getSimpleName() + ": Unable to convert \"" + obj == null ? "null" : obj.getClass().getName() + "\" to string because none of registered converters were aplicable for this object!", null); + return null; + } + + @Override + public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ignore, Object... args) + { + int iterationIndex = 0; + if (args.length > 99 && args[99] instanceof Integer) + { + iterationIndex = (int) args[99]; + args[99] = iterationIndex + 1; + } + + Object obj = null; + if (parsingCache != null) + for (int i = 0; i < parsingCache.length; i++) + { + DataParser parser = parsingCache[i]; + if (parser != null) + { + double t0 = System.nanoTime(); + obj = parser.parse(this, str, args); + double t = System.nanoTime(); + if (obj != CONTINUE) + { + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms (from cache)\n>>\t\"" + str + "\"\t -->\t" + toStringAndCls(obj)); + return obj; + } + } + } + + registryLoop: for (int i = 0, size = size(); i < size; i++) + { + DataParser parser = get(i); + if (ignore != null) + for (Class cls : ignore) + if (cls == parser.getClass()) + continue registryLoop; + + double t0 = System.nanoTime(); + obj = parser.parse(this, str, args); + double t = System.nanoTime(); + if (obj != CONTINUE) + { + if (parsingCache != null && i < parsingCache.length) + parsingCache[i] = parser; + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms\n>>\t\"" + str + "\"\t -->\t" + toStringAndCls(obj)); + return obj; + } + } + + if (returnAsStringIfNotFound) + return str; + + LogProvider.instance.logErr(DataParser.class.getSimpleName() + ": Unable to parse \"" + str + "\" because none of registred parsers were suitable!", null); + return null; + } + + /** + * @return Ordered map of registry iterations generated by using it during parsing or converting! + * + * @since 1.3.5 + */ + public Map getRegistryIterationStackTrace() + { + return iterationStackTrace; + } + } +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java new file mode 100644 index 0000000..6c0fe08 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -0,0 +1,1880 @@ +package org.ugp.serialx; + +import static org.ugp.serialx.converters.DataParser.VOID; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringReader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.ugp.serialx.converters.BooleanConverter; +import org.ugp.serialx.converters.CharacterConverter; +import org.ugp.serialx.converters.DataConverter; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.converters.DataParser.ParserRegistry; +import org.ugp.serialx.converters.NullConverter; +import org.ugp.serialx.converters.NumberConverter; +import org.ugp.serialx.converters.SerializableBase64Converter; +import org.ugp.serialx.converters.StringConverter; +import org.ugp.serialx.converters.imports.ImportConverter; +import org.ugp.serialx.converters.imports.ImportConverter.Imports; +import org.ugp.serialx.converters.imports.ImportsProvider; +import org.ugp.serialx.protocols.SerializationProtocol; +import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; + +/** + * {@link org.ugp.serialx.Serializer} is powerful utility class that allows you to serialize any object in Java using custom data format compiled by recursive descent parser consisting of {@link DataParser}s. + * This class itself is responsible for utility, formating and managing input-output (IO) of content obtained from parsers and protocols as well as their management of their usage! + * It is instance of {@link Scope} so we can say that this is scope that can serialize itself using system of already mentioned {@link DataParser} and {@link SerializationProtocol}! + * + * @author PETO + * + * @since 1.0.0 + */ +@SuppressWarnings("serial") +public abstract class Serializer extends Scope implements ImportsProvider +{ + /** + * Common parsers that can parse primitive datatypes! + * + * @since 1.3.2 + */ + public static final ParserRegistry COMMON_PARSERS = new ParserRegistry(new StringConverter(), new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter()); + + protected ParserRegistry parsers; + protected ProtocolRegistry protocols; + protected Imports imports; + + /** + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public Serializer(Object... values) + { + this(null, values); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public Serializer(Map variablesMap, Object... values) + { + this(variablesMap, values == null ? null : new ArrayList<>(Arrays.asList(values))); + } + + /** + * @param sourceScope | Scope with initial content! + * + * @since 1.3.5 + */ + public Serializer(GenericScope sourceScope) + { + this(sourceScope == null ? null : sourceScope.variables(), sourceScope == null ? null : sourceScope.values()); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public Serializer(Map variablesMap, Collection values) + { + this(null, variablesMap, values); + } + + /** + * @param parsers | Registry of parsers to use! + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public Serializer(Registry parsers, Map variablesMap, Collection values) + { + this(parsers, null, variablesMap, values, null); + } + + /** + * @param parsers | Registry of parsers to use! + * @param protocols | Registry of protocols to use! + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * @param parent | Parent of this scope. + * + * @since 1.3.2 + */ + public Serializer(Registry parsers, ProtocolRegistry protocols, Map variablesMap, Collection values, Scope parent) + { + super(variablesMap, values, parent); + if (parsers != null) + setParsers(parsers); + if (protocols != null) + setProtocols(protocols); + } + + @Override + public Scope clone() + { + try + { + return clone(getClass()); + } + catch (Exception e) + { + return new JussSerializer(variables(), values(), getParent()); + } + } + + @Override + public > S clone(Class typeOfClone) throws Exception + { + S clone = super.clone(typeOfClone); + if (clone instanceof Serializer) + { + ((Serializer) clone).setParsers(getParsers()); + ((Serializer) clone).setProtocols(getProtocols()); + } + return clone; + } + + @Override + public > S castTo(Class newType) throws Exception + { + S clone = super.castTo(newType); + if (clone instanceof Serializer) + { + ((Serializer) clone).setParsers(getParsers()); + ((Serializer) clone).setProtocols(getProtocols()); + } + return clone; + } + + @Override + public T toObjectOf(String variableWithscope, Class objClass, T defaultValue) throws Exception + { + return toObjectOf(variableWithscope, objClass, defaultValue, getProtocols()); + } + + @Override + public T toObject(Class objClass) throws Exception + { + return toObject(objClass, getProtocols()); + } + + /** + * @see Serializer#into(Object, Serializer, String...) + */ + @Override + public T into(Object obj, String... fieldNamesToUse) throws IntrospectionException, Exception + { + return Serializer.into(obj, this, fieldNamesToUse); + } + + @Override + public Imports getImports() + { + if (imports == null) + imports = ImportConverter.IMPORTS.clone(); + return imports; + } + + /** + * @param name | Name of variable. + * @param value | Value of variable. + * + * @return Classic variable expression in general form like [name] = [value]. + * + * @since 1.1.5 + */ + public String Var(String name, T value) + { + return Code(name + " = " + getParsers().toString(value, 0, 0, this, getProtocols(), false) + ";"); + } + + /** + * @param comment | The comment... + * + * @return Comment in general form, such as //comment
Each line will be taken as new comment! + * + * @since 1.1.5 + */ + public String Comment(String comment) + { + StringBuilder sb = new StringBuilder(); + String[] lines = comment.split("\n"); + for (int i = 0; i < lines.length; i++) + sb.append("//" + lines[i] + (i < lines.length - 1 ? "\n" : "")); + return Code(sb); + } + + /** + * + * @param code | Code to convert into JUSS (StringConverter) code form. + * @return "${" + code + "} + *

Note: This works only in combination with {@link StringConverter}! + * + * @since 1.1.5 + * + * @see StringConverter#DirectCode(Object) + */ + public String Code(Object code) + { + return StringConverter.DirectCode(code); + } + + /** + * @param serialize | If true, this scope will be serialized to string! + * + * @return This scope as string! + * + * @since 1.3.2 + * + * @see Serializer#Stringify(Object...) + */ + public String toString(boolean serialize) throws IOException + { + if (serialize) + return Stringify(); + return super.toString(); + } + + /** + * @param f | File to write in. This must be a text file. + * + * @return String with variables and objects serialized in specific format. + * + * @throws IOException if file can't be opened or serialization fails! + * + * @since 1.1.5 + */ + public void SerializeTo(File f) throws IOException + { + SerializeTo(false, f); + } + + /** + * @param append | When true, the new objects will be appended to files content (same objects will be also appended if there are some)! + * @param f | File to write in. This must be a text file. + * @param args | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (they should not be serialized)! + * + * @return String with variables and objects serialized in specific format. + * + * @throws IOException if file can't be opened or serialization fails! + * + * @since 1.1.5 + * + * @see Serializer#SerializeTo(Appendable, Object...) + */ + public void SerializeTo(boolean append, File f, Object... args) throws IOException + { + //double t0 = System.nanoTime(); + BufferedWriter writer = new BufferedWriter(new FileWriter(f, append)); + + writer.write(Stringify(args)); + + writer.close(); + } + + /** + * @param args | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (they should not be serialized)! + * + * @return String with objects serialized in specific format. + * + * @since 1.0.0 + * + * @see Serializer#SerializeTo(Appendable, Object...) + */ + public String Stringify(Object... args) throws IOException + { + return SerializeTo(new StringBuilder(), args).toString(); + } + + /** + * @param source | Source {@link OutputStream} to serialize variables and objects into! + * @param args | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (they should not be serialized)! + * + * @return Source {@link OutputStream} with variables and objects serialized in specific format (may or may not be flushed). + * + * @since 1.3.2 + * + * @see Serializer#SerializeTo(Appendable, Object...) + */ + public OutputStream SerializeTo(OutputStream outputStream, Object... args) throws IOException + { + SerializeTo(new OutputStreamWriter(outputStream), args); + return outputStream; + } + + /** + * @param source | Source {@link Appendable} to serialize variables and objects into! + * @param args | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (they should not be serialized)! + * + * @return Source {@link Appendable} with variables and objects serialized in specific format. + * + * @since 1.3.2 + */ + public abstract A SerializeTo(A source, Object... args) throws IOException; + + /** + * @param file | Text file with serialized objects in specific format to load. + * @param parserArgs | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (probably used for formating of incoming information)! + * + * @return Unserialized objects and variables in {@link Scope} or empty {@link Scope} if string is empty. + * You can use negative indexes to get objects from back of this array since 1.1.0 (-1 = last element)! + * + * @throws FileNotFoundException if file does not exist! + * + * @since 1.0.0 + * + * @see Serializer#LoadFrom(Reader, Object...) + */ + public S LoadFrom(File file, Object... parserArgs) throws FileNotFoundException + { + return LoadFrom(new FileReader(file), parserArgs); + } + + /** + * @param str | {@link CharSequence} with serialized objects in specific format to load. + * @param parserArgs | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (probably used for formating of incoming information)! + * + * @return Unserialized objects and variables in {@link Scope} or empty {@link Scope} if string is empty. + * You can use negative indexes to get objects from back of this array since 1.1.0 (-1 = last element)! + * + * @since 1.2.5 + * + * @see Serializer#LoadFrom(Reader, Object...) + */ + public S LoadFrom(CharSequence str, Object... parserArgs) + { + return LoadFrom(new StringReader(str.toString()), parserArgs); + } + + /** + * @param stream | Any {@link InputStream} with serialized objects in specific format to load. + * @param parserArgs | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (probably used for formating of incoming information)! + * + * @return Unserialized objects and variables in {@link Scope} or empty {@link Scope} if string is empty. + * You can use negative indexes to get objects from back of this array since 1.1.0 (-1 = last element)! + * + * @since 1.3.2 + * + * @see Serializer#LoadFrom(Reader, Object...) + */ + public S LoadFrom(InputStream stream, Object... parserArgs) + { + return LoadFrom(new InputStreamReader(stream), parserArgs); + } + + /** + * @param reader | Any {@link Reader} with serialized objects in specific format to load. + * @param parserArgs | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (probably used for formating of incoming information)! + * + * @return Unserialized objects and variables in {@link Scope} or empty {@link Scope} if string is empty. + * You can use negative indexes to get objects from back of this array since 1.1.0 (-1 = last element)! + * + * @since 1.2.5 + */ + public S LoadFrom(Reader reader) + { + return LoadFrom(reader, true); + } + + /** + * @param reader | Reader to read from! + * @param parserArgs | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (probably used for formating of incoming information)! + * + * @return This scope after loading data from reader (you most likely want to return "this")! + * + * @since 1.3.2 + */ + public abstract S LoadFrom(Reader reader, Object... parserArgs); + + /** + * @return Clone of this {@link Serializer} without variables and values, protocols and parser will remain same! + * + * @since 1.3.2 + */ + public Serializer emptyClone() throws Exception + { + return emptyClone(this); + } + + /** + * @param parent | Parent scope of new Serializer instance! + * + * @return Clone of this {@link Serializer} without variables and values, protocols and parser will remain same! + * + * @since 1.3.2 + */ + public Serializer emptyClone(Scope parent) throws Exception + { + return emptyClone(getClass(), parent); + } + + /** + * @param parent | Parent scope of new Serializer instance! + * + * @return Clone of this {@link Serializer} without variables and values, protocols and parser will remain same! + * + * @since 1.3.5 + */ + public T emptyClone(Class typeOfClone, GenericScope parent) throws Exception + { + return emptyClone(Instantiate(typeOfClone), parent); + } + + /** + * @param newEmptyInstance | Manually inserted brand new empty instance of this scope! + * @param parent | Parent scope of new Serializer instance! + * + * @return Clone of this {@link Serializer} without variables and values, protocols and parser will remain same! + * + * @since 1.3.5 + */ + public T emptyClone(T newEmptyInstance, GenericScope parent) + { + newEmptyInstance.setParsers(getParsers()); + newEmptyInstance.setProtocols(getProtocols()); + newEmptyInstance.parent = parent; + return newEmptyInstance; + } + + /** + * @return {@link Registry} with parsers that this {@link Serializer} uses! + * + * @since 1.3.2 + */ + public ParserRegistry getParsers() + { + if (parsers == null) + parsers = COMMON_PARSERS.clone(); + return parsers; + } + + /** + * @param parsers | Registry with parsers to set! + * + * @since 1.3.2 + */ + public void setParsers(Registry parsers) + { + setParsers(parsers instanceof ParserRegistry ? (ParserRegistry) parsers : new ParserRegistry(parsers)); + } + + /** + * @param parsers | Registry with parsers to set! + * + * @since 1.3.5 + */ + public void setParsers(ParserRegistry parsers) + { + this.parsers = (ParserRegistry) parsers; + } + + /** + * @return {@link ProtocolRegistry} with serialization protocols that this {@link Serializer} uses! + * + * @since 1.3.2 + */ + public ProtocolRegistry getProtocols() + { + if (protocols == null) + protocols = SerializationProtocol.REGISTRY.clone(); + return protocols; + } + + /** + * @param protocols | ProtocolRegistry with serialization protocols to set! + * + * @since 1.3.2 + */ + public void setProtocols(ProtocolRegistry protocols) + { + this.protocols = protocols; + } + + /** + * @param parser | DataParser to add! + * + * @return DataParser if was added! + * + * @since 1.3.2 + */ + public DataParser addParser(DataParser parser) + { + if (getParsers().add(parser)) + return parser; + return null; + } + + /** + * @param protocol | SerializationProtocol to add! + * + * @return SerializationProtocol if was added! + * + * @since 1.3.2 + */ + public SerializationProtocol addProtocol(SerializationProtocol protocol) + { + if (getProtocols().add(protocol)) + return protocol; + return null; + } + + /** + * This will transform this Serializer and whole tree of its sub-scopes into regular {@link Scope}s! + * Remember that scope is just a data container and analyzer and it can't be serialized in contrast to serializer! + * + * @return This serializer transformed in to simple {@link Scope}! + * + * @since 1.3.2 + */ + public GenericScope transformToScope() + { + Function transFunction = new Function() + { + @Override + public Object apply(Object t) + { + if (t instanceof Serializer) + { + GenericScope srl = ((Scope) t).transform(this); + return new GenericScope<>(srl.variables(), srl.values(), srl.getParent()); + } + return t; + } + }; + return (GenericScope) transform(transFunction); + } + + /** + * @param source | Source {@link Appendable} to serialize variables and objects into! + * @param args | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (they should not be serialized)! + * + * @return Serialized content of this scope as inner sub-scope of this scope! Wrapped inside of corresponding wrappingBrackets (default { and })! + * + * @since 1.3.5 + */ + public A SerializeAsSubscope(A source, Object... args) throws IOException + { + return SerializeAsSubscope(source, new char[] {'{', '}'}, args); + } + + /** + * @param source | Source {@link Appendable} to serialize variables and objects into! + * @param wrappingBrackets | Array of 2 characters to wrap content inside + * @param args | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (they should not be serialized)! + * + * @return Serialized content of this scope as inner sub-scope of this scope! Wrapped inside of corresponding wrappingBrackets (default { and })! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public A SerializeAsSubscope(A source, char[] wrappingBrackets, Object... args) throws IOException + { + int tabs = 0; + if (args.length > 1 && args[1] instanceof Integer) + { + tabs = (int) args[1]; + args[1] = tabs + 1; + } + source.append(wrappingBrackets[0]); + if (!isEmpty()) + source = (A) SerializeTo(source.append('\n'), args).append('\n').append(multilpy('\t', tabs)); + return (A) source.append(wrappingBrackets[1]); + } + + /* + * @param file | File with specific format content. + * @param index | Index of value to get from lowest Scope. + * + * @return Value with index in lowest Scope. Similar to Serializer.LoadFrom(file).get(index) however this function is specifically designed to load only that 1 value witch saves alto of performance! + * But target value can't be using any variables declared outside and also can't be variable invocation itself! Also there might be some problems with commented code! Also there can't be no variables in file! + * + * @since 1.2.5 + * + @Deprecated + public T LoadFrom(File file, int index) + { + try + { + return LoadFrom(new FileReader(file), index); + } + catch (FileNotFoundException e) + { + e.printStackTrace(); + } + return null; + } + + /** + * @param str | Any {@link CharSequence} with specific format content. + * @param index | Index of value to get from lowest Scope. + * + * @return Value with index in lowest Scope. Similar to Serializer.LoadFrom(str).get(index) however this function is specifically designed to load only that 1 value witch saves alto of performance! + * But target value can't be using any variables declared outside and also can't be variable invocation itself! Also there might be some problems with commented code! + * + * @since 1.2.5 + * + @Deprecated + public T LoadFrom(CharSequence str, int index) + { + return LoadFrom(new StringReader(str.toString()), index); + } + + /** + * @param reader | Any {@link Reader} with specific format content. + * @param index | Index of value to get from lowest Scope. + * + * @return Value with index in lowest Scope. Similar to Serializer.LoadFrom(reader).get(index) however this function is specifically designed to load only that 1 value witch saves alto of performance! + * But target value can't be using any variables declared outside and also can't be variable invocation itself! + * + * @since 1.2.5 + * + @Deprecated + @SuppressWarnings("unchecked") + public T LoadFrom(Reader reader, int index) + { + StringBuilder sb = new StringBuilder(); + int semicolon = 0, brackets = 0, quote = 0, vars = 0, multLineCom = -1; + + String line; + try + { + BufferedReader lineReader = new BufferedReader(reader); + while ((line = lineReader.readLine()) != null) + { + if (!contains(line = line.trim(), '=', ':') || !(brackets == 0 && quote % 2 == 0)) + for (int i = 0, com = -1, len = line.length(); i < len; i++) + { + char ch = line.charAt(i); + + if (ch == '/' && i < len-1 && line.charAt(i+1) == '/') + com++; + else if (multLineCom <= -1 && ch == '"') + quote++; + + boolean notInObj = brackets == 0 && quote % 2 == 0; + if (semicolon > index) + { + lineReader.close(); + return (T) NULL.toOopNull(DataParser.parseObj(DataParser.REGISTRY, sb.toString(), this)); + } + + if (multLineCom > -1 || com > -1) //Is comment + { + if (multLineCom > 0 && ch == '*' && i < len-1 && line.charAt(++i) == '/') + multLineCom = -1; + } + else if (ch == '/' && i < len-1) + { + char chNext = line.charAt(i+1); + if (chNext == '*') + i += multLineCom = 1; + else + sb.append(ch); + } + /*else if (notInObj && ch == '=') + { + vars++; + }* + else if (notInObj && isOneOf(ch, ';', ',')) + { + if (vars > 0) + { + vars = 0; + } + else + semicolon++; + } + else + { + if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + { + lineReader.close(); + throw new IllegalArgumentException("Missing closing bracket in: " + line); + } + } + + if (vars == 0 && semicolon == index) + sb.append(ch); + } + } + else + { + char lastCh = line.charAt(line.length()-1); + if (isOneOf(lastCh, '{', '[')) + brackets++; + if (isOneOf(lastCh, ';', ',')) + vars++; + } + + } + } + catch (IOException e) + { + e.printStackTrace(); + } + + if (brackets > 0) + throw new IllegalArgumentException("Unclosed brackets!"); + else if (quote % 2 != 0) + throw new IllegalArgumentException("Unclosed or missing quotes!"); + else if (!(line = sb.toString()).isEmpty()) + return (T) NULL.toOopNull(DataParser.parseObj(DataParser.REGISTRY, line, this)); + LogProvider.instance.logErr("Value with index " + index + " is out of bounds!"); + return null; + } + + /** + * @param file | File with specific format content. + * @param varName | Name of variable to load! + * + * @return Value of variable with varName in lowest Scope. Similar to Serializer.LoadFrom(file).get(varName) however this function is specifically designed to load only that 1 variable witch saves alto of performance! + * But target variable can't be using any variables declared outside! Also there might be some problems with commented code! + * + * @since 1.2.5 + * + @Deprecated + public T LoadFrom(File file, String varName) + { + try + { + return LoadFrom(new FileReader(file), varName); + } + catch (FileNotFoundException e) + { + e.printStackTrace(); + } + return null; + } + + /** + * @param str | Any {@link CharSequence} with specific format content. + * @param varName | Name of variable to load! + * + * @return Value of variable with varName in lowest Scope. Similar to Serializer.LoadFrom(str).get(varName) however this function is specifically designed to load only that 1 variable witch saves alto of performance! + * But target variable can't be using any variables declared outside! Also there might be some problems with commented code! + * + * @since 1.2.5 + * + @Deprecated + public T LoadFrom(CharSequence str, String varName) + { + return LoadFrom(new StringReader(str.toString()), varName); + } + + /** + * @param reader | Any {@link Reader} with specific format content. + * @param varName | Name of variable to load! + * + * @return Value of variable with varName in lowest Scope. Similar to Serializer.LoadFrom(reader).get(varName) however this function is specifically designed to load only that 1 variable witch saves alto of performance! + * But target variable can't be using any variables declared outside! Also there might be some problems with commented code! + * + * @since 1.2.5 + * + @Deprecated + @SuppressWarnings("unchecked") + public T LoadFrom(Reader reader, String varName) + { + StringBuilder sb = new StringBuilder(); + int brackets = 0, quote = 0, multLineCom = -1, fromIndex = 0, fromIndexOrig = 0, findIndex = -1; + + String line; + try + { + BufferedReader lineReader = new BufferedReader(reader); + while ((line = lineReader.readLine()) != null) + { + if (findIndex <= -1 && multLineCom <= -1 && line.length() > varName.length() && !(line.charAt(0) == '/' && isOneOf(line.charAt(1), '/', '*')) && (findIndex = line.indexOf(varName)) > -1) + { + fromIndexOrig = fromIndex = findIndex; + findIndex+=sb.length(); + } + + for (int com = -1, len = line.length(); fromIndex < len; fromIndex++) + { + char ch = line.charAt(fromIndex); + + if (ch == '/' && fromIndex < len-1 && line.charAt(fromIndex+1) == '/') + com++; + else if (multLineCom <= -1 && ch == '"') + quote++; + + if (findIndex > -1 && quote % 2 == 0 && brackets == 0 && isOneOf(ch, ';', ',')) + { + lineReader.close(); + int start = sb.indexOf("=", findIndex-fromIndexOrig); + if (start <= -1) + start = sb.indexOf(":", findIndex-fromIndexOrig); + return (T) NULL.toOopNull(DataParser.parseObj(DataParser.REGISTRY, sb.substring(start+1), this)); + } + + if (multLineCom > -1 || com > -1) //Is comment + { + if (multLineCom > 0 && ch == '*' && fromIndex < len-1 && line.charAt(++fromIndex) == '/') + multLineCom = -1; + } + else if (ch == '/' && fromIndex < len-1) + { + char chNext = line.charAt(fromIndex+1); + if (chNext == '*') + fromIndex = multLineCom = 1; + else + sb.append(ch); + } + else + { + if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + { + lineReader.close(); + throw new IllegalArgumentException("Missing closing bracket in: " + line); + } + } + + sb.append(ch); + } + } + fromIndex = 0; + } + } + catch (IOException e) + { + e.printStackTrace(); + } + + LogProvider.instance.logErr("Variable " + varName + " was not found!"); + return null; + }*/ + + /** + * @param f | Source file. + * + * @return All lines from source file as string. + * @throws IOException + * + * @since 1.1.5 + */ + public static String LoadFileToString(File f) throws IOException + { + return LoadFileToString(f, 1); + } + + /** + * @param f | Source file. + * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
+ * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! + * + * @return Content of file as string. + * @throws IOException + * + * @since 1.2.0 + */ + public static String LoadFileToString(File f, int endlMode) throws IOException + { + return StreamToString(new FileReader(f), endlMode); + } + + /** + * @param input | Input stream to read to string! + * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
+ * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! + * + * @return Reader converted to string form! + * + * @throws IOException + * + * @since 1.3.5 + */ + public static String StreamToString(InputStream input, int endlMode) throws IOException + { + return StreamToString(new InputStreamReader(input), endlMode); + } + + /** + * @param input | Input reader! + * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
+ * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! + * + * @return Reader converted to string form! + * + * @throws IOException + * + * @since 1.3.2 + */ + public static String StreamToString(Reader input, int endlMode) throws IOException + { + String l; + StringBuilder sb = new StringBuilder(); + + BufferedReader r = new BufferedReader(input); + while ((l = r.readLine()) != null) + { + sb.append(l); + if (endlMode == 1 || (endlMode > 1 && l.contains("//"))) + sb.append("\n"); + } + r.close(); + return sb.toString(); + } + + /** + * @param cls | Class to invoke method from. + * @param name | Name of public static method to be called. + * @param args | Arguments of method. Arguments should be certain if method is overloaded! + * + * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * + * @throws InvocationTargetException if called method throws and exception while calling! + * + * @since 1.2.2 + */ + public static Object InvokeStaticFunc(Class cls, String name, Object... args) throws InvocationTargetException + { + return InvokeFunc(null, cls, name, args); + } + + /** + * @param obj | The object the underlying method is invoked from! + * @param name | Name of public static method to be called. + * @param args | Arguments of method. Arguments should be certain if method is overloaded! + * + * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * + * @throws InvocationTargetException if called method throws and exception while calling! + * + * @since 1.3.5 + */ + public static Object InvokeFunc(Object obj, String name, Object... args) throws InvocationTargetException + { + return InvokeFunc(obj, obj.getClass(), name, args); + } + + /** + * @param obj | The object the underlying method is invoked from! + * @param cls | Class to invoke method from. + * @param name | Name of public static method to be called. + * @param args | Arguments of method. Arguments should be certain if method is overloaded! + * + * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * + * @throws InvocationTargetException if called method throws and exception while calling! + * + * @since 1.3.5 + */ + public static Object InvokeFunc(Object obj, Class objCls, String name, Object... args) throws InvocationTargetException + { + Object result = InvokeFunc(obj, objCls, name, ToClasses(args), args); + if (result != null) + return result; + result = InvokeFunc(obj, objCls, name, ToClasses(false, args), args); + if (result == null) + LogProvider.instance.logErr("Unable to call function \"" + name + "\" because inserted arguments " + Arrays.asList(args) + " cannot be applied or function does not exist in required class!", null); + return result; + } + + /** + * @param obj | The object the underlying method is invoked from! + * @param cls | Class to invoke method from. + * @param name | Name of public static method to be called. + * @param argClasses | Classes of args. + * @param args | Arguments of method. Arguments should be certain if method is overloaded! + * + * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * + * @throws InvocationTargetException if called method throws and exception while calling! + * + * @since 1.3.5 + */ + public static Object InvokeFunc(Object obj, Class objCls, String name, Class[] argClasses, Object... args) throws InvocationTargetException + { + try + { + Method method = objCls.getMethod(name, argClasses); + Object resualt = method.invoke(obj, args); + return method.getReturnType().equals(void.class) ? VOID : resualt; + } + catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException find) + { + for (Method method : objCls.getMethods()) + if (method.getName().equals(name)) + try + { + Object resualt = method.invoke(obj, args); + return method.getReturnType().equals(void.class) ? VOID : resualt; + } + catch (IllegalArgumentException e) + {} + catch (SecurityException | IllegalAccessException ex) + { + ex.printStackTrace(); + } + } + return null; + } + + + //Syntactical analyzes and fast string utility: + + /** + * @param obj | Object to clone. + * + * @return Cloned object using {@link DataParser}, {@link DataConverter} and {@link SerializationProtocol} or the same object as inserted one if cloning is not possible, for instance when protocol was not found and object is not instance of {@link Cloneable}. + * This clone function will always prioritized the Protocol variation, regular cloning is used only when there is no protocol registered or exception occurs.
+ * Note: If there are protocols to serialize inserted object and all its sub-objects and variables then this clone will be absolute deep copy, meaning that making any changes to this cloned object or to its variables will not affect original one in any way! + * But keep in mind that this clone is absolute hoverer, based on protocols used, it does not need to be an 100% copy! + * + * @since 1.2.2 + */ + public static T Clone(T obj) + { + return Clone(obj, DataParser.REGISTRY, new Object[] {}, new Scope()); + } + + /** + * @param obj | Object to clone. + * @param + * @param converterArgs | Argument for {@link DataConverter#objToString(Registry, Object, Object...)}! + * @param parserArgs | Arguments for {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)}! + * + * @return Cloned object using {@link DataParser}, {@link DataConverter} and {@link SerializationProtocol} or the same object as inserted one if cloning is not possible, for instance when protocol was not found and object is not instance of {@link Cloneable}. + * This clone function will always prioritized the Protocol variation, regular cloning is used only when there is no protocol registered or exception occurs.
+ * Note: If there are protocols to serialize inserted object and all its sub-objects and variables then this clone will be absolute deep copy, meaning that making any changes to this cloned object or to its variables will not affect original one in any way! + * But keep in mind that this clone is absolute hoverer, based on protocols used, it does not need to be an 100% copy! + * + * @since 1.3.2 + */ + @SuppressWarnings("unchecked") + public static T Clone(T obj, Registry parsersToUse, Object[] converterArgs, Object... parserArgs) + { + if (obj == null) + return obj; + else if (obj.getClass() == Byte.class) + return (T) new Byte((byte) obj); + else if (obj.getClass() == Short.class) + return (T) new Short((short) obj); + else if (obj.getClass() == Integer.class) + return (T) new Integer((int) obj); + else if (obj.getClass() == Long.class) + return (T) new Long((long) obj); + else if (obj.getClass() == Float.class) + return (T) new Float((float) obj); + else if (obj.getClass() == Double.class) + return (T) new Double((double) obj); + else if (obj.getClass() == Character.class) + return (T) new Character((char) obj); + else if (obj.getClass() == Boolean.class) + return (T) new Boolean((boolean) obj); + else if (obj.getClass() == String.class) + return (T) new String((String) obj); + else + { + ParserRegistry parsers = parsersToUse instanceof ParserRegistry ? (ParserRegistry) parsersToUse : new ParserRegistry(parsersToUse); + + Object cln = NULL.toOopNull(parsers.parse(parsers.toString(obj, converterArgs).toString(), parserArgs)); + if (cln != null && cln != VOID) + return (T) cln; + + if (obj instanceof Cloneable) + { + try + { + Method method = Object.class.getDeclaredMethod("clone"); + method.setAccessible(true); + return (T) method.invoke(obj); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + LogProvider.instance.logErr("Unable to clone " + obj.getClass() + ": " + obj, null); + return obj; + } + } + + /** + * @param cls | Class to instantiate. + * + * @return New blank instance of required class created by calling shortest public constructor with default values!
+ * Note: Do not use this when your class contains final fields! + * + * @throws NoSuchMethodException if there is no public constructor! + * @throws InvocationTargetException if called constructor throws and exception! + * + * @since 1.2.2 + */ + public static T Instantiate(Class cls) throws NoSuchMethodException, InvocationTargetException + { + return Instantiate(cls, true); + } + + /** + * @param cls | Class to instantiate. + * @param publicOnly | If true, only public constructors will be used to create the object! + * + * @return New blank instance of required class created by calling shortest constructor with default values!
+ * Note: Do not use this when your class contains final fields! + * + * @throws NoSuchMethodException if there is no public constructor! + * @throws InvocationTargetException if called constructor throws and exception! + * + * @since 1.3.2 + */ + @SuppressWarnings("unchecked") + public static T Instantiate(Class cls, boolean publicOnly) throws NoSuchMethodException, InvocationTargetException + { + try + { + Constructor cons = publicOnly ? cls.getConstructor() : cls.getDeclaredConstructor(); + if (!publicOnly) + cons.setAccessible(true); + return cons.newInstance(); + } + catch (Exception e) + { + try + { + Constructor[] cnstrs = publicOnly ? cls.getConstructors() : cls.getDeclaredConstructors(); + if (cnstrs.length <= 0) + throw new NoSuchMethodException("No public constructors in class " + cls.getName() + "!"); + + for (int i = 1; i < cnstrs.length; i++) + { + if (!publicOnly) + cnstrs[0].setAccessible(true); + if (cnstrs[i].getParameterCount() < cnstrs[0].getParameterCount()) + cnstrs[0] = cnstrs[i]; + } + + Object[] args = new Object[cnstrs[0].getParameterCount()]; + Class[] argTypes = cnstrs[0].getParameterTypes(); + for (int i = 0; i < cnstrs[0].getParameterCount(); i++) + { + if (argTypes[i] == byte.class) + args[i] = (byte) 0; + else if (argTypes[i] == short.class) + args[i] = (short) 0; + else if (argTypes[i] == int.class) + args[i] = 0; + else if (argTypes[i] == long.class) + args[i] = 0l; + else if ( argTypes[i] == float.class) + args[i] = 0.0f; + else if (argTypes[i] == double.class) + args[i] = 0.0; + else if (argTypes[i] == char.class) + args[i] = (char) 0; + else if (argTypes[i] == boolean.class) + args[i] = false; + else if (argTypes[i] == String.class) + args[i] = ""; + else + args[i] = null; + } + return (T) cnstrs[0].newInstance(args); + } + catch (InstantiationException | IllegalAccessException | IllegalArgumentException | SecurityException e2) + { + e2.printStackTrace(); + } + } + return null; + } + + /** + * @param objs | Array of objects. + * + * @return Array of inserted objects class types. Wrapper types of primitive values will be converted to primitive types! For instance: Integer.class -> int.class + * + * @since 1.2.2 + */ + public static Class[] ToClasses(Object... objs) + { + return ToClasses(true, objs); + } + + /** + * @param objs | Array of objects. + * + * @return Array of inserted objects class types. Wrapper types of primitive values will be converted to primitive types! For instance: Integer.class -> int.class + * + * @since 1.3.5 + */ + public static Class[] ToClasses(boolean unwrapp, Object... objs) + { + Class[] classes = new Class[objs.length]; + if (unwrapp) + { + for (int i = 0; i < classes.length; i++) + { + if (objs[i] == null) + classes[i] = Object.class; + else if (objs[i].getClass() == Byte.class || objs[i] == Byte.class) + classes[i] = byte.class; + else if (objs[i].getClass() == Short.class || objs[i] == Short.class) + classes[i] = short.class; + else if (objs[i].getClass() == Integer.class || objs[i] == Integer.class) + classes[i] = int.class; + else if (objs[i].getClass() == Long.class || objs[i] == Long.class) + classes[i] = long.class; + else if (objs[i].getClass() == Float.class || objs[i] == Float.class) + classes[i] = float.class; + else if (objs[i].getClass() == Double.class || objs[i] == Double.class) + classes[i] = double.class; + else if (objs[i].getClass() == Character.class || objs[i] == Character.class) + classes[i] = char.class; + else if (objs[i].getClass() == Boolean.class || objs[i] == Boolean.class) + classes[i] = boolean.class; + else if (objs[i] instanceof Class) + classes[i] = (Class) objs[i]; + else + classes[i] = objs[i].getClass(); + } + + return classes; + } + + for (int i = 0; i < classes.length; i++) + classes[i] = objs[i].getClass(); + return classes; + } + + /** + * @param ch | String to multiply! + * @param times | Count of multiplication! + * + * @return Multiplied char, for example multilpy('a', 5) will return "aaaaa"; + * + * @since 1.3.2 + */ + public static StringBuilder multilpy(char ch, int times) + { + StringBuilder sb = new StringBuilder(); + while (times-- > 0) + sb.append(ch); + return sb; + } + + /** + * @param ch | String to multiply! + * @param str | Count of multiplication! + * + * @return Multiplied char, for example multilpy("a", 5) will return "aaaaa"; + * + * @since 1.3.0 + */ + public static StringBuilder multilpy(CharSequence str, int times) + { + StringBuilder sb = new StringBuilder(str); + while (times-- > 1) + sb.append(str); + return sb; + } + + /** + * @param s | String to split and check some syntax. + * @param splitter | Chars where string will be split! + * + * @return String splitted after splitters. If there is more than one splitter in row, it will be taken as one whole! + * + * @since 1.0.0 + */ + public static String[] splitValues(String s, char... splitter) + { + return splitValues(s, 0, true, splitter); + } + + /** + * @param s | String to split and check some syntax. + * @param limit | If 0 or less = no limit, 1 = no splitting, more than 1 = count of results! + * @param oneOrMore | If true, string will be splitted after one or more splitters in row, if false splitting will occur only after single splitter (this is similar to "+" in regex)! + * @param splitter | Chars where string will be split! + * + * @return String splitted after splitters according to arguments. If there is more than one splitter in row, it will be taken as one whole! + * + * @since 1.3.0 + */ + public static String[] splitValues(String s, int limit, boolean splitAfterSingleCharOnly, char... splitter) + { + return splitValues(s, limit, splitAfterSingleCharOnly, new char[0], splitter); + } + + /** + * @param s | String to split and check some syntax. + * @param limit | If 0 or less = no limit, 1 = no splitting, more than 1 = count of results! + * @param oneOrMore | If true, string will be splitted after one or more splitters in row, if false splitting will occur only after single splitter (this is similar to "+" in regex)! + * @param splitBreaks | When some of these characters is encountered, splitting is terminated for the rest of the string! + * @param splitter | Chars where string will be split! + * + * @return String splitted after splitters according to arguments. If there is more than one splitter in row, it will be taken as one whole! + * + * @since 1.3.5 + */ + public static String[] splitValues(String s, int limit, boolean oneOrMore, char[] splitBreaks, char... splitter) + { + if (splitter.length <= 0 || limit == 1) + return new String[] {s}; +// +// if (isOneOf(s.charAt(0), splitter)) +// return splitValues(" "+s, limit, oneOrMore, splitBreaks, splitter); + + List result = new ArrayList<>(); + + int brackets = 0, quote = 0, lastIndex = 0; + for (int i = 0, count = 1, len = s.length(), oldCh = splitter[0]; i < len && (limit <= 0 || count < limit); i++) + { + char ch = s.charAt(i); + if (ch == '"') + quote++; + + if (quote % 2 == 0) + { + if (isOneOf(ch, splitBreaks)) + { + brackets = quote = 0; + break; + } + + if (brackets == 0 && oldCh != ch && isOneOf(ch, splitter) && (oneOrMore || (i >= len-1 || !isOneOf(s.charAt(i+1), splitter)))) + { + result.add(s.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i).trim()); + count++; + } + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing opening bracket in: " + s); + } + } + oldCh = ch; + } + + if (brackets > 0) + throw new IllegalArgumentException("Unclosed brackets in: " + s); + else if (quote % 2 != 0) + throw new IllegalArgumentException("Unclosed or missing quotes in: " + s); + else + { + result.add(s.substring(lastIndex == 0 ? 0 : lastIndex + 1, s.length()).trim()); + } + + return result.toArray(new String[0]); + } + + /** + * @param s | CharSequence to search! + * @param oneOf | Characters to find! + * + * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! + * + * @since 1.3.0 + */ + public static int indexOfNotInObj(CharSequence s, char... oneOf) + { + return indexOfNotInObj(s, true, oneOf); + } + + /** + * @param s | CharSequence to search! + * @param firstIndex | If true, first index will be returned, if false last index will be returned. + * @param oneOf | Characters to find! + * + * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! + * + * @since 1.3.5 + */ + public static int indexOfNotInObj(CharSequence s, boolean firstIndex, char... oneOf) + { + int found = -1; + for (int i = 0, brackets = 0, quote = 0, len = s.length(); i < len; i++) + { + char ch = s.charAt(i); + if (ch == '"') + quote++; + + if (quote % 2 == 0) + { + if (brackets == 0 && /*oneOf.length == 0 ? ch == oneOf[0] :*/ isOneOf(ch, oneOf)) + { + found = i; + if (firstIndex) + return found; + } + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing closing bracket in: " + s); + } + } + } + return found; + } + + /** + * @param s | CharSequence to search! + * @param sequenceToFind | CharSequence to find! + * + * @return Index of first found CharSequence that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! + * + * @since 1.3.0 + */ + public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind) + { + return indexOfNotInObj(s, sequenceToFind, true); + } + + /** + * @param s | CharSequence to search! + * @param sequenceToFind | CharSequence to find! + * @param firstIndex | If true, first index will be returned, if false last index will be returned. + * + * @return Index of first found CharSequence that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! + * + * @since 1.3.5 + */ + public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind, boolean firstIndex) + { + int found = -1; + for (int i = 0, brackets = 0, quote = 0, match = 0, len = s.length(), lenToFind = sequenceToFind.length(); i < len; i++) + { + char ch = s.charAt(i); + if (ch == '"') + quote++; + + if (quote % 2 == 0) + { + if (brackets == 0 && ch == sequenceToFind.charAt(match++)) + { + if (match == lenToFind) + { + found = i - match + 1; + if (firstIndex) + return found; + match = 0; + } + } + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing closing bracket in: " + s); + } + else + match = 0; + } + } + return found; + } + + /** + * @param str | String to do replacements in! + * @param target | Target to replace! + * @param replacement | Replacement for target! + * + * @return Inserted string after replacing all targets with replacements similar to {@link String#replace(CharSequence, CharSequence)} but faster! + * + * @since 1.2.0 + */ + public static String fastReplace(String str, String target, CharSequence replacement) + { + int targetLength = target.length(); + if (targetLength == 0) + return str; + + int i1 = 0, i2 = str.indexOf(target); + if (i2 < 0) + return str; + + StringBuilder sb = new StringBuilder(targetLength > replacement.length() ? str.length() : str.length() * 2); + do + { + sb.append(str, i1, i2).append(replacement); + i1 = i2 + targetLength; + i2 = str.indexOf(target, i1); + } while (i2 > 0); + + return sb.append(str, i1, str.length()).toString(); + } + + /** + * @param ch | Char to compare! + * @param chars | Chars to match! + * + * @return True if inserted char is any of inserted chars! + * + * @since 1.3.0 + */ + public static boolean isOneOf(int ch, char... chars) + { + if (chars.length > 0) + { + for (int i = 0, len = chars.length; i < len; i++) + if (chars[i] == ch) + return true; + } + return false; + } + + /** + * @return {@link String#contains(CharSequence)} for char sequence! + * + * @since 1.3.0 + */ + public static boolean contains(CharSequence str, char... oneOf) + { + for (int i = 0, len = str.length(); i < len; i++) + if (isOneOf(str.charAt(i), oneOf)) + return true; + return false; + } + + /** + * @param str | String to display! + * @param pos | Position to display! + * + * @return String with displayed position! + * Use for debugging or error printing! + * + * @since 1.3.2 + */ + public static String showPosInString(CharSequence str, int pos) + { + return str + "\n" + multilpy(' ', pos) + "^"; + } + + /** + * @param obj | Object to map the serializer variables into! + * @param fromSerializer | Source serializer to map obj from! + * @param fieldNamesToUse | Array of obj field names to map/populate from scopes variables using setters (write method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link Scope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! + * + * @return Same obj after being populated/mapped by contents of fromSerializer via requested fields (fieldNamesToUse) and conversion rules listed below! + * Table of specific Serializer --> Object conversions: + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Object (obj) typeAction with obj
{@link File}{@link Serializer#SerializeTo(File)}
{@link Appendable}{@link Serializer#SerializeTo(Appendable)}
{@link OutputStream}{@link Serializer#SerializeTo(OutputStream)}
{@link URL}Serializer (fromSerializer) will open connection with {@link URL} and attempt serialize its content to it if possible!
{@link URLConnection}Serializer (fromSerializer) will attempt serialize its content into given {@link URLConnection} if possible!
{@link CharSequence} (as http address)Serializer (fromSerializer) will open connection with url and get + serialize the content into it if possible!
Others (default){@link Scope#into(Object, GenericScope, String...)} (return description)
+ + * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often) or when something went wrong during serialization! + * @throws IntrospectionException when there were no PropertyDescriptor found for obj class! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public static T into(Object obj, Serializer fromSerializer, String... fieldNamesToUse) throws Exception, IntrospectionException + { + if (obj instanceof File) + { + fromSerializer.SerializeTo((File) obj); + return (T) obj; + } + + if (obj instanceof Appendable) + { + fromSerializer.SerializeTo((Appendable) obj); + return (T) obj; + } + + if (obj instanceof OutputStream) + { + fromSerializer.SerializeTo((OutputStream) obj); + return (T) obj; + } + + if (obj instanceof URL) + { + URLConnection con = ((URL) obj).openConnection(); + con.setDoOutput(true); + if (con instanceof HttpURLConnection) + post(fromSerializer, (HttpURLConnection) con); + else + fromSerializer.SerializeTo(con.getOutputStream()); + return (T) con; + } + + if (obj instanceof URLConnection) + { + if (obj instanceof HttpURLConnection) + post(fromSerializer, (HttpURLConnection) obj); + else + fromSerializer.SerializeTo(((URLConnection) obj).getOutputStream()); + return (T) obj; + } + + try + { + if (obj instanceof CharSequence) + { + if (indexOfNotInObj((CharSequence) obj, "http") == 0) + { + URLConnection con = new URL(obj.toString()).openConnection(); + con.setDoOutput(true); + if (con instanceof HttpURLConnection) + post(fromSerializer, (HttpURLConnection) con); + else + fromSerializer.SerializeTo(con.getOutputStream()); + return (T) con; + } + + try + { + File file = new File(obj.toString()); + fromSerializer.SerializeTo(file); + return (T) file; + } + catch (Exception e) + {} + } + } + catch (IOException e) + {} + + return Scope.into(obj, fromSerializer, fieldNamesToUse); + } + + /** + * @param newInstance | New instance of specific {@link Serializer} + * @param fromObj | Object to create serializer from! + * @param fieldNamesToUse | Array of obj field names to map into scopes variables using getters (read method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link GenericScope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! + * + * @return {@link Serializer} created from given fromObj by mapping obj's fields into variables of created serializer via given fields (fieldNamesToUse) and conversion rules listed below!!

+ * Table of specific Object --> Serializer conversions: + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Object (fromObj) typeObtained serializer content (return)
{@link CharSequence}{@link Serializer#LoadFrom(CharSequence)}
{@link CharSequence} (as http address)Serializer (newInstance) will open connection with url and get + deserialize the content from it if possible!
{@link File}{@link Serializer#LoadFrom(File)}
{@link Reader}{@link Serializer#LoadFrom(Reader)}
{@link InputStream}{@link Serializer#LoadFrom(InputStream)}
{@link URL}Serializer (newInstance) will open connection with {@link URL} and get + deserialize the content from it if possible!
{@link URLConnection}Serializer (newInstance) will attempt to get + deserialize the content from given {@link URLConnection} if possible!
Others (default){@link Scope#from(Object, String...)} (return description)
+ * + * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often) or when something went wrong during deserialization! + * @throws IntrospectionException when there were no PropertyDescriptor found for obj class! + * + * @since 1.3.5 + */ + public static Serializer from(Serializer newInstance, Object fromObj, String... fieldNamesToUse) throws Exception, IntrospectionException + { + if (fromObj instanceof CharSequence) + { + if (indexOfNotInObj((CharSequence) fromObj, "http") == 0) + try + { + return newInstance.LoadFrom(new URL(fromObj.toString()).openStream()); + } + catch (IOException e) + {} + + try + { + return newInstance.LoadFrom(new File(fromObj.toString())); + } + catch (Exception e) + {} + + return newInstance.LoadFrom((CharSequence) fromObj); + } + + if (fromObj instanceof File) + return newInstance.LoadFrom((File) fromObj); + if (fromObj instanceof Reader) + return newInstance.LoadFrom((Reader) fromObj); + if (fromObj instanceof InputStream) + return newInstance.LoadFrom((InputStream) fromObj); + if (fromObj instanceof URL) + return newInstance.LoadFrom(((URL) fromObj).openStream()); + if (fromObj instanceof URLConnection) + return newInstance.LoadFrom(((URLConnection) fromObj).getInputStream()); + + newInstance.addAll(Scope.from(fromObj, fieldNamesToUse)); + return newInstance; + } + + /** + * This will serialize serializer into http query post request however this is not the best networking and you should implement your own http client if you want SerialX to serialize and deserialize remote content! + * + * @param serializer | Serializer to post. + * @param conn | Http connection to use! + * + * @throws IOException if posting failed! + * + * @since 1.3.5 + */ + public static void post(Serializer serializer, HttpURLConnection conn) throws IOException + { + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : serializer.varEntrySet()) + { + if (postData.length() != 0) + postData.append('&'); + postData.append(URLEncoder.encode(param.getKey(), "UTF-8")).append('='); + postData.append(URLEncoder.encode(serializer.getParsers().toString(param.getValue()).toString(), "UTF-8")); + } + + for (Object param : serializer) + { + if (postData.length() != 0) + postData.append('&'); + postData.append(URLEncoder.encode(serializer.getParsers().toString(param).toString(), "UTF-8")); + } + + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + conn.setDoOutput(true); + conn.getOutputStream().write(postDataBytes); + } + + /** + * This is a "dummy" class that {@link Serializer} uses internally as an OOP programmatic interpretation of null. In otherwise this is wrapper object for null. + * Note: You should not be able to come in contact with this during serialization and loading, if you did then you most likely encountered and bug and you should report it! + * + * @author PETO + * + * @since 1.2.2 + */ + public static final class NULL + { + public static Object toOopNull(Object obj) + { + return obj == null ? new NULL() : obj; + } + + @Override + public boolean equals(Object obj) + { + return obj == null || obj instanceof NULL; + } + + @Override + public String toString() + { + return "null"; + } + } +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java new file mode 100644 index 0000000..ab77cc0 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java @@ -0,0 +1,199 @@ +package org.ugp.serialx.converters; + +import static org.ugp.serialx.Serializer.ToClasses; +import static org.ugp.serialx.Serializer.indexOfNotInObj; +import static org.ugp.serialx.Serializer.splitValues; + +import java.lang.reflect.Array; +import java.util.Arrays; + +/** + * This converter is capable of converting primitive arrays. + * Its case sensitive! + *
+ *
+ * Table of sample string <--> object conversions: + + + + + + + + + + + + + + + + + + +
StringObject
1 2 3new int[] {1, 2, 3}
4 5 "hello!"new Object[] {4, 5, "hello!"}
"Lorem" "ipsum"new String[] {"Lorem", "ipsum"}
+ *
+ * This parser requires one optional parse method arg that is type of boolean at index 1 and it specifies if resolving datatype of a parsed array is required (default true). + * + * @author PETO + * + * @since 1.3.0 + */ +public class ArrayConverter implements DataConverter +{ + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + if (indexOfNotInObj(str, ' ') > 0) + { + boolean findArrType = true; + if (args.length > 1 && args[1] instanceof Boolean) + findArrType = (boolean) args[1]; + + String[] strObjs = tokenize(str); + int len = strObjs.length; + Object[] objs = new Object[len]; + + Class arrClass = null; + for (int i = 0; i < len; i++) + { + Object obj = objs[i] = myHomeRegistry.parse(strObjs[i], args); + if (obj != null) + if (arrClass == null) + arrClass = obj.getClass(); + else if (arrClass != obj.getClass()) + arrClass = Object.class; + } + + if (findArrType && arrClass != null && !arrClass.equals(Object.class)) + try + { + return castArray(objs, arrClass); + } + catch (IllegalArgumentException e) + {} + return objs; + } + return CONTINUE; + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (obj != null && myHomeRegistry != null && obj.getClass().isArray()) + { + int tabs = 0, index = 0; + if (args.length > 2 && args[2] instanceof Integer) + index = (int) args[2]; + + if (index <= 0 || myHomeRegistry.indexOf(OperationGroups.class) > -1) + { + if (args.length > 1 && args[1] instanceof Integer) + tabs = (int) args[1]; + + if (args.length > 2) + args[2] = index + 1; + + StringBuilder sb = new StringBuilder(); + for (int i = 0, length = Array.getLength(obj), sizeEndl = 10000; i < length; i++) + { + CharSequence str = myHomeRegistry.toString(Array.get(obj, i), args); + char ch = str.charAt(0); + if (ch == '{' || ch == '[') + sb.append("("+str+")"); + else + sb.append(str); + + if (i < length-1) + if (sb.length() > sizeEndl) + { + sb.append('\n'); + for (int j = 0; j < tabs+1; j++) + sb.append('\t'); + sizeEndl += 10000; + } + else + sb.append(' '); + } + return index > 0 ? sb.insert(0, '(').append(')') : sb; + } + } + return CONTINUE; + } + + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object objToDescribe, Object... argsUsedConvert) + { + return "Primitive array " + objToDescribe + " converted by " + getClass().getName(); + } + + /** + * @param str | String to tokenize! + * + * @return String splitted according to defined rules! + * + * @since 1.3.2 + */ + public String[] tokenize(String str) + { + return splitValues(str, ' '); + } + + /** + * @param sourceArray | Array to cast! + * @param toType | Type to cast array in to! + * + * @return Array object casted in to required type! + * + * @since 1.3.2 + */ + public static Object castArray(Object[] sourceArray, Class toType) + { + int len = sourceArray.length; + Object arr = Array.newInstance(ToClasses(toType)[0], len); + for (int i = 0; i < len; i++) + Array.set(arr, i, sourceArray[i]); + return arr; + } + + /** + * @param arr1 | Object one that might be array! + * @param arr2 | Object two that might be array! + * + * @return New array consisting of array 1 and array 2! + * + * @throws IllegalArgumentException if object one is not an array! + * + * @since 1.3.2 + */ + public static Object[] mergeArrays(Object arr1, Object arr2) + { + Object[] array1 = fromAmbiguous(arr1), array2 = arr2.getClass().isArray() ? fromAmbiguous(arr2) : new Object[] {arr2}; + Object[] result = Arrays.copyOf(array1, array1.length + array2.length); + System.arraycopy(array2, 0, result, array1.length, array2.length); + return result; + } + + /** + * @param array | Object that might be array! + * + * @return Object transformed in to primitive array! + * + * @throws IllegalArgumentException if the specified object is not an array! + * + * @since 1.3.2 + */ + public static Object[] fromAmbiguous(Object array) + { + int len1 = Array.getLength(array); + Object[] arr = new Object[len1]; + for (int i = 0; i < len1; i++) + arr[i] = Array.get(array, i); + return arr; + } +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java new file mode 100644 index 0000000..094c4be --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java @@ -0,0 +1,89 @@ +package org.ugp.serialx.converters; + +/** + * This converter is capable of converting {@link String}. + * Its case insensitive! + *
+ *
+ * Table of all string <--> object conversions: + + + + + + + + + + + + + + + + + + + + + + +
StringObject
truenew Boolean(true)
tnew Boolean(true)
falsenew Boolean(false)
fnew Boolean(false)
+ + * @author PETO + * + * @since 1.3.0 + */ +public class BooleanConverter implements DataConverter +{ + public boolean shorten; + + public BooleanConverter() + { + this(true); + } + + public BooleanConverter(boolean shorten) + { + setShorten(shorten); + } + + @Override + public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) + { + if (arg.equalsIgnoreCase("t") || arg.equalsIgnoreCase("true")) + return new Boolean(true); + else if (arg.equalsIgnoreCase("f") || arg.equalsIgnoreCase("false")) + return new Boolean(false); + return CONTINUE; + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (obj instanceof Boolean) + return isShorten() ? (boolean) obj ? "T" : "F" : (boolean) obj ? "true" : "false"; + return CONTINUE; + } + + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) + { + return new StringBuilder().append("Primitive data type: \"").append(obj).append("\" the ").append(obj.getClass().getSimpleName().toLowerCase()).append(" value!"); + } + + public boolean isShorten() + { + return shorten; + } + + public void setShorten(boolean shorten) + { + this.shorten = shorten; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java new file mode 100644 index 0000000..90c775b --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java @@ -0,0 +1,69 @@ +package org.ugp.serialx.converters; + +import static org.ugp.serialx.Serializer.fastReplace; + +/** + * This converter is capable of converting {@link Character}. + * Its case sensitive! + *
+ *
+ * Table of sample string <--> object conversions: + + + + + + + + + + + + + + +
StringObject
'a'new Character('a')
'35'new Character('#')
+ * + * @author PETO + * + * @since 1.3.0 + */ +public class CharacterConverter implements DataConverter +{ + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + if (str.length() > 1 && str.charAt(0) == '\'' && str.charAt(str.length()-1) == '\'') + try + { + if (str.equals("''")) + return new Character(' '); + else + return new Character((char) Integer.parseInt(str = fastReplace(str, "'", ""))); + } + catch (Exception e) + { + return new Character(str.charAt(0)); + } + return CONTINUE; + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (obj instanceof Character) + return "'"+(int) (char) obj+"'"; + return CONTINUE; + } + + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) + { + return new StringBuilder().append("Primitive data type: \"").append(obj).append("\" the ").append(obj.getClass().getSimpleName().toLowerCase()).append(" value!"); + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java new file mode 100644 index 0000000..c6fadf4 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java @@ -0,0 +1,103 @@ +package org.ugp.serialx.converters; + +import org.ugp.serialx.Registry; + +/** + * This is DataParser with extended functionality! {@link DataConverter} can also parse data like DataParser but is also capable of converting them back to string! + * 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! + * + * @see DataParser + * + * @author PETO + * + * @since 1.3.0 + */ +public interface DataConverter extends DataParser +{ + /** + * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @param obj | Object to convert into string! + * @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)! + * + * @return Object converted to string. Easiest way to do this is obj.toString() but you most likely want some more sofisticated formating. + * 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! + * + * @since 1.3.0 + */ + CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args); + + /** + * @param myHomeRegistry | Registry of parsers (might be null)! + * @param objToDescribe | Object to generate description for! + * @param argsUsedConvert | Array of arguments that were used for converting described object! + * + * @return Description for object (should not contains endlines)! + * + * @since 1.3.0 + */ + default CharSequence getDescription(ParserRegistry myHomeRegistry, Object objToDescribe, Object... argsUsedConvert) + { + return "Object of " + objToDescribe.getClass().getName() + ": \"" + objToDescribe + "\" converted by " + this; + } + + /** + * @param obj | Object to convert into string! + * @param args | Additional arguments that will be obtained in {@link DataParser#toString(String, Object...)}! + * + * @return Object converted to string using {@link DataConverter} suitable converter picked from {@link DataParser#REGISTRY}! + * {@link DataConverter#toString(Object, Object...)} of all registered converters will be called however only suitable ones should return the result, others should return {@link DataParser#CONTINUE}! + * + * @since 1.3.0 + */ + public static CharSequence objToString(Object obj, Object... args) + { + return REGISTRY.toString(obj, args); + } + + /** + * @deprecated Use {@link ParserRegistry#toString(Object, Object...)}! + * + * @param registry | Registry to use! + * @param obj | Object to convert into string! + * @param args | Additional arguments that will be obtained in {@link DataParser#toString(String, Object...)}! + * + * @return Object converted to string using {@link DataConverter} suitable converter picked from registry! + * {@link DataConverter#toString(Object, Object...)} of all registered converters will be called however only suitable ones should return the result, others should return {@link DataParser#CONTINUE}! + * + * @since 1.3.0 + */ + @Deprecated + public static CharSequence objToString(Registry registry, Object obj, Object... args) + { + if (registry instanceof ParserRegistry) + return ((ParserRegistry) registry).toString(obj, args); + return objToString(new ParserRegistry(registry), obj, args); + } + + /** + * @deprecated Use {@link ParserRegistry#getConverterFor(Object, Object...)}! + * + * @param registry | Registry to use! + * @param obj | Object to find converter for! + * @param args | Additional arguments that will be obtained in {@link DataParser#toString(String, Object...)}! + * + * @return Converter suitable for converting required obj to string, selected from registry! + */ + @Deprecated + public static DataConverter getConverterFor(Registry registry, Object obj, Object... args) + { + if (registry instanceof ParserRegistry) + return ((ParserRegistry) registry).getConverterFor(obj, args); + return getConverterFor(new ParserRegistry(registry), obj, args); + } + + /** + * @return "Object of " + objToDescribe.getClass().getName() + ": \"" + objToDescribe + "\" converted by " + DataParser.class.getName() + * + * @since 1.3.2 + */ + public static String getDefaultDescriptionFor(Object objToDescribe) + { + return "Object of " + objToDescribe.getClass().getName() + ": \"" + objToDescribe + "\" converted by " + DataConverter.class.getName(); + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java new file mode 100644 index 0000000..37738bd --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -0,0 +1,427 @@ +package org.ugp.serialx.converters; + +import java.util.Collection; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.Registry; +import org.ugp.serialx.Scope; +import org.ugp.serialx.converters.operators.NegationOperator; + +/** + * This class supposed to be used to parse strings back to java objects using {@link DataParser#parse(String, Object...)}! + * Instance of DataParser should be registered into {@link DataParser#REGISTRY} or other external registry in order to work, also only one instance of each DataParser should be used and accessed via this registry!
+ * Static method {@link DataParser#parseObj} is used to walk this registry and parse inserted string in process, in other words we can say that this interface contains
recursive descent parse that uses its own implementations! + * + * @author PETO + * + * @since 1.3.0 + */ +public interface DataParser +{ + /** + * This is the way how {@link DataParser} represents void. You can return this in {@link DataParser#parse(String, Object...)} as a void. + * This can be useful when you are adding something to "storage" while parsing and you do not want it to be returned. + * + * @since 1.2.2 (moved to {@link DataParser} since 1.3.0) + * + * @see Void#TYPE + */ + public static final Object VOID = Void.TYPE; + + /** + * 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. + * + * @since 1.3.0 + */ + public static final String CONTINUE = new String(); + + /** + * This is DataParser registry. Here your parser implementations should be registered in order to work properly! + * Only one parser should be usable for specific input string, otherwise order of registration is crucial! + * Defaultly there are parsers from ugp.org.SerialX.converters. + * + * @since 1.3.0 + */ + //TODO ParserRegistry + public static final ParserRegistry REGISTRY = new ParserRegistry(new OperationGroups(), new VariableConverter(), /*new ConditionalAssignmentOperators(), new ComparisonOperators(), new LogicalOperators(), new ArithmeticOperators(),*/ new StringConverter(), new ObjectConverter(), new ArrayConverter(), new NumberConverter(), new NegationOperator(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter()); + + /** + * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @param str | Source string! + * @param args | Some additional args. This can be anything and it demands on implementation of DataParser. Default SerialX API implementation will provide one optional argument with {@link Scope} that value was loaded from! + * + * @return Object that was parsed from obtained string. Special return types are {@link DataParser#VOID} and {@link DataParser#CONTINUE}. Continue will ignore this parser and jump to another one in registry. + * + * @since 1.3.0 + */ + Object parse(ParserRegistry myHomeRegistry, String str, Object... args); + + /** + * @param str | Source string to parse using suitable parser from registry. + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @return Object that was parsed from obtained string using suitable parser. This method will iterate {@link DataParser#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! You can return {@link DataParser#CONTINUE} to mark parser as not suitable for parsing obtained string. + * If no suitable result was found, null will be returned and you will be notified in console (null does not necessary means invalid output since null can be proper result of parsing)! + * + * @since 1.3.0 + */ + public static Object parseObj(String str, Object... args) + { + return REGISTRY.parse(str, args); + } + + /** + * @deprecated Use {@link ParserRegistry#parse(String, Object...)}! + * + * @param registry | Registry to use! + * @param str | Source string to parse using suitable parser from registry. + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @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! You can return {@link DataParser#CONTINUE} to mark parser as not suitable for parsing obtained string. + * If no suitable result was found, null will be returned and you will be notified in console (null does not necessary means invalid output since null can be proper result of parsing)! + * + * @since 1.3.0 + */ + @Deprecated + public static Object parseObj(Registry registry, String str, Object... args) + { + return parseObj(registry, str, false, null, args); + } + + /** + * @deprecated Use {@link ParserRegistry#parse(String, boolean, Class[], Object...)}! + * + * @param registry | Registry to use! + * @param str | Source string to parse using suitable parser from registry. + * @param returnAsStringIfNotFound | If true, inserted string will be returned instead of null and error message! + * @param ignore | {@link DataParser} class to ignore! + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @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! You can return {@link DataParser#CONTINUE} to mark parser as not suitable for parsing obtained string. + * If no suitable result was found, null or inserted string will be returned based on returnAsStringIfNotFound! + * + * @since 1.3.0 + */ + @Deprecated + public static Object parseObj(Registry registry, String str, boolean returnAsStringIfNotFound, Class[] ignore, Object... args) + { + if (registry instanceof ParserRegistry) + return ((ParserRegistry) registry).parse(str, returnAsStringIfNotFound, ignore, args); + return parseObj(new ParserRegistry(registry), str, returnAsStringIfNotFound, ignore, args); + } + + /** + * @deprecated Use {@link DataParser.REGISTRY#getParserFor(String, Object...)}! + * + * @param registry | Registry to search! + * @param str | String to find parser for! + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @return Parser suitable for parsing required string, selected from {@link DataParser#REGISTRY}! + * + * @since 1.3.0 + */ + @Deprecated + public static DataParser getParserFor(String str, Object... args) + { + return getParserFor(REGISTRY, str, args); + } + + /** + * @deprecated Use {@link DataParser#getParserFor(String, Object...)}! + * + * @param registry | Registry to search! + * @param str | String to find parser for! + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @return Parser suitable for parsing required string, selected from inserted registry! + * + * @since 1.3.0 + */ + @Deprecated + public static DataParser getParserFor(Registry registry, String str, Object... args) + { + if (registry instanceof ParserRegistry) + return ((ParserRegistry) registry).getParserFor(str, args); + return getParserFor(new ParserRegistry(registry), str, args); + } + + /** + * Registry to store {@link DataParser} and {@link DataConverter} and performing parsing (String -> Object) and converting (Object -> String) operations with them! + * + * @author PETO + * + * @since 1.3.5 + */ + public static class ParserRegistry extends Registry + { + private static final long serialVersionUID = -2598324826689380752L; + + protected DataParser[] parsingCache; + protected DataParser[] convertingCache; + + /** + * Constructs an {@link ParserRegistry} with the specified initial capacity. + * + * @param initialSize | Initial capacity. + * + * @since 1.3.5 + */ + public ParserRegistry(int initialSize) + { + super(initialSize); + } + + /** + * Constructs an {@link ParserRegistry} with content of c. + * + * @param c | Initial content of registry. + * + * @since 1.3.5 + */ + public ParserRegistry(Collection c) + { + super(c); + } + + /** + * Constructs an {@link ParserRegistry} with parsers. + * + * @param parsers | Initial content of registry. + * + * @since 1.3.5 + */ + public ParserRegistry(DataParser... parsers) + { + super(parsers); + } + + @Override + public ParserRegistry clone() + { + return new ParserRegistry(this); + } + + /** + * @param str | String to find parser for! + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @return Parser suitable for parsing required string, selected from inserted registry! + * + * @since 1.3.5 + */ + public DataParser getParserFor(String str, Object... args) + { + for (DataParser parser : this) + if (parser.parse(this, str, args) != CONTINUE) + return parser; + return null; + } + + /** + * @param obj | Object to find converter for! + * @param args | Additional arguments that will be obtained in {@link DataParser#toString(String, Object...)}! + * + * @return Converter suitable for converting required obj to string, selected from registry! + * + * @since 1.3.5 + */ + public DataConverter getConverterFor(Object obj, Object... args) + { + for (DataParser parser : this) + if (parser instanceof DataConverter && ((DataConverter)parser).toString(this, obj, args) != CONTINUE) + return (DataConverter) parser; + return null; + } + + /** + * @param obj | Object to convert into string! + * @param args | Additional arguments that will be obtained in {@link DataParser#toString(String, Object...)}! + * + * @return Object converted to string using {@link DataConverter} suitable converter picked from registry! + * {@link DataConverter#toString(Object, Object...)} of all registered converters will be called however only suitable ones should return the result, others should return {@link DataParser#CONTINUE}! + * + * @since 1.3.5 + */ + public CharSequence toString(Object obj, Object... args) + { + CharSequence str = null; + if (convertingCache != null) + for (DataParser parser : convertingCache) + if (parser != null && (str = ((DataConverter) parser).toString(this, obj, args)) != CONTINUE) + return str; + + for (int i = 0, size = size(); i < size; i++) + { + DataParser parser = get(i); + if (parser instanceof DataConverter && (str = ((DataConverter) parser).toString(this, obj, args)) != CONTINUE) + { + if (convertingCache != null && i < convertingCache.length) + convertingCache[i] = parser; + return str; + } + } + + LogProvider.instance.logErr(DataConverter.class.getSimpleName() + ": Unable to convert \"" + obj == null ? "null" : obj.getClass().getName() + "\" to string because none of registered converters were aplicable for this object!", null); + return null; + } + + /** + * @param str | Source string to parse using suitable parser from registry. + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @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! You can return {@link DataParser#CONTINUE} to mark parser as not suitable for parsing obtained string. + * If no suitable result was found, null will be returned and you will be notified in console (null does not necessary means invalid output since null can be proper result of parsing)! + * + * @since 1.3.5 + */ + public Object parse(String str, Object... args) + { + return parse(str, false, null, args); + } + + /** + * @param str | Source string to parse using suitable parser from registry. + * @param returnAsStringIfNotFound | If true, inserted string will be returned instead of null and error message! + * @param ignore | {@link DataParser} class to ignore! + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @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! You can return {@link DataParser#CONTINUE} to mark parser as not suitable for parsing obtained string. + * If no suitable result was found, null or inserted string will be returned based on returnAsStringIfNotFound! + * + * @since 1.3.5 + */ + public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ignore, Object... args) + { + Object obj = null; + if (parsingCache != null) + for (DataParser parser : parsingCache) + if (parser != null && (obj = parser.parse(this, str, args)) != CONTINUE) + return obj; + + registryLoop: for (int i = 0, size = size(); i < size; i++) + { + DataParser parser = get(i); + if (ignore != null) + for (Class cls : ignore) + if (cls == parser.getClass()) + continue registryLoop; + + if ((obj = parser.parse(this, str, args)) != CONTINUE) + { + if (parsingCache != null && i < parsingCache.length) + parsingCache[i] = parser; + return obj; + } + } + + if (returnAsStringIfNotFound) + return str; + + LogProvider.instance.logErr(DataParser.class.getSimpleName() + ": Unable to parse \"" + str + "\" because none of registred parsers were suitable!", null); + return null; + } + + /** + * @param classOfParserToPrecache | Class of parser to precache! + * + * @return Int array of 2 signifying the index of where the parser was inserted in parsing cache and converting cache (index 0 = parsing cache index, index 1 = converting cache index) + */ + public int[] preCache(Class classOfParserToPrecache) + { + int[] ret = {-1, -1}; + if (parsingCache == null && convertingCache == null) + return ret; + + DataParser parser = null; + int i = 0; + for (int size = size(); i < size; i++) + { + DataParser elm = get(i); + Class objCls = elm.getClass(); + if (objCls == classOfParserToPrecache) + { + parser = elm; + break; + } + } + + if (parser == null) + return ret; + + if (i < parsingCache.length) + { + parsingCache[i] = parser; + ret[0] = i; + } + + if (i < convertingCache.length) + { + convertingCache[i] = parser; + ret[1] = i; + } + + return ret; + } + + /** + * Recreates and enables both parsing cache and converting cache! Doing this might give you a solid performance boost when parsing or converting large amount of objects with this registry! But sometimes, this might cause some unexpected behavior especially when you have multiple parsers that are dependent on each other!
+ * Note: Doing this will destroy any existing cache (this is usually not a big problem)! + * + * @see ParserRegistry#destroyCache() + * + * @since 1.3.5 + */ + public void resetCache() + { + int size = size(); + resetCache(new DataParser[size], new DataParser[size]); + } + + /** + * You can use this to manually set caching arrays. Doing this might give you a solid performance boost when parsing or converting large amount of objects with this registry! But sometimes, this might cause some unexpected behavior especially when you have multiple parsers that are dependent on each other! + * + * @param parsingCache | Array of specific parsing cache to use (it can contains some preached parsers to use preferably). This array is supposed to be as long as this registry! + * @param convertingCache | Array of specific converter cache to use (it can contains some preached converters to use preferably). This array is supposed to be as long as this registry! + * + * @since 1.3.5 + */ + public void resetCache(DataParser[] parsingCache, DataParser[] convertingCache) + { + if (parsingCache != null) + this.parsingCache = parsingCache; + if (convertingCache != null) + this.convertingCache = convertingCache; + } + + /** + * Destroys any existing cache and stops any further caching! Use this if you are experiencing some strange behaviors! + * + * @since 1.3.5 + */ + public void destroyCache() + { + this.parsingCache = this.convertingCache = null; + } + + /** + * @return Cache array for parsing (null if caching is disabled)! + * + * @since 1.3.5 + */ + public DataParser[] getParsingCache() + { + return parsingCache; + } + + /** + * @return Cache array for converting (null if caching is disabled)! + * + * @since 1.3.5 + */ + public DataParser[] getConverterCache() + { + return convertingCache; + } + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java new file mode 100644 index 0000000..ce04a67 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java @@ -0,0 +1,61 @@ +package org.ugp.serialx.converters; + +import org.ugp.serialx.Serializer.NULL; + +/** + * This converter is capable of converting "nothing" otherwise known as null and {@link DataParser#VOID}. + * Its case insensitive! + *
+ *
+ * Table of all string <--> object conversions: + + + + + + + + + + + + + + +
StringObject
nullnull (object)
voidDataParser.VOID
+ * + * @author PETO + * + * @since 1.3.0 + */ +public class NullConverter implements DataConverter +{ + @Override + public Object parse(ParserRegistry registry, String str, Object... args) + { + if (str.equalsIgnoreCase("null")) + return null; + else if (str.equalsIgnoreCase("void")) + return VOID; + return CONTINUE; + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (obj == null || obj instanceof NULL) + return "null"; + return CONTINUE; + } + + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) + { + return "Null, the nothing!"; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java new file mode 100644 index 0000000..9936c63 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -0,0 +1,205 @@ +package org.ugp.serialx.converters; + +import static org.ugp.serialx.Serializer.contains; +import static org.ugp.serialx.Serializer.fastReplace; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.converters.operators.NegationOperator; + +/** + * 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! + * Its case insensitive! + *
+ *
+ * Table of sample string <--> object conversions: + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StringObject
1337new Integer(1337)
1337Lnew Long(1337)
1337Snew Short(1337)
137Ynew Byte(137)
13.37new Double(13.37)
13.37Dnew Double(13.37)
13.37Fnew Float(13.37)
+ Table of sample string --> object conversions: + + + + + + + + + +
0xffnew Integer(255)
0b1111new Integer(15)
+ * + * @author PETO + * + * @since 1.3.0 + */ +public class NumberConverter implements DataConverter +{ + /** + * {@link DecimalFormat} to format decimal numbers (double, float) during serialization!
+ * Default {@link DecimalFormat} will round decimal numbers to 3 decimal places (format pattern #.###)! + * + * Set this on null and decimal numbers will not be formated! Do this when you need accuracy! + * + * @serial 1.1.0 (moved to {@link NumberConverter} since 1.3.0) + */ + protected DecimalFormat decimalFormatter = new DecimalFormat("#.###", DecimalFormatSymbols.getInstance(Locale.US)); + + @Override + public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) + { + if (arg.length() > 0) + { + char ch = arg.charAt(0); + if (ch == '+' || ch == '-' || ch == '.' || (ch >= '0' && ch <= '9')) + { + arg = formatNum(arg.toLowerCase()); + if (arg.equals(".")) + return CONTINUE; + if (contains(arg, '.') || (!arg.startsWith("0x") && arg.endsWith("f") || arg.endsWith("d"))) + { + if (arg.endsWith("f")) + return new Float(fastReplace(arg, "f", "")); + else + return new Double(fastReplace(arg, "d", "")); + } + else + try + { + Number integer; + boolean isNeg = arg.charAt(0) == '-'; + if (isNeg) + arg = arg.substring(1); + if (arg.endsWith("l")) + integer = new Long(Long.parseLong(fastReplace(fastReplace(fastReplace(arg, "l", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); + else if (arg.endsWith("s")) + integer = new Short(Short.parseShort(fastReplace(fastReplace(fastReplace(arg, "s", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); + else if (arg.endsWith("y")) + integer = new Byte(Byte.parseByte(fastReplace(fastReplace(arg, "y", ""), "0b", ""), arg.startsWith("0b") ? 2 : 10)); + else + integer = new Integer(Integer.parseInt(fastReplace(fastReplace(arg, "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); + return isNeg ? NegationOperator.negate(integer) : integer; + } + catch (NumberFormatException e) + { + if (arg.matches("[0-9.]+")) + try + { + return new Long(Long.parseLong(fastReplace(fastReplace(fastReplace(arg, "l", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); + } + catch (NumberFormatException e2) + { + LogProvider.instance.logErr("Number " + arg + " is too big for its datatype! Try to change its datatype to double (suffix D)!", e2); + return null; + } + } + } + } + return CONTINUE; + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (obj instanceof Number) + { + String str = decimalFormatter != null ? decimalFormatter.format(obj) : obj.toString(); + if (!contains(str, '.') && obj instanceof Double) + str += "D"; + else if (obj instanceof Float) + str += "F"; + else if (obj instanceof Long) + str += "L"; + if (obj instanceof Short) + str += "S"; + else if (obj instanceof Byte) + str += "Y"; + return str; + } + return CONTINUE; + } + + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) + { + return new StringBuilder().append("Primitive data type: \"").append(obj).append("\" the ").append(obj.getClass().getSimpleName().toLowerCase()).append(" value!"); + } + + /** + * @return {@link DecimalFormat} to format decimal numbers (double, float) during serialization or null if there is none! + * Value of {@link NumberConverter#decimalFormatter} + * + * @since 1.3.7 + */ + public DecimalFormat getDecimalFormatter() { + return decimalFormatter; + } + + /** + * @param decimalFormatter | New {@link DecimalFormat} to set for formating decimal numbers (double, float)! + * + * @since 1.3.7 + */ + public void setDecimalFormatter(DecimalFormat decimalFormatter) { + this.decimalFormatter = decimalFormatter; + } + + /** + * @param num | Number string to format! + * + * @return Original string with formated sign and deleted '_'! + * + * @since 1.3.0 + */ + public static String formatNum(String num) + { + if (num.length() > 2) + for (boolean minus = num.startsWith("+-") || num.startsWith("-+"); minus || num.startsWith("++") || num.startsWith("--"); minus = num.startsWith("+-") || num.startsWith("-+")) + { + num = num.substring(2); + if (minus) + num = "-"+num; + } + + return fastReplace(num, "_", ""); + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java new file mode 100644 index 0000000..59e55c8 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java @@ -0,0 +1,525 @@ +package org.ugp.serialx.converters; + +import static org.ugp.serialx.Serializer.InvokeStaticFunc; +import static org.ugp.serialx.Serializer.indexOfNotInObj; +import static org.ugp.serialx.Serializer.isOneOf; +import static org.ugp.serialx.Serializer.splitValues; + +import java.io.IOException; +import java.io.Serializable; +import java.io.StringReader; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; + +import org.ugp.serialx.GenericScope; +import org.ugp.serialx.JussSerializer; +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.Registry; +import org.ugp.serialx.Scope; +import org.ugp.serialx.Serializer; +import org.ugp.serialx.converters.imports.ImportsProvider; +import org.ugp.serialx.protocols.SerializationProtocol; +import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; + +/** + * This converter is capable of converting any Object using {@link SerializationProtocol} as well as invoking static functions! + * This is also responsible for {@link Scope}! + * Its case sensitive! + *
+ *
+ * Table of sample string <--> object conversions: + * + + + + + + + + + + + + + +
StringObject
ArrayList 2 4 6new ArrayList<>(Arrays.asList(2, 4, 6))
java.lang.Math::max 10 510
+
+ This parser requires additional parser arg at index 0 of type {@link GenericScope} or {@link Serializer} that will be used for further parsing and operating (default new {@link JussSerializer}).
+ This parser requires additional parser arg at index 3 of type {@link ProtocolRegistry} or {@link SerializationProtocol} itself that will be used for parsing protocol expressions (default {@link SerializationProtocol#REGISTRY}).
+ * This parser will insert one additional argument into array of additional parser args at index 4, in case of serialization index 5, that will be of type {@link Class} and it will contains information about class of object that is being unserialized or serialized using protocol!
+ * + * @author PETO + * + * @since 1.3.0 + */ +public class ObjectConverter implements DataConverter +{ + /** + * Set this on true to force program to use {@link Base64} serialization on {@link Serializable} objects. + * Doing this might result into some form of encryption but its less flexible and tends to be slower than SerialX {@link SerializationProtocol} system! + * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. + * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
+ * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
+ * Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! + * + * @since 1.0.0 (moved to {@link SerializableBase64Converter} since 1.3.0 and since 1.3.5 into {@link ObjectConverter}) + */ + protected boolean useBase64IfCan = false; + + @SuppressWarnings("unchecked") + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... compilerArgs) + { + Class objectClass = null, oldObjectClass; + boolean hasOp, hasCls = false; + char ch; + + if (str.length() > 0 && ((hasOp = (ch = str.charAt(0)) == '{' || ch == '[') && (hasCls = (ch = str.charAt(str.length()-1)) == '}' || ch == ']') /*|| containsNotInObj(str, ' ')*/ || (objectClass = getProtocolExprClass(str, compilerArgs)) != null)) + { + if (objectClass != null) + { + if (objectClass == IsSelectorScope.class) + { + StringBuilder sb = new StringBuilder(str); + sb.setCharAt(str.indexOf(' '), '='); + return myHomeRegistry.parse(sb.toString(), compilerArgs); + } + else + { + if (compilerArgs.length < 5) + compilerArgs = Arrays.copyOf(compilerArgs, 5); + oldObjectClass = (Class) compilerArgs[4]; + compilerArgs[4] = objectClass; + } + + String[] args = splitValues(str = str.trim(), ' '); + if (!isOneOf(args[0].charAt(0), '{', '[') && args[0].contains("::")) + { + String[] clsAttr = args[0].split("::"); + if (clsAttr.length > 1) + { + if (args.length > 1) + try + { + Object rtrn = InvokeStaticFunc(objectClass, clsAttr[1], parseAll(myHomeRegistry, args, 1, true, compilerArgs)); + compilerArgs[4] = oldObjectClass; + return rtrn; + } + catch (InvocationTargetException e) + { + LogProvider.instance.logErr("Exception while calling method \"" + clsAttr[1] + "\":", e); + e.printStackTrace(); + } + else + try + { + compilerArgs[4] = oldObjectClass; + return clsAttr[1].equals("class") ? objectClass : clsAttr[1].equals("new") ? Serializer.Instantiate(objectClass) : objectClass.getField(clsAttr[1]).get(null); + } + catch (NoSuchFieldException e) + { + try + { + Object rtrn = InvokeStaticFunc(objectClass, clsAttr[1], parseAll(myHomeRegistry, args, 1, true, compilerArgs)); + compilerArgs[4] = oldObjectClass; + return rtrn; + } + catch (InvocationTargetException e2) + { + LogProvider.instance.logErr("Exception while calling method \"" + clsAttr[1] + "\":", e2); + e.printStackTrace(); + } + } + catch (Exception e) + { + LogProvider.instance.logErr("Unable to obtain value of field \"" + clsAttr[1] + "\" in class \"" + objectClass.getSimpleName() + "\" because:", e); + e.printStackTrace(); + } + /*catch (ClassNotFoundException e) + { + LogProvider.instance.logErr("Unable to invoke \"" + args[0].split("::")[1] + "\" because class \"" + args[0].split("::")[0] + "\" was not found!"); + } */ + } + } + else + { + try + { + if ((ch = str.charAt(str.length()-1)) == ';' || ch == ',') + throw new ClassNotFoundException(); + + Object[] objArgs = parseAll(myHomeRegistry, args, 1, true, compilerArgs); + if (objArgs.length == 1 && objArgs[0] instanceof Scope && Scope.class.isAssignableFrom(objectClass)) + return objArgs[0]; + compilerArgs[4] = oldObjectClass; + return SerializationProtocol.unserializeObj(compilerArgs.length > 3 && compilerArgs[3] instanceof ProtocolRegistry ? (ProtocolRegistry) compilerArgs[3] : SerializationProtocol.REGISTRY, objectClass, objArgs); + + /*Object obj; + if (objArgs.length == 1 && objArgs[0] instanceof Scope) + { + Scope scope = (Scope) objArgs[0]; + if ((obj = p.unserialize(objectClass, scope.toValArray())) != null) + return obj; + return p.unserialize(objectClass, scope); + } + else + { + if ((obj = p.unserialize(objectClass, objArgs)) != null) + return obj; + return p.unserialize(objectClass, new Scope(objArgs)); + }*/ + } + catch (Exception e) + { + LogProvider.instance.logErr("Exception while unserializing instance of \"" + objectClass.getName() + "\":", e); + e.printStackTrace(); + } + } + compilerArgs[4] = oldObjectClass; + } + else + { + Serializer scope; + try + { + if (compilerArgs.length > 0 && compilerArgs[0] instanceof Serializer) + { + if (compilerArgs.length > 4 && compilerArgs[4] instanceof Class && Serializer.class.isAssignableFrom((Class) compilerArgs[4])) + scope = ((Serializer) compilerArgs[0]).emptyClone((Class) compilerArgs[4], (GenericScope) compilerArgs[0]); + else + scope = ((Serializer) compilerArgs[0]).emptyClone(); + } + else + scope = getPreferredSerializer(); + } + catch (Exception e) + { + scope = getPreferredSerializer(); + } + + if (indexOfNotInObj(str, '=', ':', ';', ',') > -1) + { + compilerArgs = compilerArgs.clone(); + compilerArgs[0] = false; + return ((Serializer) scope.inheritParent()).LoadFrom(new StringReader(str), compilerArgs); + } + + if (hasOp && hasCls) + { + str = str.substring(1, str.length()-1).trim(); + if (str.isEmpty()) + return scope; + + int index; + if ((index = indexOfNotInObj(str, '=', ';', ',')) > -1 && (index >= str.length()-1 || str.charAt(index+1) != ':') || (objectClass = getProtocolExprClass(str, compilerArgs)) == null || objectClass == IsSelectorScope.class) + { + compilerArgs = compilerArgs.clone(); + compilerArgs[0] = false; + return ((Serializer) scope.inheritParent()).LoadFrom(new StringReader(str), compilerArgs); + } + + if (objectClass != null && indexOfNotInObj(str, "::") > -1) + return myHomeRegistry.parse(str, compilerArgs); + return parse(myHomeRegistry, str, compilerArgs); + } + else if (str.split(" ").length > 1) + { + LogProvider.instance.logErr("Unable to unserialize \"" + str + "\"! Possible reason of this is absence of comma or semicolon, try to insert them into empty spaces!", null); + return null; + } + } + LogProvider.instance.logErr("Unable to unserialize \"" + str + "\" because there is no such class or source string is corrupted!", null); + return null; + } + return CONTINUE; + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) + { + return toString(myHomeRegistry, arg, null, args); + } + + /** + * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @param obj | Object to convert into string! + * @param preferedProtocol | Protocol to use preferably. + * @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)! + * + * @return Object converted to string. Easiest way to do this is obj.toString() but you most likely want some more sofisticated formating. + * 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! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, SerializationProtocol preferedProtocol, Object... args) + { + if (arg == null) + return CONTINUE; + + if (useBase64IfCan && arg instanceof Serializable) + return CONTINUE; + + if (arg instanceof Scope) + { + Serializer serializer; + try + { + if (arg instanceof Serializer) + serializer = (Serializer) arg; + else if (args.length > 0 && args[0] instanceof Serializer) + (serializer = ((Serializer) args[0]).emptyClone()).addAll((GenericScope) arg); + else + serializer = getPreferredSerializer(); + } + catch (Exception e) + { + serializer = getPreferredSerializer(); + } + + if (serializer instanceof JussSerializer) + ((JussSerializer) serializer).setGenerateComments(args.length > 5 && args[5] instanceof Boolean && (boolean) args[5]); + + try + { + if (args.length < 4) + args = Arrays.copyOf(args, 4); + else + args = args.clone(); + args[2] = 0; + args[3] = serializer.getProtocols(); + + StringBuilder sb = new StringBuilder(); + GenericScope parent; + if ((parent = serializer.getParent()) == null || serializer.getClass() != parent.getClass()) + sb.append(serializer.getImports().getAliasFor(arg.getClass()) + " "); + return serializer.SerializeAsSubscope(sb, args); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + else + { + if (preferedProtocol != null || (preferedProtocol = (SerializationProtocol) getProtocolFor(arg, SerializationProtocol.MODE_SERIALIZE, args)) != null) + { + Object[] objArgs; + Class oldObjectClass = null; + try + { + int tabs = 0, index = 0; + if (args.length > 1 && args[1] instanceof Integer) + tabs = (int) args[1]; + + if (args.length > 2 && args[2] instanceof Integer) + index = (int) args[2]; + + if (args.length < 5) + args = Arrays.copyOf(args, 5); + oldObjectClass = (Class) args[4]; + args[4] = arg.getClass();; + + objArgs = preferedProtocol.serialize(arg); + StringBuilder sb = new StringBuilder(ImportsProvider.getAliasFor(args.length > 0 ? args[0] : null, arg.getClass()) + (objArgs.length <= 0 ? "" : " ")); + + args = args.clone(); + for (int i = 0, sizeEndl = 10000; i < objArgs.length; i++) + { + if (args.length > 2) + args[2] = index + 1; + sb.append(myHomeRegistry.toString(objArgs[i], args)); + if (i < objArgs.length-1) + if (sb.length() > sizeEndl) + { + sb.append('\n'); + for (int j = 0; j < tabs+1; j++) + sb.append('\t'); + sizeEndl += 10000; + } + else + sb.append(' '); + } + + args[4] = oldObjectClass; + return index > 0 && objArgs.length > 0 ? sb.insert(0, '{').append('}') : sb; + } + catch (Exception e) + { + LogProvider.instance.logErr("Exception while serializing instance of \"" + arg.getClass().getName() + "\":", e); + e.printStackTrace(); + } + args[4] = oldObjectClass; + } + } + return CONTINUE; + } + + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) + { + if (obj instanceof Scope && ((Scope) obj).isEmpty()) + return "Empty scope!"; + else if (obj instanceof CharSequence && indexOfNotInObj((CharSequence) obj, '\n', '\r') != -1) + return "Multiline char sequence!"; + return new StringBuilder("Object of ").append(obj.getClass().getName()).append(": \"").append(obj.toString()).append("\" serialized using ").append(getProtocolFor(obj, SerializationProtocol.MODE_ALL, argsUsedConvert).toString()).append("!"); + } + + /** + * @return Serializer that is supposed to be used for serializing sub-scopes if there is no other option. + * + * @since 1.3.5 + */ + public Serializer getPreferredSerializer() + { + return new JussSerializer(); + } + + /** + * @return True if program is forced to use {@link Base64} serialization on {@link Serializable} objects. + * This might result into some form of encryption but its less flexible and tends to be slower than SerialX {@link SerializationProtocol} system! + * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. + * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
+ * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
+ * Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! + * + * @since 1.3.5 + */ + public boolean isUseBase64IfCan() + { + return useBase64IfCan; + } + + /** + * @param useBase64IfCan | Set this on true to force program to use {@link Base64} serialization on {@link Serializable} objects. + * Doing this might result into some form of encryption but its less flexible and tends to be slower than SerialX {@link SerializationProtocol} system! + * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. + * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
+ * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
+ * Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! + * + * @since 1.3.5 + */ + public void setUseBase64IfCan(boolean useBase64IfCan) + { + this.useBase64IfCan = useBase64IfCan; + } + + /** + * @param obj | Object to get protocol for! + * @param mode | Protocol mode! + * @param args | Parser args to get protocol from! + * + * @return Protocol obtained from args or from {@link SerializationProtocol#REGISTRY} if there is no protocol or {@link ProtocolRegistry} in args (index 3).
+ * Note: This is mainly used by {@link ObjectConverter}! + * + * @since 1.3.5 + */ + public static SerializationProtocol getProtocolFor(Object obj, byte mode, Object[] args) + { + if (args.length > 3) + { + if (args[3] instanceof ProtocolRegistry) + return ((ProtocolRegistry) args[3]).GetProtocolFor(obj, mode); + else if (args[3] instanceof SerializationProtocol) + return (SerializationProtocol) args[3]; + } + + return SerializationProtocol.REGISTRY.GetProtocolFor(obj, mode); + } + + /** + * @param str | String to check protocol class for! + * + * @return Class of the protocol or null if inserted statement is not protocol expression! + * For example: getProtocolExprClass("java.util.ArrayList 1 2 3 4 5") will return {@link ArrayList} but "Hello world!" will return null! + * + * @since 1.3.0 + */ + public static Class getProtocolExprClass(String str, Object[] compilerArgs) + { + int i = 0, len = str.length(); + for (char ch; i < len; i++) + if ((ch = str.charAt(i)) == ' ' || ch == ':') + break; + + try + { + Class cls = ImportsProvider.forName(compilerArgs.length > 0 ? compilerArgs[0] : null, str.substring(0, i), false, ObjectConverter.class.getClassLoader()); + if (cls != null) + return cls; + for (char ch; i < len; i++) + { + if ((ch = str.charAt(i)) > 32) + if (ch == '{' || ch == '[') + return IsSelectorScope.class; + else + return null; + } + } + catch (ClassNotFoundException e) + {} + return null; + } + + /** + * @param registry | Registry to use! + * @param strs | Source strings to parse using suitable parser from registry. + * @param from | Start index to begin from! + * @param trim | If true, all strings will be trimed before parsing! + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @return Array of parsed objects, each parsed using {@link DataParser#parseObj(String, Object...)} + * + * @since 1.3.0 + */ + public static Object[] parseAll(ParserRegistry registry, String strs[], int from, boolean trim, Object... args) + { + Object[] objs = new Object[strs.length-from]; + for (int i = 0; from < strs.length; from++, i++) + objs[i] = registry.parse(trim ? strs[from].trim() : strs[from], args); + return objs; + } + + /** + * @return Array with 2 preferred sub-scope wrapping chars that are used during serialization by default. { and } + * + * @since 1.3.5 + */ + public static char[] primarySubscopeWrappers() + { + return new char[] {'{', '}'}; + } + + /** + * @return Array with 2 secondary sub-scope wrapping char. [ and ] + * + * @since 1.3.5 + */ + public static char[] secondarySubscopeWrappers() + { + return new char[] {'[', ']'}; + } + + /** + * Used internally by {@link ObjectConverter}!
+ * Dummy class with no purpose except to be mark (.class) for shortened scope expression such as: + * + * shortenedSelectorLikeScope {

+ * //stuff... + * }; + *
+ * + * @author PETO + * + * @since 1.3.0 + */ + protected static class IsSelectorScope {}; +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java new file mode 100644 index 0000000..161f254 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java @@ -0,0 +1,185 @@ +package org.ugp.serialx.converters; + +import static org.ugp.serialx.Serializer.isOneOf; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.Serializer; + +/** + * This parser provides ability to use expression groups that can define order of expression evaluation and compilation! + * Its usage depends on combination with other parsers especially operators! + * Its case sensitive! + *
+ *
+ * For example: (5 + 5) / 2 = 5 which is different than 5 + 5 / 2 = 7 + *
+ * This protocol will insert one additional argument into array of additional parsing args at index 2 that will be of type {@link Map} and it will contains informations about encapsulated groups, do not alter this map in any way unless you know what are you doing! + * + * @author PETO + * + * @since 1.3.0 + */ +public class OperationGroups implements DataParser +{ + /** + * Opening and closing of group mark! + * + * @since 1.3.0 + */ + public static final String GROUP_MARK_OP = new String(new char[] {127, 128, 129}), GROUP_MARK_CLS = new String(new char[] {129, 128, 127}); + + @SuppressWarnings("unchecked") + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + if (str.length() > 1) + { + int opIndex = indexOfOpening(str, 0, '('), clsIndex = -1; + if (opIndex > -1 && (clsIndex = indexOfClosing(str, opIndex, new char[] {'('}, ')')) > -1) + { + Map runtimeGroupStack = new HashMap<>(); + if (args.length > 2 && args[2] instanceof Map) + runtimeGroupStack = (Map) args[2]; + else + { + if (args.length < 3) + args = Arrays.copyOf(args, 3); + args[2] = runtimeGroupStack; + } + String mark = GROUP_MARK_OP + runtimeGroupStack.size() + GROUP_MARK_CLS; + runtimeGroupStack.put(mark, str.substring(opIndex+1, clsIndex)); + + StringBuilder sb = new StringBuilder(str).replace(opIndex, clsIndex+1, mark); + return myHomeRegistry.parse(sb.toString(), args); + } + + if (isGroupMark(str)) + { + if (args.length > 2 && args[2] instanceof Map) + { + Map runtimeGroupStack = (Map) args[2]; + + Object[] newArgs = args.clone(); + newArgs[2] = new HashMap(); + return myHomeRegistry.parse(runtimeGroupStack.get(str), newArgs); + } + LogProvider.instance.logErr("Runtime group stack is trying to be accessed using " + str + " however it was not provided yet!", null); + return null; + } + } + + return CONTINUE; + } + + /** + * @param s | Char sequence to check! + * + * @return Return true if inserted CharSequence match the runtime group mark wrapper! + * This is used for internal purposes of {@link OperationGroups}. + * + * @since 1.3.0 + */ + public static boolean isGroupMark(CharSequence s) + { + String op = GROUP_MARK_OP, cls = GROUP_MARK_CLS; + int lo = op.length(), lc = cls.length(), len = s.length(); + if (len < lo + lc + 1) + return false; + for (int i = 0; i < lo; i++) + if (s.charAt(i) != op.charAt(i)) + return false; + + for (int i = lo, ch; i < len - lc; i++) + if ((ch = s.charAt(i)) < '0' || ch > '9') + return false; + + for (int i = 0; i < lc; i++) + if (s.charAt(len-i-1) != cls.charAt(lc-i-1)) + return false; + return true; + } + + /** + * @param str | CharSequence to search! + * @param from | Beginning index of search! + * @param openings | Openings to find! + * + * @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...)}! + * + * @since 1.3.0 + */ + public static int indexOfOpening(CharSequence str, int from, char... openings) + { + for (int len = str.length(), quote = 0, brackets = 0; from < len; from++) + { + char ch = str.charAt(from); + + if (ch == '\"') + quote++; + else if (quote % 2 == 0) + { + if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing opening bracket in: " + str); + } + else if (brackets == 0 && isOneOf(ch, openings)) + return from; + } + } + return -1; + } + + /** + * @param str | CharSequence to search! + * @param from | Beginning index of search! + * @param openings | Openings to count with! + * @param closing | Closings to find! + * + * @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...)}! + * + * @since 1.3.0 + */ + public static int indexOfClosing(CharSequence str, int from, char[] openings, char... closing) + { + for (int len = str.length(), quote = 0, brackets = 0, ops = 0; from < len; from++) + { + char ch = str.charAt(from); + + if (ch == '\"') + quote++; + else if (quote % 2 == 0) + { + if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing opening bracket in: " + str); + } + else if (brackets == 0) + { + if (isOneOf(ch, openings)) + ops++; + else if (isOneOf(ch, closing)) + { + if (ops == 1) + return from; + ops--; + } + } + } + } + return -1; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/SerializableBase64Converter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/SerializableBase64Converter.java new file mode 100644 index 0000000..b2bb26a --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/SerializableBase64Converter.java @@ -0,0 +1,150 @@ +package org.ugp.serialx.converters; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.Base64; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.protocols.SerializationProtocol; + +/** + * This converter is capable of converting {@link Serializable}. + * Its case sensitive! + *
+ *
+ * Table of sample string <--> object conversions: + + + + + + + + + + + + + + +
StringObject
#rO0ABXNyABNqYXZhLnV0aWwuQXJyYXlMaXN0eIHSHZnHYZ0DAAFJAARzaXpleHAAAAAAdwQAAAAAeA#3D#3Dnew ArrayList()
#rO0ABXVyAAJbSU26YCZ26rKlAgAAeHAAAAADAAAABQAAAAUAAAAFnew int[] {5, 5, 5}
+ * Note: In most of the cases {@link ObjectConverter} and {@link SerializationProtocol} should be used as preferable alternative!
+ * Note: In order to avoid conflicts with JUSS syntax, this converter serializes and deserializes by using {@link Base64} and {@link URLEncoder} with addition of all % are being replaced by #! + * + * @author PETO + * + * @since 1.3.0 + */ +public class SerializableBase64Converter implements DataConverter +{ + /** + * @deprecated DO NOT USE, IT WILL TAKE NOTE EFFECT! USE {@link ObjectConverter#setUseBase64IfCan(boolean)}! + * + * Set this on true to force program to use SerializationProtocol also on java.io.Serializable objects. + * Doing this also might take less memory space then using classic java.io.Serializable. + * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. + * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
+ * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization! + * + * @since 1.0.0 (moved to {@link SerializableBase64Converter} since 1.3.0) + */ + @Deprecated + public static boolean useProtocolIfCan = true; + + @Override + public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) + { + if (arg.length() <= 0) + return CONTINUE; + + char ch0 = arg.charAt(0); + if (ch0 == '#' || ch0 == 'r') + { + try + { + if (ch0 == '#') + return UnserializeClassis(arg = URLDecoder.decode(arg.substring(1).replace('#', '%'), "UTF-8")); + return UnserializeClassis(arg = URLDecoder.decode(arg.replace('#', '%'), "UTF-8")); + } + catch (Exception e) + { + LogProvider.instance.logErr("Looks like there appear some problems with unserializing some object, the instance of java.io.Serializable from string \"" + arg + "\"! This string is most likely corrupted! See error below:", e); + e.printStackTrace(); + return null; + } + } + return CONTINUE; + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) + { + if (arg instanceof Serializable) + try + { + return "#" + URLEncoder.encode(SerializeClassic((Serializable) arg), "UTF-8").replace('%', '#'); + } + catch (Exception e) + { + LogProvider.instance.logErr("Looks like there appear some problems with serializing \"" + arg + "\", the instance of java.io.Serializable. This could happen when certain object contains non-transient unserializable objects. Use custom valid protocol for serializing \"" + arg + "\" might solve the problem!", e); + e.printStackTrace(); + return null; + } + return CONTINUE; + } + + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) + { + return new StringBuilder("Object of ").append(obj.getClass().getName()).append(": \"").append(obj).append("\" serialized using classic Base64 java.io.Serializable!"); + } + + /** + * @param objStr | String to unserialize by classic Java serialization. + * + * @return Unsrialized object. + * + * @throws IOException - if an I/O error occurs while reading stream header. + * @throws ClassNotFoundException - Class of a serialized object cannot be found. + * + * @see java.util.Base64 + * + * @since 1.0.0 (moved to {@link SerializableBase64Converter} since 1.3.0) + */ + public static Object UnserializeClassis(String objStr) throws Exception + { + return new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(objStr))).readObject(); + } + + /** + * @param obj | Object to serialize using classic Java serialization. + * + * @return String with serialized object. + * + * @throws Exception - if an I/O error occurs while writing stream header + * + * @see java.lang.Base64 + * + * @since 1.0.0 (moved to {@link SerializableBase64Converter} since 1.3.0) + */ + public static String SerializeClassic(Serializable obj) throws Exception + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + + oos.writeObject(obj); + oos.close(); + return Base64.getEncoder().encodeToString(baos.toByteArray()); + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java new file mode 100644 index 0000000..206dd48 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java @@ -0,0 +1,101 @@ +package org.ugp.serialx.converters; + +import static org.ugp.serialx.Serializer.contains; +import static org.ugp.serialx.Serializer.indexOfNotInObj; + +import org.ugp.serialx.Registry; + +/** + * This converter is capable of converting {@link String}. + * Its case sensitive! + *
+ *
+ * Table of sample string <--> object conversions: + + + + + + + + + + +
StringObject
"Hello world!"new String("Hello world!")
+ * If you enter string in ${yourString}, "yourString" will be returned by {@link StringConverter#toString(Registry, Object, Object...)} according to {@link StringConverter#CodeInsertion(String)}! + * + * @author PETO + * + * @since 1.3.0 + */ +public class StringConverter implements DataConverter +{ + /** + * Set this on true and {@link String} will be serialized normally, for instance "Hello world!" and not using protocols or java Base64!
+ * Setting this on false will also make Strings unreadable for normal people! + * + * @since 1.2.0 (moved to {@link StringConverter} since 1.3.0) + */ + public static boolean serializeStringNormally = true; + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) + { + if (arg instanceof String) + { + String str = arg.toString(); + if (str.startsWith("${") && str.endsWith("}")) + { + str = str.substring(2, str.length()-1); + if (str.contains("::") && indexOfNotInObj(str, ' ') > -1) + str = "{"+str+"}"; + return str; + } + else if (serializeStringNormally) + { + if (contains(str, '\"', '\n', '\r')) + return CONTINUE; + else + return "\""+str+"\""; + } + } + return CONTINUE; + } + + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + if (str.length() > 1 && str.charAt(0) == '\"' && str.charAt(str.length()-1) == '\"' && indexOfNotInObj(str, ' ') == -1) + return str.substring(1, str.length() - 1); + return CONTINUE; + } + + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) + { + String str = obj.toString(); + boolean hasComment = false; + if (str.startsWith("${") && str.endsWith("}") && !(hasComment = str.substring(2).contains("//"))) + return "Manually inserted code!"; + if (!hasComment) + return new StringBuilder().append("Object of ").append(obj.getClass().getName()).append(": \"").append(obj.toString()).append("\"!"); + return ""; + } + + /** + * @param obj | Object to stringify directly. + * + * @return "${" + obj + "}" - if this is be inserted into {@link StringConverter#toString(Registry, Object, Object...))}, it will be returned without ${ and }! + * + * @since 1.3.5 + */ + public static String DirectCode(Object obj) + { + return "${" + obj + "}"; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java new file mode 100644 index 0000000..6937c7b --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java @@ -0,0 +1,222 @@ +package org.ugp.serialx.converters; + +import static org.ugp.serialx.Serializer.Clone; +import static org.ugp.serialx.Serializer.contains; +import static org.ugp.serialx.Serializer.fastReplace; +import static org.ugp.serialx.Serializer.multilpy; +import static org.ugp.serialx.Serializer.splitValues; + +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Map; +import java.util.Map.Entry; + +import org.ugp.serialx.GenericScope; +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.Scope; +import org.ugp.serialx.Serializer.NULL; + +/** + * This converter is capable of converting {@link Map.Entry} and reading variables from {@link Scope} via "$"! + * {@link VariableConverter#parse(String, Object...)} required one additional Scope argument in args... argument! + * Its case insensitive!
+ * Exact outputs of this converter are based on inserted scope! + * + * @author PETO + * + * @since 1.3.0 + */ +public class VariableConverter implements DataConverter +{ + protected boolean jsonStyle; + + public VariableConverter() + { + this(false); + } + + /** + * @param jsonStyle | If true, this converter will be using Json style of variables ("key" : value)! + * + * @since 1.3.2 + */ + public VariableConverter(boolean jsonStyle) + { + setJsonStyle(jsonStyle); + } + + /** + * Raw example of empty variable entry this converter can convert! + * + * @since 1.3.0 + */ + public static final Entry RAW_VAR_ENTRY = NewVariable("", "null"); + + @SuppressWarnings("unchecked") + @Override + public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) + { + if (args.length > 0 && arg.length() > 0 && args[0] instanceof GenericScope) + { + GenericScope scope = (GenericScope) args[0]; + boolean genericVar = args.length > 4 && args[4] == GenericScope.class; + if (isVarAssignment(arg)) + { + String[] enrty = splitValues(arg, 0, false, new char[] {'?'}, '=', ':'); + + Object obj = null; + String objString = enrty[enrty.length-1]; + + if (enrty.length > 1 && !objString.isEmpty()) + { + obj = NULL.toOopNull(myHomeRegistry.parse(objString, args)); + } + + for (int i = 0; i < enrty.length-1; i++) + { + if (!genericVar && contains(enrty[i] = enrty[i].trim(), ' ')) + LogProvider.instance.logErr("Variable name \"" + enrty[i] + "\" is invalid, blank characters are not allowed!", null); + else + { + if ((enrty[i] = fastReplace(enrty[i], "$", "")).indexOf('.') > -1) + { + String[] tree = splitValues(enrty[i], '.'); + GenericScope sc = (GenericScope) scope.getGenericScope((Object[]) Arrays.copyOfRange(tree, 0, tree.length-1)); + if (sc != null) + { + if (obj == VOID) + sc.variables().remove(enrty[i]); + else + sc.put(genericVar ? myHomeRegistry.parse(tree[tree.length-1], true, null, args) : tree[tree.length-1], obj); + } + else + LogProvider.instance.logErr("Variable \"" + tree[tree.length-2] +"\" was not declared as scope in its scope so variable \"" + tree[tree.length-1] +"\" cant be set to \"" + obj + "\"!", null); + } + else if (obj == VOID) + scope.variables().remove(enrty[i]); + else + scope.put(genericVar ? myHomeRegistry.parse(enrty[i], true, null, args) : enrty[i], obj); + } + } + if (arg.charAt(0) == '$') + return obj; + return VOID; + } + else if (arg.charAt(0) == '$' && !contains(arg, ' ', '+', '-', '*', '/', '%', '>', '<', '=', '&', '|', '^', '?', '=')) + { + Object obj; + if ((arg = fastReplace(arg, "$", "")).indexOf('.') > -1) + { + Object[] tree = splitValues(fastReplace(fastReplace(arg, "::new", ""), "::class", ""), '.'); + GenericScope sc = (GenericScope) scope.getGenericScope(Arrays.copyOfRange(tree, 0, tree.length-1)); + obj = sc == null ? null : sc.variables().get(tree[tree.length-1]); + /*if (sc == null || !sc.containsVariable(tree[tree.length-1])) + LogProvider.instance.logErr("Variable \"" + tree[tree.length-1] + "\" was not declared in \"" + arg.substring(0, arg.length() - tree[tree.length-1].length() - 1) + "\"! Defaulting to null!");*/ + } + else + { + String str = fastReplace(fastReplace(arg, "::new", ""), "::class", ""); + /*if (!scope.containsVariable(str)) + LogProvider.instance.logErr("Variable \"" + str + "\" was not declared! Defaulting to null!");*/ + obj = scope.variables().get(str); + } + + return arg.endsWith("::class") ? obj.getClass() : arg.endsWith("::new") ? Clone(obj) : obj; + } + } + return CONTINUE; + } + + @SuppressWarnings("unchecked") + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (obj instanceof Entry) + { + Entry var = (Entry) obj; + int tabs = 0; + if (args.length > 1 && args[1] instanceof Integer) + tabs = (int) args[1]; + + boolean jsonStyle = isJsonStyle(), genericVar = false; + Object key = (genericVar = !((key = var.getKey()) instanceof String)) ? myHomeRegistry.toString(key, args) : key, val = var.getValue(); + return new StringBuilder().append(jsonStyle && !genericVar ? "\""+key+"\"" : key).append(val instanceof Scope && !((Scope) val).isEmpty() ? (jsonStyle ? " : " : " =\n" + multilpy('\t', tabs)) : (jsonStyle ? " : " : " = ")).append(myHomeRegistry.toString(val, args)); + } + return CONTINUE; + } + + @SuppressWarnings("unchecked") + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object objToDescribe, Object... argsUsedConvert) + { + Entry ent = (Entry) objToDescribe; + return new StringBuilder(myHomeRegistry.getConverterFor(ent.getValue(), argsUsedConvert).getDescription(myHomeRegistry, ent.getValue(), argsUsedConvert)).append(" Stored by \"").append(ent.getKey()).append("\" variable!"); + } + + /** + * @return True if variables will be serialized using json style ("key" : value)! + * + * @since 1.3.2 + */ + public boolean isJsonStyle() + { + return jsonStyle; + } + + /** + * @param jsonStyle | If true, this converter will be using Json style of variables ("key" : value)! + * + * @since 1.3.2 + */ + public void setJsonStyle(boolean jsonStyle) + { + this.jsonStyle = jsonStyle; + } + + /** + * @param s | CharSequence to search! + * + * @return true if inserted expression is variable assignment expression such as variable = 4 otherwise false! + * + * @since 1.3.0 + */ + public static boolean isVarAssignment(CharSequence s) + { + for (int i = 0, brackets = 0, quote = 0, len = s.length(), oldCh = -1, chNext; i < len; i++) + { + char ch = s.charAt(i); + if (ch == '"') + quote++; + + if (quote % 2 == 0) + { + if (ch == '?') + return false; + else if (brackets == 0 && (ch == '=' || ch == ':') && !(oldCh == '=' || oldCh == ':' || oldCh == '!' || oldCh == '>'|| oldCh == '<') && (i >= len-1 || !((chNext = s.charAt(i+1)) == '=' || chNext == ':' || chNext == '!' || chNext == '>'|| chNext == '<'))) + return true; + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + if (brackets > 0) + brackets--; + } + oldCh = ch; + } + return false; + } + + /** + * @param varName | Name of variable. + * @param varValue | Value of variable. + * + * @return New entry with varName as name and varValue as value! + * + * @param | Generic type of variables value. + * + * @since 1.3.5 + */ + public static Entry NewVariable(String varName, T varValue) + { + return new AbstractMap.SimpleImmutableEntry<>(varName, varValue); + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java new file mode 100644 index 0000000..66755ad --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java @@ -0,0 +1,129 @@ +package org.ugp.serialx.converters.imports; + +import org.ugp.serialx.Serializer; +import org.ugp.serialx.converters.imports.ImportConverter.Imports; + +/** + * This class is represents single import. It stores target class of import and its alias!
+ * This imports are stored and managed in {@link Imports} and are used by many parsers and {@link Serializer}! + * + * @author PETO + * + * @since 1.3.0 + * + * @see Import + */ +public class Import implements Cloneable +{ + protected final Class cls; + protected final String alias; + protected final ImportsProvider owner; + + /** + * @param cls | Class to create import for! Alias of this class will be its simple name! + * + * @since 1.3.0 + */ + public Import(Class cls) + { + this(cls, cls.getSimpleName()); + } + + /** + * @param cls | Class to create import for! Alias of this class will be its simple name! + * @param owner | Owner/provider of this Import! + * + * @since 1.3.5 + */ + public Import(Class cls, ImportsProvider owner) + { + this(cls, cls.getSimpleName(), owner); + } + + /** + * @param cls | Class to create import for! + * @param alias | Alias of class! + * + * @since 1.3.5 + */ + public Import(Class cls, String alias) + { + this(cls, alias, null); + } + + + /** + * @param cls | Class to create import for! + * @param alias | Alias of class! + * @param owner | Owner/provider of this Import! + * + * @since 1.3.5 + */ + public Import(Class cls, String alias, ImportsProvider owner) + { + this.cls = cls; + this.alias = alias; + this.owner = owner; + } + + @Override + public String toString() + { + if (getCls().getSimpleName().equals(getClsAlias())) + return "import " + getCls().getName(); + return getCls().getName() + " => " + getClsAlias(); + } + + @Override + public boolean equals(Object obj) + { + if (obj instanceof String) + return getClsAlias().equals(obj); + else if (obj instanceof Class) + return getCls().equals(obj); + else if (obj instanceof Import) + return getClsAlias().equals(((Import) obj).getClsAlias()) && getCls().equals(((Import) obj).getCls()); + return super.equals(obj); + } + + @Override + public Import clone() + { + return new Import(getCls(), getClsAlias(), getOwner()); + } + + public Import clone(ImportsProvider newOwner) + { + return new Import(getCls(), getClsAlias(), newOwner); + } + + /** + * @return Class of this import! + * + * @since 1.3.0 + */ + public Class getCls() + { + return cls; + } + + /** + * @return Alias for class! + * + * @since 1.3.0 + */ + public String getClsAlias() + { + return alias; + } + + /** + * @return Owner/provider of this import! + * + * @since 1.3.5 + */ + public ImportsProvider getOwner() + { + return owner; + } +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportConverter.java new file mode 100644 index 0000000..92f8524 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportConverter.java @@ -0,0 +1,267 @@ +package org.ugp.serialx.converters.imports; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.Scope; +import org.ugp.serialx.Serializer; +import org.ugp.serialx.converters.DataConverter; +import org.ugp.serialx.converters.DataParser; + +/** + * This parser maintains list of {@link Imports#IMPORTS} represented as {@link Import}s. Where are registered imports imported by user as well as temporary imports that are parsed! Result of parsing will be always added to imports list and {@link DataParser#VOID} will be returned! + * Parsing example: import java.util.ArrayList will add temporary {@link Import} of java.util.ArrayList or java.lang.String => Word will import java.lang.String as Word! + * Imports will be converted to string just by calling toString!
+ *
+ * This parser requires additional parser arg at index 0 of type {@link ImportsProvider} that will obtain managed imports! This arg is required during both parsing and converting! + * + * @author PETO + * + * @since 1.3.0 + */ +public class ImportConverter implements DataConverter +{ + /** + * List of global shared common registered imports! + * + * @since 1.3.0 + */ + public static final Imports IMPORTS = new Imports(new Import(Serializer.class), new Import(Scope.class), new Import(ArrayList.class), new Import(Math.class), new Import(Double.class), new Import(Integer.class), new Import(Double.class, "double"), new Import(Integer.class, "int"), new Import(String.class), new Import(System.class)); + + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + if (args.length > 0 && args[0] instanceof ImportsProvider) + { + Imports imports = ((ImportsProvider) args[0]).getImports(); + int index; + if (str.startsWith("import ")) + { + try + { + if ((str = str.substring(7).trim()).indexOf("=>") > -1) + return parse(myHomeRegistry, str, args); + imports.add(new Import(imports.forName(str), (ImportsProvider) args[0])); + } + catch (ClassNotFoundException e) + { + LogProvider.instance.logErr("Unable to import " + str + " because there is no such a class!", e); + } + return VOID; + } + else if ((index = (str = str.trim()).indexOf("=>")) > -1) + { + try + { + imports.add(new Import(imports.forName(str.substring(0, index).trim()), str.substring(index+2).trim(), (ImportsProvider) args[0])); + } + catch (ClassNotFoundException e) + { + LogProvider.instance.logErr("Unable to import " + str.substring(0, index).trim() + " because there is no such a class!", e); + } + return VOID; + } + } + return CONTINUE; + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (args.length > 0 && args[0] instanceof ImportsProvider && obj instanceof Import) + { + return obj.toString(); + } + return CONTINUE; + } + + @Override + public String getDescription(ParserRegistry myHomeRegistry, Object objToDescribe, Object... argsUsedConvert) + { + return "Import of " + ((Import) objToDescribe).getCls() + " as " + ((Import) objToDescribe).getClsAlias(); + } + + /** + * Collection used to store and operate with {@link Import}! + * + * @author PETO + * + * @since 1.3.5 + * + * @see ImportsProvider + */ + public static class Imports extends ArrayList implements Cloneable, ImportsProvider + { + private static final long serialVersionUID = 8487976264622823940L; + + /** + * Constructs an {@link Imports} with the specified initial capacity. + * + * @param initialSize | Initial capacity. + * + * @since 1.3.5 + */ + public Imports(int initialSize) + { + super(initialSize); + } + + /** + * Constructs an {@link Imports} with inserted imports c. + * + * @param c | Initial content of registry. + * + * @since 1.3.5 + */ + public Imports(Collection c) + { + super(c); + } + + /** + * Constructs an {@link Imports} with inserted imports. + * + * @param parsers | Initial content of registry. + * + * @since 1.3.5 + */ + public Imports(Import... imports) + { + addAll(imports); + } + + @Override + public Imports clone() + { + return new Imports(this); + } + + @Override + public Imports getImports() + { + return this; + } + + /** + * @param imports | Imports to add. + * + * @return {@link ArrayList#addAll(Collection)}; + * + * @since 1.3.5 + */ + public boolean addAll(Import... imports) + { + return super.addAll(Arrays.asList(imports)); + } + + /** + * @param aliasOrName | Alias of class or its full name! + * + * @return Class with inserted alias picked from {@link Imports#IMPORTS} similar to {@link Imports#getClassFor(String)} but this will also search via {@link Class#forName(String, boolean, ClassLoader)} if there is no import with required alias! + * + * @throws ClassNotFoundException when {@link Class#forName(String, boolean, ClassLoader)} throws! + * + * @since 1.3.5 + */ + public Class forName(String aliasOrName) throws ClassNotFoundException + { + return forName(aliasOrName, true, Imports.class.getClassLoader()); + } + + /** + * @param aliasOrName | Alias of class or its full name! + * @param initialize | If true the class will be initialized. See Section 12.4 of The Java Language Specification. + * @param loader | Class loader from which the class must be loaded. + * + * @return Class with inserted alias picked from {@link Imports#IMPORTS} similar to {@link Imports#getClassFor(String)} but this will also search via {@link Class#forName(String, boolean, ClassLoader)} if there is no import with required alias! + * If there are no dots in required alias and alias is not imported then null will be returned! + * + * @throws ClassNotFoundException when {@link Class#forName(String, boolean, ClassLoader)} throws! + * + * @since 1.3.5 + */ + public Class forName(String aliasOrName, boolean initialize, ClassLoader loader) throws ClassNotFoundException + { + Class cls = getClassFor(aliasOrName); + if (cls != null) + return cls; + if (aliasOrName.indexOf('.') > 0) + return Class.forName(aliasOrName, initialize, loader); + /*try + { + return Class.forName("java.lang."+aliasOrName, initialize, loader); + } + catch (Exception e) + { + return null; + }*/ + return null; + } + + /** + * @param cls | Class to get alias for! + * + * @return Alias of class picked from {@link Imports#IMPORTS} or name of class if there is no import for this class! + * + * @since 1.3.5 + */ + public String getAliasFor(Class cls) + { + for (int i = size() - 1; i >= 0; i--) + { + Import imp = get(i); + if (imp.equals(cls)) + return imp.getClsAlias(); + } + return cls.getName(); + } + + /** + * @param alias | Alias of class to obtain! + * + * @return Class with inserted alias picked from {@link Imports#IMPORTS} or null if there is no import with required alias! + * + * @since 1.3.5 + */ + public Class getClassFor(String alias) + { + for (int i = size() - 1; i >= 0; i--) + { + Import imp = get(i); + if (imp.equals(alias)) + return imp.getCls(); + } + return null; + } + + /** + * @param owner | Owner of imports to get! + * + * @return Imports of provided owner stored by this list! + * + * @since 1.3.5 + */ + public Imports importsOf(ImportsProvider owner) + { + Imports imports = new Imports(); + for (Import imp : imports) + if (imp.getOwner() == owner) + imports.add(imp); + return imports; + } + + /** + * @param owner | Owner of imports to remove from this list! + * + * @since 1.3.5 + */ + public void removeImportsOf(ImportsProvider owner) + { + for (int i = size() - 1; i >= 0; i--) + if (get(i).getOwner() == owner) + remove(i); + } + } +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java new file mode 100644 index 0000000..5afa8a4 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java @@ -0,0 +1,130 @@ +package org.ugp.serialx.converters.imports; + +import java.util.Collection; + +import org.ugp.serialx.converters.imports.ImportConverter.Imports; + +/** + * This interface is supposed to be implemented by class that can provide array of imports! + * + * @author PETO + * + * @since 1.3.5 + */ +public interface ImportsProvider +{ + /** + * @return Array of provided imports! + * + * @since 1.3.5 + */ + public Imports getImports(); + + /** + * @param obj | Object to get imports from (its supposed to be instance of {@link ImportsProvider} or collection of {@link Import})! + * + * @return Imports of object or null if object can't provide any! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public static Imports importsOf(Object obj) + { + if (obj == null) + return null; + + if (obj instanceof ImportsProvider) + return ((ImportsProvider) obj).getImports(); + + try + { + return new Imports((Collection) obj); + } + catch (Exception e) + { + return null; + } + } + + /** + * @param importProvider | Object to get imports from! + * @param aliasOrName | Alias of class or its full name! + * + * @return Class with inserted alias picked from {@link Imports#IMPORTS} similar to {@link Imports#getClassFor(String)} but this will also search via {@link Class#forName(String, boolean, ClassLoader)} if there is no import with required alias! + * + * @throws ClassNotFoundException when {@link Class#forName(String, boolean, ClassLoader)} throws! + * + * @since 1.3.5 + * + * @see ImportsProvider#importsOf(Object) + */ + public static Class forName(Object importProvider, String aliasOrName) throws ClassNotFoundException + { + return forName(importProvider, aliasOrName, true, Imports.class.getClassLoader()); + } + + /** + * @param importProvider | Object to get imports from! + * @param aliasOrName | Alias of class or its full name! + * @param initialize | If true the class will be initialized. See Section 12.4 of The Java Language Specification. + * @param loader | Class loader from which the class must be loaded. + * + * @return Class with inserted alias picked from {@link Imports#IMPORTS} similar to {@link Imports#getClassFor(String)} but this will also search via {@link Class#forName(String, boolean, ClassLoader)} if there is no import with required alias! + * If there are no dots in required alias and alias is not imported then null will be returned! + * + * @throws ClassNotFoundException when {@link Class#forName(String, boolean, ClassLoader)} throws! + * + * @since 1.3.5 + * + * @see ImportsProvider#importsOf(Object) + */ + public static Class forName(Object importProvider, String aliasOrName, boolean initialize, ClassLoader loader) throws ClassNotFoundException + { + Class cls = getClassFor(importProvider, aliasOrName); + if (cls != null) + return cls; + if (aliasOrName.indexOf('.') > 0) + return Class.forName(aliasOrName, initialize, loader); + /*try + { + return Class.forName("java.lang."+aliasOrName, initialize, loader); + } + catch (Exception e) + { + return null; + }*/ + return null; + } + + /** + * @param importProvider | Object to get imports from! + * @param cls | Class to get alias for! + * + * @return Alias of class picked from {@link Imports#IMPORTS} or name of class if there is no import for this class! + * + * @since 1.3.5 + * + * @see ImportsProvider#importsOf(Object) + */ + public static String getAliasFor(Object importProvider, Class cls) + { + Imports imports = importsOf(importProvider); + return imports != null ? imports.getAliasFor(cls) : cls.getName(); + } + + /** + * @param importProvider | Object to get imports from! + * @param alias | Alias of class to obtain! + * + * @return Class with inserted alias picked from {@link Imports#IMPORTS} or null if there is no import with required alias! + * + * @since 1.3.5 + * + * @see ImportsProvider#importsOf(Object) + */ + public static Class getClassFor(Object importProvider, String alias) + { + Imports imports = importsOf(importProvider); + return imports != null ? imports.getClassFor(alias) : null; + } +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java new file mode 100644 index 0000000..f1d1466 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -0,0 +1,495 @@ +package org.ugp.serialx.converters.operators; + +import static org.ugp.serialx.Serializer.fastReplace; +import static org.ugp.serialx.Serializer.isOneOf; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.Scope; +import org.ugp.serialx.Serializer; +import org.ugp.serialx.converters.ArrayConverter; +import org.ugp.serialx.converters.DataParser; + +/** + * This parser provides arithmetics operators to evaluate mathematical expressions such as 5 * 2 +-- 2 / 2 ** 2 % 4 = 10! + * + * @author PETO + * + * @since 1.3.0 + */ +public class ArithmeticOperators implements DataParser +{ + protected String[] priority1Oprs = {"*", "*-", "/", "/-", "%"}, priority2Oprs = {"**", "**-"}; + + @Override + public Object parse(ParserRegistry myHomeRegistry, String s, Object... args) + { + if (s.length() > 2 && isExpression(s, '+', '-', '*', '/', '%')) + return eval(myHomeRegistry, s, args); + return CONTINUE; + } + + /** + * @return Result of evaluated expression that was inserted! For instance 5 + 5, result 10! + * + * @since 1.3.0 + */ + protected Object eval(ParserRegistry registryForParsers, String expr, Object... argsForParsers) + { + while (expr.contains("++") || expr.contains("--") || expr.contains("+-") || expr.contains("-+")) + expr = fastReplace(fastReplace(fastReplace(fastReplace(expr, "-+", "-"), "+-", "-"), "--", "+"), "++", "+"); + + List[] terms = getTerms(expr, '+', '-', '*', '/', '%'); + List cofs = terms[0]; + if (cofs.size() <= 1) + return CONTINUE; + List oprs = terms[1]; + + Object cof1 = null, cof2 = null; + String opr = null; + try + { + for (int i = 0, index = -1, orderIndex = 0, size = oprs.size(); i < size; index = -1, i++) + { + for (String adept : priority1Oprs) + if ((orderIndex = oprs.indexOf(adept)) > -1 && (index == -1 || orderIndex < index)) + index = orderIndex; + for (String adept : priority2Oprs) + if ((orderIndex = oprs.indexOf(adept)) > -1) + index = orderIndex; + + cof1 = cofs.get(index = index < 0 ? 0 : index); + if (cof1 instanceof String) + cof1 = registryForParsers.parse(cof1.toString().trim(), i > 0, new Class[] {getClass(), ArrayConverter.class}, argsForParsers); + cof1 = cof1 instanceof ResultWrapper ? ((ResultWrapper) cof1).obj : cof1; + + cof2 = cofs.remove(index + 1); + if (cof2 instanceof String) + cof2 = registryForParsers.parse(cof2.toString().trim(), i > 0, new Class[] {getClass()}, argsForParsers); + cof2 = cof2 instanceof ResultWrapper ? ((ResultWrapper) cof2).obj : cof2; + + opr = oprs.remove(index).toString(); + if (opr.charAt(0) == '+') + cofs.set(index, new ResultWrapper(addOperator(cof1, cof2))); + else if (opr.charAt(0) == '-') + cofs.set(index, new ResultWrapper(subOperator(cof1, cof2))); + else if (opr.startsWith("**")) + cofs.set(index, new ResultWrapper(powOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1))); + else if (opr.charAt(0) == '*') + cofs.set(index, new ResultWrapper(multOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1))); + else if (opr.charAt(0) == '/') + cofs.set(index, new ResultWrapper(divOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1))); + else if (opr.charAt(0) == '%') + cofs.set(index, new ResultWrapper(modOperator(cof1, cof2))); + } + } + catch (ClassCastException ex) + { + LogProvider.instance.logErr("Arithmetic operator " + opr + " is undefined between " + cof1.getClass().getName() + " and " + cof2.getClass().getName() + "!", ex); + } + catch (IndexOutOfBoundsException ex) + { + LogProvider.instance.logErr("Missing coefficient in \"" + expr + "\"!", ex); + } + catch (ArithmeticException ex) + { + LogProvider.instance.logErr(ex.getMessage(), ex); + } + + return (cof1 = cofs.get(0)) instanceof ResultWrapper ? ((ResultWrapper) cof1).obj : cof1; + } + + /** + * @return Addition of cof and cof2 (cof + cof2) supposed to be returned! + * + * @since 1.3.2 + */ + public Object addOperator(Object cof, Object cof2) + { + return add(toNum(cof), cof instanceof String ? cof2 : toNum(cof2)); + } + + /** + * @return Subtraction of cof and cof2 (cof - cof2) supposed to be returned! + * + * @since 1.3.2 + */ + public Object subOperator(Object cof, Object cof2) + { + return sub(toNum(cof), toNum(cof2)); + } + + /** + * @return Multiplication of cof and cof2 multiplied by sign (cof * cof2 * sign) supposed to be returned! + * + * @since 1.3.2 + */ + public Object multOperator(Object cof, Object cof2, int sign) + { + return mult(toNum(cof), toNum(cof2), sign); + } + + /** + * @return Division of cof and cof2 multiplied by sign (cof / cof2 * sign) supposed to be returned! + * + * @since 1.3.2 + */ + public Object divOperator(Object cof, Object cof2, int sign) + { + return div(toNum(cof), toNum(cof2), sign); + } + + /** + * @return Modulation of cod and cof2 (cof % cof2) supposed to be returned! + * + * @since 1.3.2 + */ + public Object modOperator(Object cof, Object cof2) + { + return mod(toNum(cof), toNum(cof2)); + } + + /** + * @return Cof powered by cof2 multiplied by sign (Math.pow(cof, cof2 * sign)) supposed to be returned! + * + * @since 1.3.2 + */ + public Object powOperator(Object cof, Object cof2, int sign) + { + return pow(toNum(cof), toNum(cof2), sign); + } + + /** + * @return Addition of cof and cof2 (cof + cof2)! + * + * @since 1.3.0 + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Object add(Object cof, Object cof2) + { + if (cof instanceof Number && cof2 instanceof Number) + { + if (cof instanceof Double || cof2 instanceof Double) + return ((Number) cof).doubleValue() + ((Number) cof2).doubleValue(); + if (cof instanceof Float || cof2 instanceof Float) + return ((Number) cof).floatValue() + ((Number) cof2).floatValue(); + if (cof instanceof Integer || cof2 instanceof Integer) + return ((Number) cof).intValue() + ((Number) cof2).intValue(); + if (cof instanceof Long || cof2 instanceof Long) + return ((Number) cof).longValue() + ((Number) cof2).longValue(); + + return ((Number) cof).doubleValue() + ((Number) cof2).doubleValue(); + } + + if (cof.getClass().isArray()) + return ArrayConverter.mergeArrays(cof, cof2); + + if (cof instanceof Collection) + { + if (cof2 instanceof Collection) + ((Collection) cof).addAll(((Collection) cof2)); + else if (cof2.getClass().isArray()) + ((Collection) cof).addAll(Arrays.asList(ArrayConverter.fromAmbiguous(cof2))); + else + ((Collection) cof).add(cof2); + return cof; + } + + if (cof instanceof Scope) + { + if (cof2 instanceof Scope) + ((Scope) cof).addAll(((Scope) cof2)); + else if (cof2 instanceof Collection) + ((Scope) cof).addAll((Collection) cof2); + else if (cof2.getClass().isArray()) + ((Scope) cof).addAll(ArrayConverter.fromAmbiguous(cof2)); + else + ((Scope) cof).add(cof2); + return cof; + } + return String.valueOf(cof) + String.valueOf(cof2); + } + + /** + * @return Subtraction of cof and cof2 (cof - cof2)! + * + * @since 1.3.0 + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Object sub(Object cof, Object cof2) + { + if (cof instanceof Number && cof2 instanceof Number) + { + if (cof instanceof Double || cof2 instanceof Double) + return ((Number) cof).doubleValue() - ((Number) cof2).doubleValue(); + if (cof instanceof Float || cof2 instanceof Float) + return ((Number) cof).floatValue() - ((Number) cof2).floatValue(); + if (cof instanceof Integer || cof2 instanceof Integer) + return ((Number) cof).intValue() - ((Number) cof2).intValue(); + if (cof instanceof Long || cof2 instanceof Long) + return ((Number) cof).longValue() - ((Number) cof2).longValue(); + + return ((Number) cof).doubleValue() - ((Number) cof2).doubleValue(); + } + + if (cof instanceof Collection) + { + if (cof2 instanceof Collection) + ((Collection) cof).removeAll(((Collection) cof2)); + else if (cof2.getClass().isArray()) + ((Collection) cof).removeAll(Arrays.asList(ArrayConverter.fromAmbiguous(cof2))); + else + ((Collection) cof).remove(cof2); + return cof; + } + + return null; + } + + /** + * @return Multiplication of cof and cof2 multiplied by sign (cof * cof2 * sign)! + * + * @since 1.3.0 + */ + public static Object mult(Object cof, Object cof2, int sign) + { + if (cof2 instanceof Number) + { + if (!(cof instanceof Number)) + return Serializer.multilpy(cof.toString(), ((Number) cof2).intValue() * sign).toString(); + + if (cof instanceof Double || cof2 instanceof Double) + return ((Number) cof).doubleValue() * ((Number) cof2).doubleValue() * sign; + if (cof instanceof Float || cof2 instanceof Float) + return ((Number) cof).floatValue() * ((Number) cof2).floatValue() * sign; + if (cof instanceof Integer || cof2 instanceof Integer) + return ((Number) cof).intValue() * ((Number) cof2).intValue() * sign; + if (cof instanceof Long || cof2 instanceof Long) + return ((Number) cof).longValue() * ((Number) cof2).longValue() * sign; + + return ((Number) cof).doubleValue() * ((Number) cof2).doubleValue() * sign; + } + + return Serializer.multilpy(cof2.toString(), ((Number) cof).intValue() * sign).toString(); + } + + /** + * @return Division of cof and cof2 multiplied by sign (cof / cof2 * sign)! + * + * @since 1.3.0 + */ + public static Object div(Object cof, Object cof2, int sign) + { + if (cof instanceof Double || cof2 instanceof Double) + return ((Number) cof).doubleValue() / ((Number) cof2).doubleValue() * sign; + if (cof instanceof Float || cof2 instanceof Float) + return ((Number) cof).floatValue() / ((Number) cof2).floatValue() * sign; + if (cof instanceof Integer || cof2 instanceof Integer) + return ((Number) cof).intValue() / ((Number) cof2).intValue() * sign; + if (cof instanceof Long || cof2 instanceof Long) + return ((Number) cof).longValue() / ((Number) cof2).longValue() * sign; + + return ((Number) cof).doubleValue() / ((Number) cof2).doubleValue() * sign; + } + + /** + * @return Modulation of cod and cof2 (cof % cof2)! + * + * @since 1.3.0 + */ + public static Object mod(Object cof, Object cof2) + { + if (cof instanceof Double || cof2 instanceof Double) + return ((Number) cof).doubleValue() % ((Number) cof2).doubleValue(); + if (cof instanceof Float || cof2 instanceof Float) + return ((Number) cof).floatValue() % ((Number) cof2).floatValue(); + if (cof instanceof Integer || cof2 instanceof Integer) + return ((Number) cof).intValue() % ((Number) cof2).intValue(); + if (cof instanceof Long || cof2 instanceof Long) + return ((Number) cof).longValue() % ((Number) cof2).longValue(); + + return ((Number) cof).doubleValue() % ((Number) cof2).doubleValue(); + } + + /** + * @return Cof powered by cof2 multiplied by sign (Math.pow(cof, cof2 * sign))! + * + * @since 1.3.0 + */ + public static Object pow(Object cof, Object cof2, int sign) + { + if (cof instanceof Number && cof2 instanceof Number) + { + double pow = Math.pow(((Number) cof).doubleValue(), ((Number) cof2).doubleValue() * sign); + if (pow > Long.MAX_VALUE || pow < Long.MIN_VALUE || cof instanceof Double || cof2 instanceof Double) + return pow; + else if (pow <= Float.MAX_VALUE && pow >= Float.MIN_VALUE && (cof instanceof Float || cof2 instanceof Float)) + return (float) pow; + + if (pow > Integer.MAX_VALUE || pow < Integer.MIN_VALUE || cof instanceof Long || cof2 instanceof Long) + return (long) pow; + else if (cof instanceof Integer || cof2 instanceof Integer) + return (int) pow; + } + return null; + } + + /** + * + * @param str | String to split! + * @param operatos | If true, list of spited operators will be returned otherwise terms split after each operator. + * @param oprs | Operators to use as a splitters. + * + * @return List of terms splitted according to inserted arguments! For example getTerm("5 + 6", true, '+') will return [+], while getTerm("5 + 6", false, '+') will return [5, 6]! + * + * @since 1.3.0 + */ + @SuppressWarnings("unchecked") + public static List[] getTerms(String str, char... oprs) + { + List[] ret = new ArrayList[] {new ArrayList<>(), new ArrayList<>()}; //cofs, ops + + StringBuilder[] sbs = {new StringBuilder(), new StringBuilder()}; //cofs, ops + + int i = 0, type = 0, len = str.length(); + for (; i < len; i++) //in case of start cof sign + { + char ch = str.charAt(i); + if (isOneOf(ch, oprs)) + sbs[0].append(ch); + else + break; + } + + for (int quote = 0, brackets = 0, lastType = type; i < len; i++) + { + char ch = str.charAt(i); + if (ch == '\"') + quote++; + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + brackets--; + + if (type == 1 || quote % 2 == 0 && brackets == 0) + { + if ((type = isOneOf(ch, oprs) ? 1 : 0) != lastType) + { + String s = sbs[lastType].toString().trim(); + if (!s.isEmpty()) + ret[lastType].add(s); + sbs[lastType] = new StringBuilder(); + } + else + type = lastType; + } + + sbs[lastType = type].append(ch); + } + + if (sbs[type].length() > 0) + { + String s = sbs[type].toString().trim(); + if (!s.isEmpty()) + ret[type].add(s); + } + return ret; + } + + /** + * @param str | String that might be an expression! + * @param operators | Operators that str must have! + * + * @return True if inserted string is expression with any coefficients splitted by operators! + * + * @since 1.3.2 + */ + public static boolean isExpression(CharSequence str, char... operators) + { + int hasOpr = -1; + for (int i = 0, len = str.length(), oldCh = 0, isCof = 0, quote = 0, brackets = 0; i < len; i++) + { + char ch = str.charAt(i); + if (ch > 32) + { + if (ch == '\"') + quote++; + else if (quote % 2 == 0) + { + if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + brackets--; + else if (brackets == 0) + { + if (Serializer.isOneOf(ch, operators)) + hasOpr = isCof = 0; + else if (oldCh <= 32 && isCof == 1) + return false; + else + isCof = 1; + } + } + } + oldCh = ch; + } + return hasOpr == 0; + } + + /** + * @return null -> 0, bool ? 1 : 0 + * + * @since 1.3.0 + */ + public static Object toNum(Object obj) + { + if (obj == null) + return 0; + else if (obj instanceof Boolean) + return (boolean) obj ? 1 : 0; + else if (obj instanceof Character) + return (int) (char) obj; + return obj; + } + + /** + * DEPRECATED: Use {@link String#valueOf(Object)} instead, this function is duplicate functionality rendering it unnecessary. + * + * @return "null" if null and else obj.toString(); + * + * @since 1.3.0 + */ + @Deprecated + public static String toString(Object obj) + { + return obj == null ? "null" : obj.toString(); + } + + /** + * Used internally by {@link ArithmeticOperators} to wrap result of evaluation! + * Mainly used by String results! + * + * @author PETO + * + * @since 1.3.0 + */ + protected static class ResultWrapper + { + public final Object obj; + + public ResultWrapper(Object obj) + { + this.obj = obj; + } + + @Override + public String toString() + { + return obj.toString(); + } + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java new file mode 100644 index 0000000..44b593d --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java @@ -0,0 +1,184 @@ +package org.ugp.serialx.converters.operators; + +import static org.ugp.serialx.Serializer.indexOfNotInObj; + +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.Scope; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.converters.imports.ImportsProvider; + +/** + * This parser provides comparison operators to compare 2 objects! For example 6 > 5 or 5 == 5 returns true! + * + * @author PETO + * + * @since 1.3.0 + */ +public class ComparisonOperators implements DataParser +{ + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + int index = -1; + if (str.length() > 2 && (indexOfNotInObj(str, '>', '<', '!', '=') > -1 || (index = indexOfNotInObj(str, " instanceof ")) > -1)) + { + if (index > -1) + { + try + { + return ImportsProvider.forName(args.length > 0 ? args[0] : null, str.substring(index+12).trim()).isInstance(myHomeRegistry.parse(str.substring(0, index).trim(), args)); + } + catch (Exception e) + { + LogProvider.instance.logErr("Unable to check if object " + str.substring(0, index).trim() + " is instance of class \"" + str.substring(index+12).trim() + "\" because there is no such a class!", e); + return null; + } + } + else if ((index = str.indexOf("!=")) > -1) + { + boolean isTripple = str.charAt(index+2) == '='; + return !equalsOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (isTripple ? 3 : 2)).trim(), args), isTripple); + } + else if ((index = str.indexOf("==")) > -1) + { + boolean isTripple = str.charAt(index+2) == '='; + return equalsOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (isTripple ? 3 : 2)).trim(), args), isTripple); + } + else if ((index = str.indexOf('<')) > -1) + { + boolean orEqual = str.charAt(index+1) == '='; + return comparisonOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (orEqual ? 2 : 1)).trim(), args), false, orEqual); + } + else if ((index = str.indexOf('>')) > -1) + { + boolean orEqual = str.charAt(index+1) == '='; + return comparisonOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (orEqual ? 2 : 1)).trim(), args), true, orEqual); + } + //System.out.println(str); + } + //double t = System.nanoTime(); + //System.out.println((t-t0)/1000000); + return CONTINUE; + } + + /** + * @param obj1 | Object 1! + * @param obj2 | Object 2! + * @param compareInstances | If true, this method will compare objects using == operator! + * + * @return True supposed to be returned if obj1 equals to obj2 otherwise false similar to {@link Objects#deepEquals(Object)} but this one can handle OOP crosstype number compression such as {@link Integer} and {@link Double}! + * + * @since 1.3.2 + */ + public boolean equalsOperator(Object obj1, Object obj2, boolean compareInstances) + { + return equals(obj1, obj2, compareInstances); + } + + /** + * @param obj1 | Object 1! + * @param obj2 | Object 2 to be compared with Object 1! + * @param isGreater | If true, Object 1 must be greater than Object 2 in order for true to be returned! + * @param orEqual | If true, Object 1 being numerically equal to Object 2 will result in true to be returned! + * + * @return True supposed to be returned according to arguments! + * + * @since 1.3.2 + */ + @SuppressWarnings("unchecked") + public Object comparisonOperator(Object obj1, Object obj2, boolean isGreater, boolean orEqual) + { + try + { + return numberComparator(((Number) (obj1 = toCompareFriendly(obj1))).doubleValue(), ((Number) (obj2 = toCompareFriendly(obj2))).doubleValue(), isGreater, orEqual); + } + catch (ClassCastException ex) + { + if (obj1 instanceof Comparable) + return numberComparator(((Comparable) obj1).compareTo(obj2), 0, isGreater, orEqual); + + LogProvider.instance.logErr("Comparison operator is undefined between " + obj1.getClass().getName() + " and " + obj2.getClass().getName() + "!", ex); + return null; + } + } + + /** + * @return {@link Map} -> {@link Map#size()}, {@link Collection} -> {@link Collection#size()}, {@link CharSequence} -> {@link CharSequence#length()}, array -> array.length otherwise {@link ArithmeticOperators#toNum(Object)} + * + * @since 1.3.0 + */ + public static Object toCompareFriendly(Object obj) + { + if (obj instanceof Map) + return ((Map) obj).size(); + else if (obj instanceof Collection) + return ((Collection) obj).size(); + else if (obj instanceof Scope) + return ((Scope) obj).valuesCount() + ((Scope) obj).variablesCount(); + else if (obj instanceof CharSequence) + return ((CharSequence) obj).length(); + else if ((obj = ArithmeticOperators.toNum(obj)).getClass().isArray()) + return Array.getLength(obj); + return obj; + } + + /** + * @param d1 | Number 1! + * @param d2 | Number 2 to be compared with number 1! + * @param isGreater | If true, number 1 must be greater than number 2 in order for true to be returned! + * @param orEqual | If true, number 1 being equal to number 2 will result in true to be returned! + * + * @return True according to arguments! + * + * @since 1.3.2 + */ + public static boolean numberComparator(double d1, double d2, boolean isGreater, boolean orEqual) + { + return isGreater ? (orEqual ? d1 >= d2 : d1 > d2) : (orEqual ? d1 <= d2 : d1 < d2); + } + + /** + * @param obj1 | Object 1! + * @param obj2 | Object 2! + * + * @return True if obj1 equals to obj2 otherwise false similar to {@link Objects#deepEquals(Object)} but this one can handle OOP crosstype number compression such as {@link Integer} and {@link Double}! + * + * @since 1.3.0 + */ + public static boolean equals(Object obj1, Object obj2) + { + return equals(obj1, obj2, false); + } + + /** + * @param obj1 | Object 1! + * @param obj2 | Object 2! + * @param compareInstances | If true, this method will compare objects using == operator! + * + * @return True if obj1 equals to obj2 otherwise false similar to {@link Objects#deepEquals(Object)} but this one can handle OOP crosstype number compression such as {@link Integer} and {@link Double}! + * + * @since 1.3.2 + */ + public static boolean equals(Object obj1, Object obj2, boolean compareInstances) + { + return compareInstances ? obj1 == obj2 || obj1 != null && obj2 != null && obj1.getClass() == obj2.getClass() && numericallyEquals(obj1, obj2) : Objects.deepEquals(obj1, obj2) || numericallyEquals(obj1, obj2); + } + + /** + * @param obj1 | Object 1! + * @param obj2 | Object 2! + * + * @return True if obj1 numerically equals to obj2! For instance true == 1, null == 0! + * + * @since 1.3.2 + */ + public static boolean numericallyEquals(Object obj1, Object obj2) + { + return (obj1 = ArithmeticOperators.toNum(obj1)) instanceof Number && (obj2 = ArithmeticOperators.toNum(obj2)) instanceof Number && ((Number) obj1).doubleValue() == ((Number) obj2).doubleValue(); + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java new file mode 100644 index 0000000..ffeee37 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java @@ -0,0 +1,123 @@ +package org.ugp.serialx.converters.operators; + +import static org.ugp.serialx.Serializer.indexOfNotInObj; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.Serializer.NULL; +import org.ugp.serialx.converters.DataParser; + +/** + * This parser provides conditional assignment operators more specially ternary and null coalescing! For example true ? "Yes" : "No" will return "Yes" and null ?? "Hello!" will return hello! + * + * @author PETO + * + * @since 1.3.0 + */ +public class ConditionalAssignmentOperators implements DataParser +{ + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + if (str.length() > 2 && indexOfNotInObj(str, '?') > -1) + { + int index = indexOfOne(str, 0, '?'); + if (index > -1) + { + try + { + String last = str.substring(index+1), first = str.substring(0, index); + boolean condition = (boolean) LogicalOperators.toBool(myHomeRegistry.parse(first.trim(), args)); + if ((index = indexOfTernaryElse(last, 1, '?', ':')) > -1) + { + first = last.substring(0, index); + return condition ? myHomeRegistry.parse(first.trim(), args) : (last = last.substring(index+1).trim()).isEmpty() ? VOID : myHomeRegistry.parse(last, args); + } + else + return condition ? myHomeRegistry.parse(last.trim(), args) : VOID; + } + catch (ClassCastException ex) + { + LogProvider.instance.logErr(str.substring(0, index).trim() + " is invalid condition for ternary operator! Condition must be boolean, try to insert \"!= null\" check!", ex); + return null; + } + } + + if ((index = str.indexOf("??")) > -1) + { + Object obj = myHomeRegistry.parse(str.substring(0, index).trim(), args); + if (obj != null && !(obj instanceof NULL)) + return obj; + + String next = str.substring(index+2); + if ((next = next.trim()).isEmpty()) + return null; + return myHomeRegistry.parse(next, args); + } + } + return CONTINUE; + } + + /** + * @param str + * @param defaultCountOfConfitions + * @param tenraryTokens + * + * @return + * + * @since 1.3.5 + */ + public static int indexOfTernaryElse(CharSequence str, int defaultCountOfConfitions, char... ternaryOperators) + { + for (int i = 0, len = str.length(), oldCh = -1, tokenCount = 0, quote = 0, brackets = 0; i < len; i++) + { + char ch = str.charAt(i); + if (ch == '\"') + quote++; + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + brackets--; + else if (quote % 2 == 0 && brackets == 0) + { + for (char token : ternaryOperators) + if (ch == token && oldCh != token && (i >= len-1 || str.charAt(i+1) != token)) + { + defaultCountOfConfitions += token == ternaryOperators[0] ? 1 : -1; + tokenCount++; + } + + if (defaultCountOfConfitions == 0 && tokenCount > 0) + return i; + } + oldCh = ch; + } + return -1; + } + + /** + * @param str + * @param from + * @param oneChar + * + * @return + * + * @since 1.3.5 + */ + public static int indexOfOne(CharSequence str, int from, char oneChar) + { + for (int len = str.length(), oldCh = -1, quote = 0, brackets = 0; from < len; from++) + { + char ch = str.charAt(from); + if (ch == '\"') + quote++; + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + brackets--; + else if (quote % 2 == 0 && brackets == 0 && ch == oneChar && oldCh != oneChar && (from >= len-1 || str.charAt(from+1) != oneChar)) + return from; + oldCh = ch; + } + return -1; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java new file mode 100644 index 0000000..a0f8487 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java @@ -0,0 +1,152 @@ +package org.ugp.serialx.converters.operators; + +import static org.ugp.serialx.Serializer.indexOfNotInObj; +import static org.ugp.serialx.converters.operators.ArithmeticOperators.getTerms; + +import java.util.List; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.converters.DataParser; + +/** + * This parser provides logical operators to evaluate boolean expressions such as false || true && true ^ false = true! + * + * @author PETO + * + * @since 1.3.0 + */ +public class LogicalOperators implements DataParser +{ + @Override + public Object parse(ParserRegistry myHomeRegistry, String s, Object... args) + { + if (s.length() > 2 && indexOfNotInObj(s, '&', '|', '^') > -1) + { + List[] terms = getTerms(s, '&', '|', '^'); + List cofs = terms[0]; + if (cofs.size() <= 1) + return CONTINUE; + + List oprs = terms[1]; + + Object cof1 = null, cof2 = null, opr = null; + try + { + for (int i = 0, index = 0, size = oprs.size(); i < size; index = 0, i++) + { + opr = oprs.remove(index); + if (opr.equals("&&")) + { + cof1 = cofs.get(index); + if (cof1 instanceof String) + cof1 = myHomeRegistry.parse(cof1.toString().trim(), i > 0, new Class[] {getClass()}, args); + if (cof1.equals(false)) + { + cofs.remove(index + 1); + cofs.set(index, false); + } + else + { + cof2 = cofs.remove(index + 1); + if (cof2 instanceof String) + cof2 = myHomeRegistry.parse(cof2.toString().trim(), i > 0, new Class[] {getClass()}, args); + cofs.set(index, andOperator(cof1, cof2)); + } + } + else if (opr.equals("||")) + { + cof1 = cofs.get(index); + if (cof1 instanceof String) + cof1 = myHomeRegistry.parse(cof1.toString().trim(), i > 0, new Class[] {getClass()}, args); + if (cof1.equals(true)) + { + return true; + } + else + { + cof2 = cofs.remove(index + 1); + if (cof2 instanceof String) + cof2 = myHomeRegistry.parse(cof2.toString().trim(), i > 0, new Class[] {getClass()}, args); + cofs.set(index, orOperator(cof1, cof2)); + } + } + else if (opr.equals("^")) + { + cof1 = cofs.get(index); + if (cof1 instanceof String) + cof1 = myHomeRegistry.parse(cof1.toString().trim(), i > 0, new Class[] {getClass()}, args); + + cof2 = cofs.remove(index + 1); + if (cof2 instanceof String) + cof2 = myHomeRegistry.parse(cof2.toString().trim(), i > 0, new Class[] {getClass()}, args); + cofs.set(index, xorOperator(cof1, cof2)); + } + } + } + catch (ClassCastException ex) + { + LogProvider.instance.logErr("Logical operator " + opr + " is undefined between " + cof1.getClass().getName() + " and " + cof2.getClass().getName() + "!", ex); + } + catch (IndexOutOfBoundsException e) + { + LogProvider.instance.logErr("Missing coefficient in \"" + s + "\"!", e); + } + return cofs.get(0); + } + return CONTINUE; + } + + /** + * @return True if obj1 and obj2 is true! + * + * @since 1.3.2 + */ + public Object andOperator(Object obj1, Object obj2) + { + return (boolean) toBool(obj1) && (boolean) toBool(obj2); + } + + /** + * @return True if obj1 or obj2 is true! + * + * @since 1.3.2 + */ + public Object orOperator(Object obj1, Object obj2) + { + return (boolean) toBool(obj1) || (boolean) toBool(obj2); + } + + /** + * @return True if obj1 xor obj2 is true! + * + * @since 1.3.2 + */ + public Object xorOperator(Object obj1, Object obj2) + { + return (boolean) toBool(obj1) ^ (boolean) toBool(obj2); + } + + /** + * @return null -> false or if number > 0 + * + * @since 1.3.0 + */ + public static Object toBool(Object obj) + { + if (obj == null) + return false; + else if (obj instanceof Number) + return ((Number) obj).doubleValue() > 0; + else if (obj instanceof Character) + return (char) obj > 0; + /*else if (obj instanceof Map) + return !((Map) obj).isEmpty(); + else if (obj instanceof Collection) + return !((Collection) obj).isEmpty(); + else if (obj instanceof Scope) + return !((Scope) obj).isEmpty(); + else if (obj.getClass().isArray()) + return Array.getLength(obj) > 0;*/ + return obj; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java new file mode 100644 index 0000000..d59f941 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java @@ -0,0 +1,81 @@ +package org.ugp.serialx.converters.operators; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.converters.DataParser; + +/** + * This parser provides ability to negate stuff! For example !true returns false! + * + * @author PETO + * + * @since 1.3.0 + */ +public class NegationOperator implements DataParser +{ + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + int ch, len = str.length(); + if (len > 0 && ((ch = str.charAt(0)) == '-' || ch == '!')) + { + int negCount = 1; + for (int i = negCount; i < len; i++) + if ((ch = str.charAt(i)) == '-' || ch == '!') + negCount++; + else + break; + + Object obj = myHomeRegistry.parse(str.substring(negCount), args); + if (negCount % 2 == 0) + return obj; + Object neg = notOperator(obj); + if (obj == neg && !(obj instanceof Number && ((Number) obj).intValue() == 0)) + LogProvider.instance.logErr("Unable to nagete \"" + obj + "\" because object of \"" + obj.getClass().getName() + "\" cant be negated!", null); + return neg; + } + return CONTINUE; + } + + + /** + * @param obj | Object to negate! + * + * @return Negated object supposed to be returned or same object as argument if object can't be negated! Only numbers and booleans can be negated! + * + * @since 1.3.2 + */ + public Object notOperator(Object obj) + { + return negate(obj); + } + + /** + * @param obj | Object to negate! + * + * @return Negated object or same object as argument if object can't be negated! Only numbers and booleans can be negated! + * + * @since 1.3.0 + */ + public static Object negate(Object obj) + { + if (obj == null) + return 0; + else if (obj instanceof Boolean) + obj = !((boolean) obj); + else if (obj.getClass() == Byte.class) + obj = (byte) -((Number) obj).byteValue(); + else if (obj.getClass() == Short.class) + obj = (short) -((Number) obj).shortValue(); + else if (obj.getClass() == Integer.class) + obj = -((int) obj); + else if (obj.getClass() == Character.class) + obj = (char) -((Character) obj); + else if (obj.getClass() == Long.class) + obj = -((long) obj); + else if (obj.getClass() == Float.class) + obj = -((float) obj); + else if (obj.getClass() == Double.class) + obj = -((double) obj); + return obj; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java new file mode 100644 index 0000000..2246d6d --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java @@ -0,0 +1,235 @@ +package org.ugp.serialx.protocols; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.ugp.serialx.Scope; +import org.ugp.serialx.Serializer; + +/** + * This is automatic protocol that will automatically serialize every or selected field in object that has valid and public getter and setter! + * This protocol is applicable on anything you want however condition of use is absence of final field otherwise {@link AutoProtocol#createBlankInstance(Class)} should be overridden. ALso you should {@link AutoProtocol#createBlankInstance(Class)} when you object is to complex! + * + * @author PETO + * + * @param | Generic type of object to use protocol for. + * + * @since 1.2.2 + */ +public class AutoProtocol extends SerializationProtocol +{ + static { + UNIVERSAL_INTROSPECTION = new ArrayList<>(); + } + + /** + * Universal instance of AutoProtocol that is applicable for any {@link Object}! + * + * @since 1.3.5 + * + * @see AutoProtocol#UNIVERSAL_SCOPE + */ + public static final AutoProtocol UNIVERSAL = new AutoProtocol<>(Object.class, AutoProtocol.UNIVERSAL_INTROSPECTION); + + /** + * Universal instance of AutoProtocol that is applicable for any {@link Object}! + * Object will be serialized as {@link Scope}! + * + * @since 1.3.5 + */ + public static final AutoProtocol UNIVERSAL_SCOPE = new AutoProtocol<>(Object.class, true, AutoProtocol.UNIVERSAL_INTROSPECTION); + + /** + * This is information for {@link AutoProtocol} to always introspect structure of every object before that is being serialized or deserialized, which means all fields with public and valid getters and setters will be serialized for every object! + *
+ * This is default behavior of {@link AutoProtocol} when no fields are specified in constructor! + * + * @since 1.3.5 + */ + public static final List UNIVERSAL_INTROSPECTION; + + protected final Class applicableFor; + protected List fieldDescriptors = new ArrayList<>(); + protected HashMap, List> cache = new HashMap<>(); + protected boolean useScope; + + /** + * @param applicableFor | Class that can be serialized using this protocol. + * @param fieldsToSerialize | Names of fields to serialize, if empty array is put there then all fields with public and valid getters and setters will be serialized! + * + * @throws IntrospectionException when there are no field with valid and public getters and setters. + * + * @since 1.2.2 + */ + public AutoProtocol(Class applicableFor, String... fieldsToSerialize) throws IntrospectionException + { + this(applicableFor, false, fieldsToSerialize); + } + + /** + * @param applicableFor | Class that can be serialized using this protocol. + * @param fieldsToSerialize | PropertyDescriptor of fields to serialize, if null all fields width valid and public getters and setters will be serialized! + * + * @since 1.3.5 + */ + public AutoProtocol(Class applicableFor, List fieldsToSerialize) + { + this(applicableFor, false, fieldsToSerialize); + } + + /** + * @param applicableFor | Class that can be serialized using this protocol. + * @param useScope | If true, objects will be serialized using scope which is longer but more readable! + * @param fieldsToSerialize | Names of fields to serialize, if this array is empty or null then all fields with public and valid getters and setters will be serialized! + * + * @throws IntrospectionException when there are no fields with valid and public getters and setters. + * + * @since 1.3.2 + */ + public AutoProtocol(Class applicableFor, boolean useScope, String... fieldsToSerialize) throws IntrospectionException + { + this(applicableFor, useScope, fieldsToSerialize.length == 0 ? UNIVERSAL_INTROSPECTION : Scope.getPropertyDescriptorsOf(applicableFor, fieldsToSerialize)); + } + + /** + * @param applicableFor | Class that can be serialized using this protocol. + * @param useScope | If true, objects will be serialized using scope which is longer but more readable! + * @param fieldsToSerialize | PropertyDescriptor of fields to serialize, if null {@link AutoProtocol#UNIVERSAL_INTROSPECTION} will take place! + * + * @since 1.3.5 + */ + public AutoProtocol(Class applicableFor, boolean useScope, List fieldsToSerialize) + { + this.applicableFor = applicableFor; + setUseScope(useScope); + this.fieldDescriptors = fieldsToSerialize == null ? UNIVERSAL_INTROSPECTION : fieldsToSerialize; + + if (fieldDescriptors == UNIVERSAL_INTROSPECTION) + try + { + Scope.getPropertyDescriptorsOf(applicableFor, cache); + } + catch (IntrospectionException e) + {} + } + + /** + * @param objectClass | Class to create new instance of! + * + * @return New blank instance of required class! When not override, it returns {@link Serializer#Instantiate(objectClass)} + * + * @throws Exception if any exception occurs (based on implementation). + * + * @since 1.2.2 + */ + public T createBlankInstance(Class objectClass) throws Exception + { + return Serializer.Instantiate(objectClass); + } + + @Override + public Object[] serialize(T object) throws Exception + { + List fieldDescriptors = this.fieldDescriptors; + if (fieldDescriptors == UNIVERSAL_INTROSPECTION) + fieldDescriptors = Scope.getPropertyDescriptorsOf(object.getClass(), cache); + + if (isUseScope()) + { + return new Object[] {Scope.from(object, fieldDescriptors)}; + } + else + { + int size = fieldDescriptors.size(); + Object[] args = new Object[size]; + for (int i = 0; i < size; i++) + args[i] = fieldDescriptors.get(i).getReadMethod().invoke(object); + return args; + } + } + + @Override + public T unserialize(Class objectClass, Object... args) throws Exception + { + List fieldDescriptors = this.fieldDescriptors; + if (fieldDescriptors == UNIVERSAL_INTROSPECTION) + fieldDescriptors = Scope.getPropertyDescriptorsOf(objectClass, cache); + + T obj = createBlankInstance(objectClass); + if (isUseScope() && args.length == 1 && args[0] instanceof Scope) + { + return Scope.into(obj, (Scope) args[0], fieldDescriptors); + } + + for (int i = 0, size = fieldDescriptors.size(); i < size && i < args.length; i++) + fieldDescriptors.get(i).getWriteMethod().invoke(obj, args[i]); + return obj; + } + + /** + * @deprecated DO NOT USE! + * + * @param variableName | Name of variable! + * + * @return PropertyDescriptor of variable with name or null if this protocols can't use it! + * + * @since 1.3.2 + */ + @Deprecated + public PropertyDescriptor getfieldDescriptorsDescriptor(String variableName) + { + for (PropertyDescriptor var : fieldDescriptors) + if (var.getName().equals(variableName)) + return var; + return null; + } + + @Override + public Class applicableFor() + { + return applicableFor; + } + + /** + * @return If true, objects will be serialized using scope which is longer but more readable! + * + * @since 1.3.2 + */ + public boolean isUseScope() + { + return useScope; + } + + /** + * @param useScope | If true, objects will be serialized using scope which is longer but more readable! + * + * @since 1.3.2 + */ + public void setUseScope(boolean useScope) + { + this.useScope = useScope; + } + + /** + * DEPRECATED: DO NOT USE! USE {@link Scope#getPropertyDescriptorsOf(Class, String...)} instead! + * + * @param cls | Class to inspect! + * @param fieldNames | Names of fields to get descriptors for, if this array is empty or null, descriptors for all fields with public getters and setters will be obtained! + * + * @return List of {@link PropertyDescriptor}s of cls representing access methods of required fields! Only descriptors of fields that have valid and public getter and setter will be returned! + * + * @throws IntrospectionException when there are no fields with valid and public getters and setters. + * + * @see PropertyDescriptor + * + * @since 1.3.2 + */ + @Deprecated + public static List getPropertyDescriptorsOf(Class cls, String... fieldNames) throws IntrospectionException + { + return Scope.getPropertyDescriptorsOf(cls, fieldNames); + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/EnumProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/EnumProtocol.java new file mode 100644 index 0000000..f0bba4d --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/EnumProtocol.java @@ -0,0 +1,33 @@ + package org.ugp.serialx.protocols; + +import java.util.Collection; + +/** + * EnumProtocol is universal protocol to serialize any enumerator ({@link Collection} instance). + * + * @author PETO + * + * @since 1.2.2 + */ +public class EnumProtocol extends SerializationProtocol> +{ + @Override + public Object[] serialize(Enum object) + { + return new Object[] {object.name()}; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Enum unserialize(Class> objectClass, Object... args) + { + return Enum.valueOf((Class) objectClass, args[0].toString()); + } + + @SuppressWarnings("unchecked") + @Override + public Class> applicableFor() + { + return (Class>) Enum.class; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/ListProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/ListProtocol.java new file mode 100644 index 0000000..d2d99a8 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/ListProtocol.java @@ -0,0 +1,44 @@ +package org.ugp.serialx.protocols; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +/** + * ListProtocol is universal protocol to serialize any {@link Collection} instance. The condition of use is public constructor with one {@link Collection} argument. + * + * @author PETO + * + * @since 1.0.0 and applicable for {@link Collection} since 1.2.2 + */ +public class ListProtocol extends SerializationProtocol> +{ + @Override + public Object[] serialize(Collection obj) + { + return obj.toArray(); + } + + @Override + public Collection unserialize(Class> objectClass, Object... args) throws Exception + { + if (objectClass.isInterface()) + return new ArrayList<>(Arrays.asList(args)); + + try + { + return objectClass.getConstructor(Collection.class).newInstance(Arrays.asList(args)); + } + catch (Exception e) + { + return objectClass.getConstructor(Object[].class).newInstance(args); + } + } + + @SuppressWarnings("unchecked") + @Override + public Class> applicableFor() + { + return (Class>) Collection.class; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java new file mode 100644 index 0000000..47af7e3 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java @@ -0,0 +1,50 @@ +package org.ugp.serialx.protocols; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.ugp.serialx.GenericScope; +import org.ugp.serialx.LogProvider; + +public class MapProtocol extends SerializationProtocol> +{ + @Override + public Object[] serialize(Map object) + { + Object[] args = new Object[object.size()*2]; + int i = 0; + for (Entry entry: object.entrySet()) + { + args[i] = entry.getKey(); + args[i+1] = entry.getValue(); + i+=2; + } + return args; + } + + @SuppressWarnings("unchecked") + @Override + public Map unserialize(Class> objectClass, Object... args) throws Exception + { + boolean isFromScope = args.length == 1 && args[0] instanceof GenericScope; + if (args.length % 2 != 0 && !isFromScope) + LogProvider.instance.logErr(getClass().getSimpleName() + ": Some variables have no values, this is not good!", null); + + if (objectClass.isInterface()) + objectClass = (Class>) HashMap.class; + + if (isFromScope) + return objectClass.getConstructor(Map.class).newInstance(((GenericScope) args[0]).variables()); + + return objectClass.getConstructor(Map.class).newInstance(GenericScope.mapKvArray(new LinkedHashMap<>(args.length/2), args)); + } + + @SuppressWarnings("unchecked") + @Override + public Class> applicableFor() + { + return (Class>) Map.class; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java new file mode 100644 index 0000000..d1c8a69 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java @@ -0,0 +1,47 @@ +package org.ugp.serialx.protocols; + +import java.util.HashMap; +import java.util.Map; + +import org.ugp.serialx.GenericScope; +import org.ugp.serialx.Scope; +import org.ugp.serialx.converters.DataConverter; + + +/** + * ScopeProtocol is universal protocol to serialize any {@link GenericScope} instance. The condition of use is public constructor with arguments {@link Map} and Object[]!
+ * Note: This protocol is unique in some way because it works for read only because scopes are normally serialized via {@link DataConverter} meaning calling serialize method will throw exception right away! But under normal circumstances protocols like this should not exist! + * + * @author PETO + * + * @since 1.2.2 + */ +public class ScopeProtocol extends SerializationProtocol> +{ + @Override + public Object[] serialize(GenericScope object) throws Exception + { + if (object.getClass() != Scope.class) + return new Object[] {object.castTo(Scope.class)}; + throw new UnsupportedOperationException(getClass().getSimpleName() + ": You are trying to serialize GenericScope or Scope via protocol! This is not good and should not even be possible! Scopes are meant to be serialized via converters!"); + } + + @Override + public GenericScope unserialize(Class> objectClass, Object... args) throws Exception + { + if (args.length == 1 && args[0] instanceof GenericScope) + { + if (objectClass == args[0].getClass()) + return (GenericScope) args[0]; + return objectClass.getConstructor(Map.class, Object[].class).newInstance(((GenericScope) args[0]).toVarMap(), ((GenericScope) args[0]).toValArray()); + } + return objectClass.getConstructor(Map.class, Object[].class).newInstance(new HashMap<>(), args); + } + + @SuppressWarnings("unchecked") + @Override + public Class> applicableFor() + { + return (Class>) GenericScope.class; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializable.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializable.java new file mode 100644 index 0000000..3c35d90 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializable.java @@ -0,0 +1,22 @@ +package org.ugp.serialx.protocols; + +import java.io.Serializable; + +/** + * This is based on pretty similar concept as regular {@link Serializable} is! However this interface is meant to create its instance programmatically via constructor! + * So condition of using this is that array of objects returned by {@link SelfSerializable#serialize()} must be applicable for some public constructor of certain class implementing this! + * Specific instances of this interface will be created by calling that public constructor! This is done reflectively by {@link SelfSerializableProtocol}! + * + * @author PETO + * + * @since 1.2.2 + */ +public interface SelfSerializable +{ + /** + * @return Array of objects that can be applied to certain public constructor of this class! This constructor will be then used as unserialize method and will be called during unserialization! + * + * @since 1.2.2 + */ + public Object[] serialize(); +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializableProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializableProtocol.java new file mode 100644 index 0000000..466a06c --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializableProtocol.java @@ -0,0 +1,31 @@ +package org.ugp.serialx.protocols; + +/** + * SelfSerializableProtocol is universal protocol to serialize any {@link SelfSerializable} instance. The condition of use is implementation of {@link SelfSerializable} interface and public constructor that can be called with content returned by specific {@link SelfSerializable#serialize()}! + * + * @author PETO + * + * @since 1.2.2 + * + * @see UniversalObjectInstantiationProtocol + */ +public class SelfSerializableProtocol extends UniversalObjectInstantiationProtocol +{ + @Override + public Object[] serialize(SelfSerializable object) + { + return object.serialize(); + } + + @Override + public Class applicableFor() + { + return SelfSerializable.class; + } + + @Override + public byte getMode() + { + return MODE_ALL; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java new file mode 100644 index 0000000..16e65ba --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java @@ -0,0 +1,450 @@ +package org.ugp.serialx.protocols; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.Registry; +import org.ugp.serialx.Serializer; + +/** + * This class supposed to be used for serializing and unserializing objects in Java by turning them in to array of Objects that can be serialized by {@link Serializer} or used by some higher entities. Also this class is capable of turning array of these objects back in to that very same Object!
+ * {@link SerializationProtocol#unserialize(Class, Object...)} and {@link SerializationProtocol#serialize(Object)} are used for this conversion. + * Instance of SerializationProtocol should be registered into {@link SerializationProtocol#REGISTRY} in order to work, also only one instance of each SerializationProtocol should be used and accessed via this registry!
+ * Note: Protocols should not be serializable in any way!
+ * + * @author PETO + * + * @param | Generic type of object to use protocol for. + * + * @since 1.0.0 + */ +public abstract class SerializationProtocol +{ + /** + * This is serialization protocol registry. This is place where your {@link SerializationProtocol} implementations should be registered in order to work properly! Do not add there two protocols applicable for exactly same classes! + * Also I recommend to register protocols in generic order of object that are they applicable for! In other words If some object Foo has child classes, protocol of these classes should be registered after each other. + * Defaultly there are registered protocols from ugp.org.SerialX.protocols. + * + * @since 1.3.0 + */ + public static final ProtocolRegistry REGISTRY = new ProtocolRegistry(new UniversalObjectInstantiationProtocol(), new ListProtocol(), new MapProtocol(), new StringProtocol(), new ScopeProtocol(), new SelfSerializableProtocol(), new EnumProtocol()); + + /** + * This mode is for protocols that are used for serialization only! + * + * @since 1.3.5 + */ + public static final byte MODE_SERIALIZE = 0; + + /** + * This mode is for protocols that are used for deserialization only! + * + * @since 1.3.5 + */ + public static final byte MODE_DESERIALIZE = 1; + + /** + * This mode is for protocols that chat can both serialize and deserialize! + * + * @since 1.3.5 + */ + public static final byte MODE_ALL = 2; + + protected boolean isActive = true; + + @Override + public boolean equals(Object obj) + { + if (obj instanceof Class) + return applicableFor().equals(obj); + else if (obj instanceof SerializationProtocol) + return applicableFor().equals(((SerializationProtocol) obj).applicableFor()); + return super.equals(obj); + } + + @Override + public String toString() + { + return getClass().getName() + "[" + applicableFor().getName() + "]"; + } + + /** + * @param object | The object. + * + * @return Array of objects to serialize created from given object. + * + * @since 1.0.0 + */ + public abstract Object[] serialize(T object) throws Exception; + + /*/** + * @param object | The object. + * @param scope | Scope to use! + * + * @return Scope of object to serialize created from given object. + * Note: Do not use WORK IN PROGRESS! + * + * @since 1.2.2 + * + public Scope serializeAsScope(T object) + { + return null; + }*/ + + /** + * @param objectClass | The class of object that should be created. This can be useful when object {@link T} has children classes with same constructors. You can use reflection to make protocol working also for these child classes! + * @param args | Args to create obj {@link T} from. + * + * @return New instance of object {@link T} created from args. This supposed to be an instance of object, not null! + * + * @throws Exception you can just pass exception to Serializer if you are not interested in handling it on your own. + * + * @since 1.0.0 + */ + public abstract T unserialize(Class objectClass, Object... args) throws Exception; + + /*/** + * @param objectClass | The class of object that should be created. This can be useful when object {@link T} has children classes with same constructors. You can use reflection to make protocol working also for these child classes! + * @param scope | Scope with data to create {@link T} from. + * + * @return New instance of object {@link T} created from scopeOfArgs. + * + * @since 1.2.0 + * + public T unserialize(Class objectClass, Scope scope) throws Exception + { + return null; + }*/ + + /** + * @return Class that can be serialized using this protocol. + * In other words it should return class of object {@link T} + * + * @since 1.0.0 + */ + public abstract Class applicableFor(); + + /** + * @return Mode of this protocol. Default is {@link SerializationProtocol#MODE_ALL}! + * + * @see SerializationProtocol#MODE_ALL + * @see SerializationProtocol#MODE_DESERIALIZE + * @see SerializationProtocol#MODE_SERIALIZE + * + * @since 1.3.5 + */ + public byte getMode() + { + return MODE_ALL; + } + + /** + * @return True if this protocol is active. + * Only active protocols can be used! + * + * @since 1.0.0 + */ + public boolean isActive() + { + return isActive; + } + + /** + * @param isActive | Set this on true to activate this protocol or set this on false to deactivate it so it will not be used. + * This can be useful for example when you want to force program to serialize java.io.Serializable object using classic java.io.Serializable. + * For example when you deactivate {@link StringProtocol} program will be forced to serialize all Strings via java.io.Serializable. + * + * @since 1.0.0 + */ + public void setActive(boolean isActive) + { + this.isActive = isActive; + } + + /** + * @param object | The object. + * + * @return Array of objects to serialize created from given object. Object will be serialized via protocol picked from {@link SerializationProtocol#REGISTRY}. + * {@link SerializationProtocol#serialize(Class, Object...)} method of picked protocol will be called! Null will be returned if no protocol was found and you will be prompted with error message! + * + * @since 1.3.0 + */ + public static Object[] serializeObj(O object) throws Exception + { + return serializeObj(REGISTRY, object); + } + + /** + * @param registry | Registry to use! + * @param object | The object. + * + * @return Array of objects to serialize created from given object. Object will be serialized via protocol picked from registry. + * {@link SerializationProtocol#serialize(Class, Object...)} method of picked protocol will be called! Null will be returned if no protocol was found and you will be prompted with error message! + * + * @since 1.3.0 + */ + public static Object[] serializeObj(ProtocolRegistry registry, O object) throws Exception + { + SerializationProtocol prot = registry.GetProtocolFor(object, MODE_SERIALIZE); + if (prot == null) + { + LogProvider.instance.logErr(SerializationProtocol.class.getSimpleName() + ": Unable to serialize \"" + object + "\" because there is no registered and active protocol for serializing " + object.getClass() + "!", null); + return null; + } + return prot.serialize(object); + } + + /** + * @param objectClass | The class of object that should be created. This can be useful when object {@link O} has children classes with same constructors. You can use reflection to make protocol working also for these child classes! This class is also used to pick suitable protocol! + * @param args | Args to create obj {@link T} from. + * + * @return New instance of object {@link T} created from args. Object will be created via protocol picked from {@link SerializationProtocol#REGISTRY}. If there is no protocol registered for objectClass null will be returned and you will be prompted in console! + * {@link SerializationProtocol#unserialize(Class, Object...)} method of picked protocol will be called! + * + * @throws Exception when exception occurs while unserializing object using protocol! + * + * @since 1.3.0 + */ + public static O unserializeObj(Class objectClass, Object... args) throws Exception + { + return unserializeObj(REGISTRY, objectClass, args); + } + + /** + * @param registry | Registry to use! + * @param objectClass | The class of object that should be created. This can be useful when object {@link O} has children classes with same constructors. You can use reflection to make protocol working also for these child classes! This class is also used to pick suitable protocol! + * @param args | Args to create obj {@link T} from. + * + * @return New instance of object {@link T} created from args. Object will be created via protocol picked from registry. If there is no protocol registered for objectClass null will be returned and you will be prompted in console! + * {@link SerializationProtocol#unserialize(Class, Object...)} method of picked protocol will be called! + * + * @throws Exception when exception occurs while unserializing object using protocol! + * + * @since 1.3.0 + */ + @SuppressWarnings("unchecked") + public static O unserializeObj(ProtocolRegistry registry, Class objectClass, Object... args) throws Exception + { + SerializationProtocol prot = (SerializationProtocol) registry.GetProtocolFor(objectClass, MODE_DESERIALIZE); + if (prot == null) + { + LogProvider.instance.logErr(SerializationProtocol.class.getSimpleName() + ": Unable to unserialize " + Arrays.toString(args) + " because there is no registered and active protocol for unserializing \"" + objectClass + "\"!", null); + return null; + } + return (O) prot.unserialize(objectClass, args); + } + + /** + * ProtocolRegistry, place to register protocols! + * + * @author PETO + * + * @since 1.0.0 (moved to SerializationProtocol since 1.3.0) + */ + public static class ProtocolRegistry extends Registry> + { + private static final long serialVersionUID = 1L; + + /** + * Constructs an {@link ProtocolRegistry} with the specified initial capacity. + * + * @param initialSize | Initial capacity. + * + * @since 1.3.5 + */ + public ProtocolRegistry(int initialSize) + { + super(initialSize); + } + + /** + * Constructs an {@link ProtocolRegistry} with content of c. + * + * @param c | Initial content of registry. + * + * @since 1.3.5 + */ + public ProtocolRegistry(Collection> c) + { + super(c); + } + + /** + * Constructs an {@link ProtocolRegistry} with protocols. + * + * @param protocols | Initial content of registry. + * + * @since 1.3.0 + */ + public ProtocolRegistry(SerializationProtocol... protocols) + { + super(protocols); + } + + @Override + public ProtocolRegistry clone() + { + return new ProtocolRegistry(this); + } + + @Override + public void add(int index, SerializationProtocol element) + { + if (GetProtocolFor(element.applicableFor()) != null && element.applicableFor() != Object.class) + LogProvider.instance.logErr(getClass().getSimpleName() + ": Protocol applicable for \"" + element.applicableFor().getName() + "\" is already registred!", null); + addDuplicatively(index, element); + } + + /** + * @param protocolsClass | Protocols class. + * + * @return Protocol by its class. + * + * @since 1.0.0 + */ + public SerializationProtocol getProtocolByClass(Class> protocolsClass) + { + for (SerializationProtocol p : this) + if (p.getClass().equals(protocolsClass)) + return p; + return null; + } + + /** + * @return Sublist of protocols that are active and can be used. + * + * @since 1.0.0 + */ + public List> GetActiveProtocols() + { + return GetActiveProtocols(MODE_ALL); + } + + /** + * @return Sublist of protocols that are not active and can't be used. + * + * @since 1.0.0 + */ + public List> GetDeactivatedProtocols() + { + return GetDeactivatedProtocols(MODE_ALL); + } + + /** + * @param mode | Mode of protocol to find. + * + * @return Sublist of protocols that are active and can be used according to mode. + * + * @since 1.3.5 + */ + public List> GetActiveProtocols(byte mode) + { + List> resault = new ArrayList<>(); + + for (SerializationProtocol p : this) + if (p.isActive() && (p.getMode() == 2 || p.getMode() == mode)) + resault.add(p); + return resault; + } + + /** + * @param mode | Mode of protocol to find. + * + * @return Sublist of protocols that are not active and can't be used according to mode. + * + * @since 1.3.5 + */ + public List> GetDeactivatedProtocols(byte mode) + { + List> resault = new ArrayList<>(); + + for (SerializationProtocol p : this) + if (!p.isActive() && (p.getMode() == 2 || p.getMode() == mode)) + resault.add(p); + return resault; + } + + /** + * @param + * @param obj | Object that is required protocol applicable for. + * + * @return Protocol applicable for required objects class or null if there is no such an active protocol! + * + * @since 1.0.5 + */ + public SerializationProtocol GetProtocolFor(O obj) + { + return GetProtocolFor(obj, MODE_ALL); + } + + /** + * @param + * @param applicableFor | Class of object that is protocol applicable for. + * + * @return Protocol applicable for required class or null if there is no such an active protocol! + * + * @since 1.0.0 + */ + public SerializationProtocol GetProtocolFor(Class applicableFor) + { + return GetProtocolFor(applicableFor, MODE_ALL); + } + + /** + * @param + * @param obj | Object that is required protocol applicable for. + * @param mode | Mode of protocol to find. + * + * @return Protocol applicable for required objects class according to mode or null if there is no such an active protocol! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public SerializationProtocol GetProtocolFor(O obj, byte mode) + { + return (SerializationProtocol) GetProtocolFor(obj.getClass(), mode); + } + + /** + * @param + * @param applicableFor | Class of object that is protocol applicable for. + * @param mode | Mode of protocol to find. + * + * @return Protocol applicable for required class according to mode or null if there is no such an active protocol! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public SerializationProtocol GetProtocolFor(Class applicableFor, byte mode) + { + SerializationProtocol protocol = null; + for (int i = 0, len = size(), myMode = 0; i < len; i++) + { + SerializationProtocol p = get(i); + if (p.isActive() && ((myMode = p.getMode()) == 2 || myMode == mode)) + { + Class applicable = p.applicableFor(); + if (applicable == applicableFor) + return (SerializationProtocol) p; + else if (applicable.isAssignableFrom(applicableFor)) + protocol = (SerializationProtocol) p; + } + } + return protocol; + } + + /** + * @param isActive | Activity state for all registered protocols. + * + * @since 1.0.0 + */ + public void setActivityForAll(boolean isActive) + { + for (SerializationProtocol p : this) + p.setActive(isActive); + } + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/StringProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/StringProtocol.java new file mode 100644 index 0000000..68e1529 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/StringProtocol.java @@ -0,0 +1,62 @@ +package org.ugp.serialx.protocols; + +/** + * StringProtocol is universal protocol to serialize any {@link CharSequence} instance. The condition of use is public constructor with one {@link String} or byte[] argument. + * + * @author PETO + * + * @since 1.0.0 and universal for {@link CharSequence} since 1.2.0 + */ +public class StringProtocol extends SerializationProtocol +{ + @Override + public Object[] serialize(CharSequence object) + { + int len = object.length(); + Object[] chars = new Object[len]; + + for (int i = 0; i < len; i++) + chars[i] = (int) object.charAt(i); + return chars; + } + + @Override + public CharSequence unserialize(Class objectClass, Object... args) throws Exception + { + if (args.length == 1 && args[0] instanceof CharSequence) + return (CharSequence) args[0]; + + if (objectClass.isInterface()) + objectClass = String.class; + + char[] chars = new char[args.length]; + for (int i = 0; i < args.length; i++) + if (args[i] != null) + { + if (args[i] instanceof Character) + chars[i] = (char) args[i]; + else + chars[i] = (char)((Number) args[i]).intValue(); + } + else + break; + + String str = new String(chars); + if (objectClass == String.class) + return str; + try + { + return objectClass.getConstructor(String.class).newInstance(str); + } + catch (Exception e) + { + return objectClass.getConstructor(char[].class).newInstance(chars); + } + } + + @Override + public Class applicableFor() + { + return CharSequence.class; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java new file mode 100644 index 0000000..414c37f --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java @@ -0,0 +1,61 @@ +package org.ugp.serialx.protocols; + +import java.lang.reflect.Constructor; +import java.util.Arrays; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.Serializer; + +/** + * Universal protocol for deserializing any object using its constructor. Args array of {@link UniversalObjectInstantiationProtocol#unserialize(Class, Object...)} must have elements applicable as arguments for some constructor of required objects class! + * Note: This protocol is for deserialization only! + * + * @author PETO + * + * @param Generic type of deserialized object! + * + * @since 1.3.5 + */ +public class UniversalObjectInstantiationProtocol extends SerializationProtocol { + + @Override + public Object[] serialize(T object) + { + throw new UnsupportedOperationException(getClass().getSimpleName() + ": This protocol is only for reading! It cant serialize " + object); + } + + @SuppressWarnings("unchecked") + @Override + public T unserialize(Class objectClass, Object... args) throws Exception + { + try + { + return objectClass.getConstructor(Serializer.ToClasses(args)).newInstance(args); + } + catch (Exception e0) + { + for (Constructor cons : objectClass.getConstructors()) + try + { + return (T) cons.newInstance(args); + } + catch (IllegalArgumentException e) + {} + } + LogProvider.instance.logErr(getClass().getSimpleName() + ": Unable to call create new instance of \"" + objectClass + "\" because inserted arguments " + Arrays.asList(args) + " cannot be applied on any public constructor in required class!", null); + return null; + } + + @SuppressWarnings("unchecked") + @Override + public Class applicableFor() + { + return (Class) Object.class; + } + + @Override + public byte getMode() + { + return MODE_DESERIALIZE; + } +} diff --git a/SerialX-json/.classpath b/SerialX-json/.classpath new file mode 100644 index 0000000..002ad57 --- /dev/null +++ b/SerialX-json/.classpath @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SerialX-json/.project b/SerialX-json/.project new file mode 100644 index 0000000..873aaef --- /dev/null +++ b/SerialX-json/.project @@ -0,0 +1,23 @@ + + + SerialX-json + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/SerialX-json/.settings/org.eclipse.jdt.core.prefs b/SerialX-json/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..2f5cc74 --- /dev/null +++ b/SerialX-json/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/SerialX-json/.settings/org.eclipse.m2e.core.prefs b/SerialX-json/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/SerialX-json/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/SerialX-json/pom.xml b/SerialX-json/pom.xml new file mode 100644 index 0000000..9b6b1be --- /dev/null +++ b/SerialX-json/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + + org.ugp + serialx + 1.3.7 + + org.ugp.serialx + json + + SerialX-json + SerialX Json support + + + + org.ugp.serialx + core + 1.3.7 + + + \ No newline at end of file diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java new file mode 100644 index 0000000..f468198 --- /dev/null +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java @@ -0,0 +1,403 @@ +package org.ugp.serialx.json; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; + +import org.ugp.serialx.GenericScope; +import org.ugp.serialx.JussSerializer; +import org.ugp.serialx.Registry; +import org.ugp.serialx.Scope; +import org.ugp.serialx.Serializer; +import org.ugp.serialx.converters.BooleanConverter; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.converters.DataParser.ParserRegistry; +import org.ugp.serialx.json.converters.JsonCharacterConverter; +import org.ugp.serialx.json.converters.JsonNumberConverter; +import org.ugp.serialx.json.converters.JsonObjectConverter; +import org.ugp.serialx.converters.NullConverter; +import org.ugp.serialx.converters.StringConverter; +import org.ugp.serialx.converters.VariableConverter; +import org.ugp.serialx.protocols.SerializationProtocol; +import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; + +/** + * This is implementation of {@link JussSerializer} for serializing in Json! + * It should generate and work with .json files! + *

+ * Note: No Json specific syntax checks are made, only some small conventions and formating changes will occur to ensure Json syntax correctness but it will let you to use some Juss features freely so you can easily end up with some Json-juss hybrid! + * + * @author PETO + * + * @since 1.3.2 + */ +@SuppressWarnings("serial") +public class JsonSerializer extends JussSerializer +{ + /** + * This is representation of empty Json array. Use this instead of empty scope during serialization when you want to prevent it being serialized as empty Json object! + *

+ * [] + * + * @since 1.3.5 + */ + public static final String EMPTY_ARRAY = StringConverter.DirectCode("[]"); + + /** + * This is representation of empty Json array. This is how empty scopes will be serialized by default! + *

+ * [] + * + * @since 1.3.5 + * + * @see JsonSerializer#EMPTY_ARRAY + */ + public static final String EMPTY_OBJECT = StringConverter.DirectCode("{}"); + + public static final ParserRegistry JSON_PARSERS = new ParserRegistry(new VariableConverter(true), new StringConverter(), new JsonNumberConverter(), new BooleanConverter(false), new JsonCharacterConverter(false), new NullConverter(), new JsonObjectConverter()); + + /** + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public JsonSerializer(Object... values) + { + this(null, values); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public JsonSerializer(Map variablesMap, Object... values) + { + this(variablesMap, values == null ? null : new ArrayList<>(Arrays.asList(values))); + } + + /** + * @param sourceScope | Scope with initial content! + * + * @since 1.3.5 + */ + public JsonSerializer(GenericScope sourceScope) + { + this(sourceScope == null ? null : sourceScope.variables(), sourceScope == null ? null : sourceScope.values()); + } + + /** + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public JsonSerializer(Map variablesMap, Collection values) + { + this(JSON_PARSERS.clone(), variablesMap, values); + } + + /** + * @param parsers | Registry of parsers to use! + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * + * @since 1.3.2 + */ + public JsonSerializer(Registry parsers, Map variablesMap, Collection values) + { + this(parsers, SerializationProtocol.REGISTRY.clone(), variablesMap, values, null); + } + + /** + * @param parsers | Registry of parsers to use! + * @param protocols | Registry of protocols to use! + * @param variablesMap | Initial variables to be added in to this scope! + * @param values | Initial independent values to be added in to this scope! + * @param parent | Parent of this scope. + * + * @since 1.3.2 + */ + public JsonSerializer(Registry parsers, ProtocolRegistry protocols, Map variablesMap, Collection values, Scope parent) + { + super(parsers, protocols, variablesMap, values, parent); + } + + @Override + public String Var(String name, T value, boolean isValue) + { + return Code((isValue ? "$\"" : "\"") + name + "\" = " + getParsers().toString(value, 0, 0, this, getProtocols(), isGenerateComments()) + (generateComments ? ", //Object of " + value.getClass().getName() + ": \"" + value + "\" inserted manually! Stored by \"" + name + "\" variable!" : "")); + } + + @Override + public Object put(String variableName, Object variableValue) + { + if (Serializer.isOneOf(variableName.charAt(0), '"', '\'') && Serializer.isOneOf(variableName.charAt(variableName.length()-1), '"', '\'')) + variableName = variableName.substring(1, variableName.length()-1); + return super.put(variableName, variableValue); + } + + @Override + public JsonSerializer emptyClone(Scope parent) + { + JsonSerializer srl = emptyClone(new JsonSerializer(), parent); + srl.setGenerateComments(isGenerateComments()); + return srl; + } + + @SuppressWarnings("unchecked") + @Override + public S LoadFrom(Reader reader, Object... formatArgs) + { + Scope sc = super.LoadFrom(reader, formatArgs); + + Object jsonScope; + if (sc.valuesCount() == 1 && (jsonScope = sc.get(0)) instanceof Scope) + return (S) jsonScope; + return (S) sc; + } + + @Override + public A SerializeTo(A source, Object... args) throws IOException + { + int tabs = 0; + if (args.length > 1 && args[1] instanceof Integer) + tabs = (int) args[1]; + + if (tabs == 0 && !(valuesCount() == 1 && variablesCount() <= 0 && get(0) instanceof Scope)) + { + JussSerializer scope = emptyClone(null); + scope.add(this); + return scope.SerializeTo(source, args); + } + return super.SerializeTo(source, args); + } + + @Override + public ParserRegistry getParsers() + { + return parsers != null ? parsers : (parsers = JSON_PARSERS.clone()); + } + + /** + * This should append serializedVar into source based on arguments, add separator and return source! + * + * @since 1.3.2 + */ + @Override + protected Appendable appandVar(Appendable source, CharSequence serializedVar, Entry var, int tabs, boolean isLast) throws IOException + { + source.append(multilpy('\t', tabs)).append(serializedVar); + if (isLast) + return source; + return source.append(','); + } + + /** + * This should append serializedVal into source based on arguments, add separator and return source! + * + * @since 1.3.2 + */ + @Override + protected Appendable appandVal(Appendable source, CharSequence serializedVal, Object value, int tabs, boolean isLast) throws IOException + { + source.append(multilpy('\t', tabs)).append(serializedVal); + if (isLast || serializedVal != null && indexOfNotInObj(serializedVal, '/') != -1) + return source; + return source.append(','); + } + + @Override + public A SerializeAsSubscope(A source, Object... args) throws IOException + { + return SerializeAsSubscope(source, variablesCount() > 0 ? new char[] {'{', '}'} : new char[] {'[', ']'}, args); + } + + /** + * @param jsonSerializer | JsonSerializer to create {@link JussSerializer} from! + * + * @return JussSerializer created from JsonSerializer, all values and variables will remain intact! + * + * @since 1.3.2 + */ + public static JsonSerializer fromJussSerializer(JussSerializer jussSerializer) + { + if (jussSerializer instanceof JsonSerializer) + return (JsonSerializer) jussSerializer; + try + { + return jussSerializer.transformToScope().clone(JsonSerializer.class); + } + catch (Exception e) + { + e.printStackTrace(); + return null; + } + } + + /** + * @param jsonSerializer | JsonSerializer to create {@link JussSerializer} from! + * + * @return JussSerializer created from JsonSerializer, all values and variables will remain intact! + * + * @since 1.3.2 (since 1.3.7 moved from {@link JussSerializer} and renamed from "fromJsonSerializer" to "toJussSerializer") + */ + public static JussSerializer toJussSerializer(JsonSerializer jsonSerializer) + { + try + { + if (jsonSerializer.valuesCount() == 1 && jsonSerializer.variablesCount() == 0 && jsonSerializer.get(0) instanceof Scope) + { + GenericScope sc = (GenericScope) jsonSerializer.getScope(0); + if (sc instanceof Serializer) + return ((Serializer) sc).transformToScope().clone(JsonSerializer.class); + return sc.clone(JsonSerializer.class); + } + else + return jsonSerializer.transformToScope().clone(JsonSerializer.class); + } + catch (Exception e) + { + e.printStackTrace(); + return null; + } + } + + /** + * @param fromObj | Object to create serializer from! + * + * @return {@link JsonSerializer} created from given fromObj by mapping obj's fields into variables of created serializer via given fields (fieldNamesToUse) and conversion rules listed below!!

+ * Table of specific Object --> JsonSerializer conversions: + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Object (fromObj) typeObtained serializer content (return)
{@link CharSequence}{@link Serializer#LoadFrom(CharSequence)}
{@link CharSequence} (as http address)Serializer (newInstance) will open connection with url and get + deserialize the content from it if possible!
{@link File}{@link Serializer#LoadFrom(File)}
{@link Reader}{@link Serializer#LoadFrom(Reader)}
{@link InputStream}{@link Serializer#LoadFrom(InputStream)}
{@link URL}Serializer (newInstance) will open connection with {@link URL} and get + deserialize the content from it if possible!
{@link URLConnection}Serializer (newInstance) will attempt to get + deserialize the content from given {@link URLConnection} if possible!
Others (default){@link Scope#from(Object, String...)} (return description)
+ * + * @throws When something went wrong during deserialization! + * + * @since 1.3.5 + */ + public static JsonSerializer from(Object fromObj) throws Exception + { + try + { + return from(fromObj, new String[0]); + } + catch (IntrospectionException e) + { + return new JsonSerializer(fromObj); + } + } + + /** + * @param fromObj | Object to create serializer from! + * @param fieldNamesToUse | Array of obj field names to map into scopes variables using getters (read method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link GenericScope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! + * + * @return {@link JsonSerializer} created from given fromObj by mapping obj's fields into variables of created serializer via given fields (fieldNamesToUse) and conversion rules listed below!!

+ * Table of specific Object --> JsonSerializer conversions: + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Object (fromObj) typeObtained serializer content (return)
{@link CharSequence}{@link Serializer#LoadFrom(CharSequence)}
{@link CharSequence} (as http address)Serializer (newInstance) will open connection with url and get + deserialize the content from it if possible!
{@link File}{@link Serializer#LoadFrom(File)}
{@link Reader}{@link Serializer#LoadFrom(Reader)}
{@link InputStream}{@link Serializer#LoadFrom(InputStream)}
{@link URL}Serializer (newInstance) will open connection with {@link URL} and get + deserialize the content from it if possible!
{@link URLConnection}Serializer (newInstance) will attempt to get + deserialize the content from given {@link URLConnection} if possible!
Others (default){@link Scope#from(Object, String...)} (return description)
+ * + * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often) or when something went wrong during deserialization! + * @throws IntrospectionException when there were no PropertyDescriptor found for obj class! + * + * @since 1.3.5 + */ + public static JsonSerializer from(Object fromObj, String... fieldNamesToUse) throws IntrospectionException, Exception + { + return (JsonSerializer) Serializer.from(new JsonSerializer(), fromObj, fieldNamesToUse); + } +} diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java new file mode 100644 index 0000000..0850e25 --- /dev/null +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java @@ -0,0 +1,28 @@ +package org.ugp.serialx.json.converters; + +import org.ugp.serialx.converters.CharacterConverter; + +public class JsonCharacterConverter extends CharacterConverter { + + protected boolean formatAsString; + + public JsonCharacterConverter(boolean formatAsString) { + setFormatAsString(formatAsString); + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (obj instanceof Character) + return isFormatAsString() ? obj.toString() : String.valueOf((int) (char) obj); + return CONTINUE; + } + + public boolean isFormatAsString() { + return formatAsString; + } + + public void setFormatAsString(boolean formatAsString) { + this.formatAsString = formatAsString; + } +} diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java new file mode 100644 index 0000000..4850d18 --- /dev/null +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java @@ -0,0 +1,14 @@ +package org.ugp.serialx.json.converters; + +import org.ugp.serialx.converters.NumberConverter; + +public class JsonNumberConverter extends NumberConverter { + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (obj instanceof Number) + return decimalFormatter != null ? decimalFormatter.format(obj) : obj.toString(); + return CONTINUE; + } +} diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java new file mode 100644 index 0000000..255591d --- /dev/null +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java @@ -0,0 +1,48 @@ +package org.ugp.serialx.json.converters; + +import org.ugp.serialx.Scope; +import org.ugp.serialx.Serializer; +import org.ugp.serialx.converters.ArrayConverter; +import org.ugp.serialx.converters.ObjectConverter; +import org.ugp.serialx.json.JsonSerializer; +import org.ugp.serialx.protocols.SerializationProtocol; + +/** + * Used internally by {@link JsonSerializer} to ensure proper and valid Json format for scopes and protocols. + * + * @author PETO + * + * @since 1.3.5 + */ +public class JsonObjectConverter extends ObjectConverter +{ + @SuppressWarnings("unchecked") + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) + { + if (arg.getClass().isArray()) + arg = new Scope(ArrayConverter.fromAmbiguous(arg)); + + SerializationProtocol prot = (SerializationProtocol) getProtocolFor(arg, SerializationProtocol.MODE_SERIALIZE, args); + + if (prot != null && !(arg instanceof Scope)) + try + { + Object[] objArgs = prot.serialize(arg); + if (objArgs.length == 1 && objArgs[0] instanceof Scope) + return super.toString(myHomeRegistry, objArgs[0], args); + else + return super.toString(myHomeRegistry, new Scope(objArgs), args); + } + catch (Exception e) + {} + + return super.toString(myHomeRegistry, arg, prot, args); + } + + @Override + public Serializer getPreferredSerializer() + { + return new JsonSerializer(); + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c9a8d30 --- /dev/null +++ b/pom.xml @@ -0,0 +1,58 @@ + + 4.0.0 + + org.ugp + serialx + 1.3.7 + pom + + + SerialX-json + SerialX-core + + + SerialX root + Store Java objects into file via SerialX. SerialX is a powerful utility library to serialize objects in Java programmatically via recursive descent parser for custom domain-specific languages! + https://github.com/SimplyProgrammer/Java-SerialX + + + + Custom license + https://github.com/SimplyProgrammer/Java-SerialX/blob/master/LICENSE + + + + + + SimplyProgrammer + petko.hupka@gmail.com + org.ugp + https://github.com/SimplyProgrammer/ + + + + + scm:git:git://github.com/SimplyProgrammer/Java-SerialX.git + scm:git:ssh://github.com:SimplyProgrammer/Java-SerialX.git + https://github.com/SimplyProgrammer/ + + + + 1.8 + 1.8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.8 + 1.8 + + + + + \ No newline at end of file From 234b2fdb37cd2bc9e1245f5823293e3e51af2222 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Mon, 26 Jun 2023 16:06:08 +0200 Subject: [PATCH 04/48] further modularization and bug fixes --- .classpath | 9 + .project | 6 + .settings/org.eclipse.core.resources.prefs | 2 + .settings/org.eclipse.jdt.core.prefs | 8 + Changelog.md | 211 ------------------ .../org.eclipse.core.resources.prefs | 6 + SerialX-core/pom.xml | 6 +- .../java/org/ugp/serialx/GenericScope.java | 2 +- .../java/org/ugp/serialx/JussSerializer.java | 47 +++- .../main/java/org/ugp/serialx/Registry.java | 44 +++- .../src/main/java/org/ugp/serialx/Scope.java | 15 +- .../main/java/org/ugp/serialx/Serializer.java | 42 ++-- .../ugp/serialx/converters/DataParser.java | 3 +- .../serialx/converters/NumberConverter.java | 6 +- .../serialx/converters/ObjectConverter.java | 2 +- .../serialx/converters/imports/Import.java | 10 +- .../ugp/serialx/protocols/MapProtocol.java | 7 + SerialX-devtools/.classpath | 38 ++++ SerialX-devtools/.project | 23 ++ .../org.eclipse.core.resources.prefs | 6 + .../.settings/org.eclipse.jdt.core.prefs | 8 + .../.settings/org.eclipse.m2e.core.prefs | 4 + SerialX-devtools/pom.xml | 23 ++ .../devtools}/SerializationDebugger.java | 169 +------------- .../converters/DebugParserRegistry.java | 165 ++++++++++++++ .../org.eclipse.core.resources.prefs | 6 + SerialX-json/pom.xml | 8 +- SerialX-operators/.classpath | 38 ++++ SerialX-operators/.project | 23 ++ .../org.eclipse.core.resources.prefs | 6 + .../.settings/org.eclipse.jdt.core.prefs | 8 + .../.settings/org.eclipse.m2e.core.prefs | 4 + SerialX-operators/pom.xml | 23 ++ .../org/ugp/serialx/converters/Operators.java | 69 ++++++ .../operators/ArithmeticOperators.java | 0 .../operators/ComparisonOperators.java | 0 .../ConditionalAssignmentOperators.java | 0 .../operators/LogicalOperators.java | 2 +- .../operators/NegationOperator.java | 0 pom.xml | 39 +++- 40 files changed, 650 insertions(+), 438 deletions(-) create mode 100644 .classpath create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 .settings/org.eclipse.jdt.core.prefs delete mode 100644 Changelog.md create mode 100644 SerialX-core/.settings/org.eclipse.core.resources.prefs create mode 100644 SerialX-devtools/.classpath create mode 100644 SerialX-devtools/.project create mode 100644 SerialX-devtools/.settings/org.eclipse.core.resources.prefs create mode 100644 SerialX-devtools/.settings/org.eclipse.jdt.core.prefs create mode 100644 SerialX-devtools/.settings/org.eclipse.m2e.core.prefs create mode 100644 SerialX-devtools/pom.xml rename {SerialX-core/src/main/java/org/ugp/serialx => SerialX-devtools/src/main/java/org/ugp/serialx/devtools}/SerializationDebugger.java (63%) create mode 100644 SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java create mode 100644 SerialX-json/.settings/org.eclipse.core.resources.prefs create mode 100644 SerialX-operators/.classpath create mode 100644 SerialX-operators/.project create mode 100644 SerialX-operators/.settings/org.eclipse.core.resources.prefs create mode 100644 SerialX-operators/.settings/org.eclipse.jdt.core.prefs create mode 100644 SerialX-operators/.settings/org.eclipse.m2e.core.prefs create mode 100644 SerialX-operators/pom.xml create mode 100644 SerialX-operators/src/main/java/org/ugp/serialx/converters/Operators.java rename {SerialX-core => SerialX-operators}/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java (100%) rename {SerialX-core => SerialX-operators}/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java (100%) rename {SerialX-core => SerialX-operators}/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java (100%) rename {SerialX-core => SerialX-operators}/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java (99%) rename {SerialX-core => SerialX-operators}/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java (100%) diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..bd36355 --- /dev/null +++ b/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.project b/.project index bbfcc34..fd37aa3 100644 --- a/.project +++ b/.project @@ -5,6 +5,11 @@ + + org.eclipse.jdt.core.javabuilder + + + org.eclipse.m2e.core.maven2Builder @@ -12,6 +17,7 @@ + org.eclipse.jdt.core.javanature org.eclipse.m2e.core.maven2Nature diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..2f5cc74 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/Changelog.md b/Changelog.md deleted file mode 100644 index ab29a47..0000000 --- a/Changelog.md +++ /dev/null @@ -1,211 +0,0 @@ -# SerialX 1.0.0 (beta) - -Release date: 8.14.2020 (Evening) - -What was added: -* Serializer utility class. -* 2 build-in protocols. -# - -# SerialX 1.0.5 (beta) - -Release date: 8.20.2020 (Night) - -What was added: -* Ability to generate comments. -* Fixing some small bugs. -# - -# SerialX 1.0.6 - -Release date: 8.22.2020 (Noon) - -What was added: -* Improveing way to serialize numbers. -* Adding suffixes fot double "d", short "s" and byte "y"! -* Java Base64 serialized object now does not need to start with "#"! -* Objects serialized using protocol with no arguments will now not by serialized with null argument! -* Repairing an error with long suffix! -# - -# SerialX 1.1.0 - -Release date: 9.22.2020 (Afternoon) - -What was added: -* Adding decimal number formatter! -* "unserialize" method in SerializationProtocol now throws Exception which makes reflection stuff easier! -* Fixing some problems such as "Too big objects simply disappear during serialization!" -* Better optimization. Improving the performance of Serializing and Unserializing astronomically! -* Some characters now can be serialized using regular Java way for example 'a'! However SerialX syntax characters such as { or } must be still serialized using ASCII code! -Numbers must have additional character behind for example '4/' otherwise they will be taken as ASCII code! -* Some new methods and stuff! -# - -# SerialX 1.1.2 - -Release date: 9.27.2020 (Evening) - -What was added: -* Integers now can be serialized using Java binary and hexadecimal form (0b1111, 0xffff)! -* Numbers can be separated with underscore (just like in Java)! -* Fixing the bug when formatter mess up decimals suffixes and integers! -# - -# SerialX 1.1.5 - -Release date: 12.6.2020 (Evening) - -What was added: -* Variable system! Now "order" is not only possibility. -* Functions working with variable system! -* Functions that allows you to insert custom code (comments and stuff)! -* Fixing "long-lived" bugs such as the on with double slash comment, hopefuly for the last! -# - -# SerialX 1.2.0_pre - V2 - -Release date: 3.18.2021 (Afternoon) - -What was added: -* New Scope object that are now values and variables loaded in to so now its not necesarry to load indepednent values and variables separatly! -* Scope is the physical manifestation of loaded content in your program! -* Ability to create sub-scopes / neasted scopes in side of parent scopes or file itself similarly to JSON! For example: { \/\*scope\*\/ } -* Ability to serialize string normaly in quotes like in java! But certain syntactical characters from SerialX cant be present! -* "splitValues" method was removed becasue it was out of purpous of library itself. -* Comma now works as semicolon! -* Tremendous reading performence boost! Large quantity reading is now up to 50x faster than in previous version. -* Fixing a bug when order of elements being messed up during serialization. -* Fixing a bug with hexadecimal and binary number formats. -* Fixing some other less important bugs. -* Note: Since this is pre release, there are probably some bugs but hopefully nothing totaly broken. Also this prerelease can only read scopes, not write! -# - -# SerialX 1.2.2 - -Release date: 4.11.2021 (Afternoon) - -What was added: -* Ability to serialize Scope object! -* Ability to clone Objects using Serializer! -* Ability to instantiate any object using Serializer by calling shortest public constructor! -* Now you can access Java utility from SerialX, you can invoke public static methods and fields directly from SerialX! -* SelfSerializable interface which gives you ability to serialize objects without protocol by calling public constructors! -* Static field "new" to obtain clone of variable and "class" to obtain class of variables value! -* 4 new protocols: - * MapProtocol - to serialize maps! - * ScopeProtocol (reading only) to read scopes using protocol! - * AutoProtocol - will automatically serialize selected fields with getters and setters! - * EnumProtocol - to serialize any java enum! - * SelfSerializableProtocol - operates with SelfSerializable interface! -* Tremendous writing performance boost! Large quantity writing is now up to 80x faster than in previous version. -* Eliminating usage of Regex completely which results into even faster reading! -* Now you can access variables of scopes by "." directly in SerialX! -* Fixing bug when blank characters despair from string, also now string can contains any character except quote and nextline! -* SerialX API is now partially opensource, the sources are included in main Jar, however according to the License you cant appropriate any of this code without including its origins! -# - -# SerialX 1.2.5 - -Release date: 4.11.2021 (Afternoon) - -What was added: -* Serializer can now serialize into any Appendable which includes all Writers, StringBuilder and many others which gives you a lot of opportunities! -* Serializer can now read from any CharSequence or any Reader object! -* Serializer is now fully capable of reading JSON! -* Serializer can read specific object or variable while ignoring any other stuff which saves a lot of performance (this is experimental)! -* Slight increase of reading performance! -* Utility to work with JSON like JsonScope! -* A lot of new utility in Scope object such as filtering or object transformation! -* Small bugs fixed! -# - -# SerialX 1.3.0 - -Release date: 8.8.2021 (Night) - -What was added: -* Revelation of compiler that is now Recursive descent parser that is customizable and configurable. -* Structure of entire API was generally reorganized in to 3 main sections: - * Serializer - which is main class that operates entire API. Is responsible for input and output, formatting and general utility! - * DataParser and DataConverter API - is recursive descent parser itself that is responsible for converting objects to strings and parsing them back! In default SerialX API implementation now known as JUSS (Java universal serial script) are these parsers and converters available: - * NumberConverter - for converting and parsing numbers (integers, decimals, hexa, bin)! - * BooleanConverter - for converting and parsing booleans! - * CharacterConverter - for converting and parsing chars! - * StringConverter - for converting and parsing strings ("Hello world!", "And others...")! - * NullConverter - for converting and parsing null! - * ObjectConverter - for converting and parsing SerializationProtocol expressions and Scopes! - * VariableConverter - for converting and parsing JUSS variables (Map.Entry)! - * SerializableBase64Converter - for converting and parsing Base64 expressions (java.io.Serializable)! - * ArrayConverter - for converting and parsing primitive arrays! - ## - * OperationGroups - for parsing expression groups such as (5 + 5) / 2 - * ArithmeticOperators - for parsing arithmetic expression such as 2 + 5 * 4 ** 2 - * LogicalOperators - for parsing logical expression such as true && false || true - * ComparisonOperators - for comparing objects, for instance 6 > 5 - * ConditionalAssignmentOperators - that provides ternary operator (?:) and null coalescing (??) - * NegationOperator - to negate stuff, for example !true - ## - * As mentioned. you can create your own parsers or even replace already existing ones with yours! - * SerializationProtocol API - long known protocol system for more complex objects. It contains 8 protocols as before! Now protocols are operated by ObjectConverter! -* New import system that allows you to import some class once with certain alias and then use it with that alias, similar to java! -* Too big integers are now automatically converted into long without necessarily of using L suffix! -* Small new syntax features and alot of small enhancements (shortened version of variable being initialized to scope)! -* Alot of string utility methods from Serializer become public and some were moved into converters where they are mainly used! -* Registry object which is Collection type that can store only one instance per class! -* Some new functions in Scope! -* Deprecated methods were removed! -* Source code was excluded from main jar to save space and is now available in separate src.zip file! Now on java doc files will not be provided and src.zip should be used instead! -* Small bugs fixed but there were alot of internal changes in this update so they might be another bugs so I encourage you to report any bug you encounter! -# - -# SerialX 1.3.2 - -Release date: 10.25.2021 (Morning) - -What was added: -* Serializer now abstract class which inherits Scope so now it is Scope that can serialize itself! Serialization and deserialization methods are now not static and original functionality has been split into two separated objects that inherit Serializer: - * JussSerializer - which is responsible for serializing and deserializing objects using Juss format (original functionality of Serializer). - * JsonSerializer - which is responsible for serializing and deserializing objects using Json format (successors of JsonSelxUtils) -* JsonSelxUtils was replaced with JsonSerializer that is capable of both reading and writing Json! -* Main formatting and reading algorithms can be now overridden by extending JsonSerializer, JussSerializer or Serializer! -* Ability to set multiple variables on one value, for example x = y = z = 5 -* Ability to remove multiple variables by setting them on null! -* Variables of scope are now settable from outer world, for example someScope.x = 9 -* Compare identity operator (triple equals) was added and transtype comparison logic was changed, mainly between primitive datatypes! -* Logical operators now have higher precedence over comparison operators by default! -* Logic behind operators can now be overridden by extending belonging operator DataParser! -* Adding some new utility and functionalities! -* Small syntax features (scopes now don't have to be separated with semicolon if they are in new line)! -* Package name was renamed from "ugp.org.SerialX" to "org.ugp.serialx"! -* Fixing some bugs with formatting and reading! -# - -# SerialX 1.3.5 - -Release date: imminent... - -What was added: -* Scope was split into 2 separate classes: - * GenericScope - that allows you to set generic types of keys and values. Furthermore, it can be serialized with generic types preserved! - * Scope - that you already know which poses the same functionality as before now as a child class of GenericScope! -* Imports system was redesigned and splitted into multiple separate classes, each handling some part of functionality! - * Also imports are now Serializer specific rather than global! -* Precedence of ConditionalAssignmentOperators ?: and ?? was slightly altered to closely resemble behavior of these operators in other languages. Also, these operators now can be nested without necessity of (). -* Parser API (DataParser and DataConverter) was redesigned and is now handled by ParserRegistry which can provide additional functionality such as caching to improve performance! -* Serialization syntax of Serializable objects using Base64 via SerializableBase64Converter was slightly altered to mitigate conflicts with the rest of JUSS syntax! -* New "from/into API" which is now part of the Scope that allows you to map almost any java object into a scope and any scope into corresponding java object! -* AutoProtocol is now based on "from/into API" making it more flexible! -* New UniversalObjectInstantiationProtocol that can deserialize any object by calling its constructor (something similar to ObjectClass::new)! -* SerializationProtocols now have a "mode" that can define what they can do! -* JsonSerializer will now serialize JUSS protocols as JSON objects to achieve more JSON compatibility out of the box! -* LogProvider which is now responsible for logging errors and allows you to implement your own form of logging! -* SerializationDebugger that provides ability to debug serialization and deserialization! -* New utility across API and small new functionalities and changes! -* Fixing bugs (hopefully not adding new ones): - * Long live bug with // and /* comments in strings now fixed for good (I hope...) - * Bug with wrong formatting when serializing Json in Juss and revers! - * Some other small ones! -* New examples were added! -* Source code is now also available in "dev" branch! -# diff --git a/SerialX-core/.settings/org.eclipse.core.resources.prefs b/SerialX-core/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..29abf99 --- /dev/null +++ b/SerialX-core/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/SerialX-core/pom.xml b/SerialX-core/pom.xml index d26d70a..561fa3b 100644 --- a/SerialX-core/pom.xml +++ b/SerialX-core/pom.xml @@ -3,11 +3,13 @@ org.ugp serialx - 1.3.7 + ${revision} + org.ugp.serialx core + 1.3.7 - SerialX-core + SerialX core Core of SerialX \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index 0cd2c1f..9ad062b 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -314,7 +314,7 @@ public boolean containsIndependentValue(ValT value) * @since 1.2.0 */ @SuppressWarnings("unchecked") - public V get(int valueIndex) + public V get(int valueIndex) { V obj = (V) values().get(valueIndex < 0 ? valuesCount() + valueIndex : valueIndex); return obj instanceof Serializer.NULL ? null : obj; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java b/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java index 05e85fd..008607d 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java @@ -25,16 +25,11 @@ import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.converters.DataParser.ParserRegistry; import org.ugp.serialx.converters.ObjectConverter; -import org.ugp.serialx.converters.StringConverter; import org.ugp.serialx.converters.imports.ImportConverter; -import org.ugp.serialx.converters.operators.ArithmeticOperators; -import org.ugp.serialx.converters.operators.ComparisonOperators; -import org.ugp.serialx.converters.operators.ConditionalAssignmentOperators; -import org.ugp.serialx.converters.operators.LogicalOperators; +import org.ugp.serialx.converters.imports.ImportConverter.Imports; +import org.ugp.serialx.converters.imports.ImportsProvider; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; -import javafx.beans.binding.When; - /** * This is implementation of {@link Serializer} for serializing in default SerialX API implementation known as JUSS (Java universal serial script) which is Json like domain specific language that has extended functionality! * It should generate and work with .juss or .srlx files! @@ -44,17 +39,39 @@ * @since 1.3.2 */ @SuppressWarnings("serial") -public class JussSerializer extends Serializer +public class JussSerializer extends Serializer implements ImportsProvider { - public static final ParserRegistry JUSS_PARSERS = DataParser.REGISTRY.clone(), JUSS_PARSERS_AND_OPERATORS; + /** + * {@link ParserRegistry} with all parsers required to parse JUSS! + * + * @since 1.3.2 + */ + public static final ParserRegistry JUSS_PARSERS = DataParser.REGISTRY.clone(); + + /** + * {@link ParserRegistry} with all parsers required to parse JUSS with additional operators. + *
+ * Since 1.3.7 this requires "org.ugp.serialx.converters.Operators" from SerialX "operators" modules to be present on the classpath! + * + * @since 1.3.2 + */ + public static final ParserRegistry JUSS_PARSERS_AND_OPERATORS; static { JUSS_PARSERS.add(0, new ImportConverter()); JUSS_PARSERS_AND_OPERATORS = JUSS_PARSERS.clone(); - JUSS_PARSERS_AND_OPERATORS.addAllBefore(StringConverter.class, true, new ConditionalAssignmentOperators(), new LogicalOperators(), new ComparisonOperators(), new ArithmeticOperators()); + + try + { + InvokeStaticFunc(Class.forName("org.ugp.serialx.converters.Operators"), "install", JUSS_PARSERS_AND_OPERATORS); + } + catch (Exception e) + {} } + protected Imports imports; + /** * Set this on true and program will generate comments and report!
* Note: Keep this on false to achieve the best performance! @@ -158,6 +175,14 @@ public ParserRegistry getParsers() return parsers != null ? parsers : (parsers = JUSS_PARSERS.clone()); } + @Override + public Imports getImports() + { + if (imports == null) + imports = ImportConverter.IMPORTS.clone(); + return imports; + } + /** * @param absoluteClone | If true this scope will be cloned using {@link Serializer#Clone(Object, Registry, Object[], Object...)}, if false {@link Scope#clone()}! * @@ -785,7 +810,7 @@ Obtained serializer content (return) * - * @throws When something went wrong during deserialization! + * @throws If something went wrong during deserialization! * * @since 1.3.5 */ diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Registry.java b/SerialX-core/src/main/java/org/ugp/serialx/Registry.java index ba26bc7..0681b36 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Registry.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Registry.java @@ -183,11 +183,13 @@ public void addAll(@SuppressWarnings("unchecked") Class... elms) throws Excep * @param cls | Class to find! * @param element | Element to insert before index of required class! * + * @return Index where the element was inserted. {@link Registry#indexOf(cls, false)} + * * @since 1.3.0 */ - public void addBefore(Class cls, E element) + public int addBefore(Class cls, E element) { - addBefore(cls, false, element); + return addBefore(cls, false, element); } /** @@ -195,21 +197,26 @@ public void addBefore(Class cls, E element) * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! * @param element | Element to insert before index of required class! * + * @return {@link Registry#indexOf(Class, boolean)} + * * @since 1.3.0 */ - public void addBefore(Class cls, boolean includeChildrens, E element) + public int addBefore(Class cls, boolean includeChildrens, E element) { - int index = indexOf(cls); + int index = indexOf(cls, includeChildrens); if (index <= -1) add(element); else add(index, element); + return index; } /** * @param cls | Class to find! * @param element | Element to insert after index of required class! * + * @return Index where the elements were inserted. {@link Registry#indexOf(cls, false)} + * * @since 1.3.0 */ public void addAllBefore(Class cls, @SuppressWarnings("unchecked") E... element) @@ -222,26 +229,31 @@ public void addAllBefore(Class cls, @SuppressWarnings("unchecked") * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! * @param element | Element to insert after index of required class! * + * @return {@link Registry#indexOf(Class, boolean)} + * * @since 1.3.0 */ - public void addAllBefore(Class cls, boolean includeChildrens, @SuppressWarnings("unchecked") E... element) + public int addAllBefore(Class cls, boolean includeChildrens, @SuppressWarnings("unchecked") E... element) { - int index = indexOf(cls); + int index = indexOf(cls, includeChildrens); if (index <= -1) addAll(element); else addAll(index, element); + return index; } /** * @param cls | Class to find! * @param element | Element to insert after index of required class! * + * @return Index where the element was inserted. {@link Registry#indexOf(cls, false)} + * * @since 1.3.0 */ - public void addAfter(Class cls, E element) + public int addAfter(Class cls, E element) { - addAfter(cls, false, element); + return addAfter(cls, false, element); } /** @@ -249,26 +261,31 @@ public void addAfter(Class cls, E element) * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! * @param element | Element to insert after index of required class! * + * @return {@link Registry#indexOf(Class, boolean)} + * * @since 1.3.0 */ - public void addAfter(Class cls, boolean includeChildrens, E element) + public int addAfter(Class cls, boolean includeChildrens, E element) { int index = indexOf(cls, includeChildrens); if (index <= -1) add(element); else add(index + 1, element); + return index; } /** * @param cls | Class to find! * @param element | Element to insert after index of required class! * + * @return Index where the elements were inserted. {@link Registry#indexOf(cls, false)} + * * @since 1.3.0 */ - public void addAllAfter(Class cls, @SuppressWarnings("unchecked") E... element) + public int addAllAfter(Class cls, @SuppressWarnings("unchecked") E... element) { - addAllAfter(cls, false, element); + return addAllAfter(cls, false, element); } /** @@ -276,15 +293,18 @@ public void addAllAfter(Class cls, @SuppressWarnings("unchecked") E * @param includeChildrens | If true, index of child classes of cls will be returned when object with exactly matching class is not registered! * @param element | Element to insert after index of required class! * + * @return {@link Registry#indexOf(Class, boolean)} + * * @since 1.3.0 */ - public void addAllAfter(Class cls, boolean includeChildrens, @SuppressWarnings("unchecked") E... element) + public int addAllAfter(Class cls, boolean includeChildrens, @SuppressWarnings("unchecked") E... element) { int index = indexOf(cls, includeChildrens); if (index <= -1) addAll(element); else addAll(index + 1, element); + return index; } /** diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java index baa1551..6cadf3c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java @@ -1,5 +1,7 @@ package org.ugp.serialx; +import static org.ugp.serialx.converters.DataParser.VOID; + import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.Array; @@ -10,12 +12,11 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Map.Entry; +import java.util.Objects; import java.util.function.Predicate; import org.ugp.serialx.converters.ArrayConverter; -import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.protocols.SerializationProtocol; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; @@ -295,8 +296,7 @@ public String getString(String variableName) */ public String getString(String variableName, String defaultValue) { - Object obj = get(variableName, defaultValue); - return obj == null ? null : obj.toString(); + return String.valueOf(get(variableName, defaultValue)); } /** @@ -475,8 +475,7 @@ else if (obj instanceof CharSequence) */ public String getString(int valueIndex) { - Object obj = get(valueIndex); - return obj == null ? null : obj.toString(); + return String.valueOf(get(valueIndex)); } /** @@ -1206,8 +1205,8 @@ public static T into(T obj, GenericScope fromScope, List) fromScope).get(var.getName(), DataParser.VOID); - if (varValue != DataParser.VOID) + Object varValue = ((GenericScope) fromScope).get(var.getName(), VOID); + if (varValue != VOID) var.getWriteMethod().invoke(obj, varValue); } return obj; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 6c0fe08..9bd75d3 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -40,9 +40,6 @@ import org.ugp.serialx.converters.NumberConverter; import org.ugp.serialx.converters.SerializableBase64Converter; import org.ugp.serialx.converters.StringConverter; -import org.ugp.serialx.converters.imports.ImportConverter; -import org.ugp.serialx.converters.imports.ImportConverter.Imports; -import org.ugp.serialx.converters.imports.ImportsProvider; import org.ugp.serialx.protocols.SerializationProtocol; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; @@ -56,7 +53,7 @@ * @since 1.0.0 */ @SuppressWarnings("serial") -public abstract class Serializer extends Scope implements ImportsProvider +public abstract class Serializer extends Scope { /** * Common parsers that can parse primitive datatypes! @@ -67,7 +64,6 @@ public abstract class Serializer extends Scope implements ImportsProvider protected ParserRegistry parsers; protected ProtocolRegistry protocols; - protected Imports imports; /** * @param values | Initial independent values to be added in to this scope! @@ -199,14 +195,6 @@ public T into(Object obj, String... fieldNamesToUse) throws IntrospectionExc return Serializer.into(obj, this, fieldNamesToUse); } - @Override - public Imports getImports() - { - if (imports == null) - imports = ImportConverter.IMPORTS.clone(); - return imports; - } - /** * @param name | Name of variable. * @param value | Value of variable. @@ -887,6 +875,34 @@ else if (ch == '}' || ch == ']') LogProvider.instance.logErr("Variable " + varName + " was not found!"); return null; }*/ + + /** + * @param indexWithStringValue | Index of independent value that should be string. + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @return Object that was parsed from string at given index, using parsers of this {@link Serializer}! + * + * @since 1.3.7 + */ + @SuppressWarnings("unchecked") + public T getParsed(int indexWithStringValue, Object... args) + { + return (T) getParsers().parse(getString(indexWithStringValue), args); + } + + /** + * @param variableWithStringValue | Variable name with string value. + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @return Object that was parsed from value of given variable, using parsers of this {@link Serializer}! + * + * @since 1.3.7 + */ + @SuppressWarnings("unchecked") + public T getParsed(String variableWithStringValue, Object... args) + { + return (T) getParsers().parse(getString(variableWithStringValue), args); + } /** * @param f | Source file. diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index 37738bd..d50616c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -5,7 +5,6 @@ import org.ugp.serialx.LogProvider; import org.ugp.serialx.Registry; import org.ugp.serialx.Scope; -import org.ugp.serialx.converters.operators.NegationOperator; /** * This class supposed to be used to parse strings back to java objects using {@link DataParser#parse(String, Object...)}! @@ -43,7 +42,7 @@ public interface DataParser * @since 1.3.0 */ //TODO ParserRegistry - public static final ParserRegistry REGISTRY = new ParserRegistry(new OperationGroups(), new VariableConverter(), /*new ConditionalAssignmentOperators(), new ComparisonOperators(), new LogicalOperators(), new ArithmeticOperators(),*/ new StringConverter(), new ObjectConverter(), new ArrayConverter(), new NumberConverter(), new NegationOperator(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter()); + public static final ParserRegistry REGISTRY = new ParserRegistry(new OperationGroups(), new VariableConverter(), new StringConverter(), new ObjectConverter(), new ArrayConverter(), new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter()); /** * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java index 9936c63..dc69f63 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -8,7 +8,6 @@ import java.util.Locale; import org.ugp.serialx.LogProvider; -import org.ugp.serialx.converters.operators.NegationOperator; /** * 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! @@ -106,9 +105,6 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) try { Number integer; - boolean isNeg = arg.charAt(0) == '-'; - if (isNeg) - arg = arg.substring(1); if (arg.endsWith("l")) integer = new Long(Long.parseLong(fastReplace(fastReplace(fastReplace(arg, "l", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); else if (arg.endsWith("s")) @@ -117,7 +113,7 @@ else if (arg.endsWith("y")) integer = new Byte(Byte.parseByte(fastReplace(fastReplace(arg, "y", ""), "0b", ""), arg.startsWith("0b") ? 2 : 10)); else integer = new Integer(Integer.parseInt(fastReplace(fastReplace(arg, "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); - return isNeg ? NegationOperator.negate(integer) : integer; + return integer; } catch (NumberFormatException e) { diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java index 59e55c8..02c0f90 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java @@ -299,7 +299,7 @@ else if (args.length > 0 && args[0] instanceof Serializer) StringBuilder sb = new StringBuilder(); GenericScope parent; if ((parent = serializer.getParent()) == null || serializer.getClass() != parent.getClass()) - sb.append(serializer.getImports().getAliasFor(arg.getClass()) + " "); + sb.append(ImportsProvider.getAliasFor(serializer, getClass()) + " "); return serializer.SerializeAsSubscope(sb, args); } catch (IOException e) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java index 66755ad..5ea69be 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java @@ -1,5 +1,7 @@ package org.ugp.serialx.converters.imports; +import java.lang.reflect.Type; + import org.ugp.serialx.Serializer; import org.ugp.serialx.converters.imports.ImportConverter.Imports; @@ -13,7 +15,7 @@ * * @see Import */ -public class Import implements Cloneable +public class Import implements Cloneable, Type { protected final Class cls; protected final String alias; @@ -92,6 +94,12 @@ public Import clone() return new Import(getCls(), getClsAlias(), getOwner()); } + @Override + public String getTypeName() + { + return getClsAlias(); + } + public Import clone(ImportsProvider newOwner) { return new Import(getCls(), getClsAlias(), newOwner); diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java index 47af7e3..54fab5a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java @@ -8,6 +8,13 @@ import org.ugp.serialx.GenericScope; import org.ugp.serialx.LogProvider; +/** + * ListProtocol is universal protocol to serialize any {@link Map} instance. The condition of use is public constructor with one {@link Map} argument. + * + * @author PETO + * + * @since 1.2.2 + */ public class MapProtocol extends SerializationProtocol> { @Override diff --git a/SerialX-devtools/.classpath b/SerialX-devtools/.classpath new file mode 100644 index 0000000..002ad57 --- /dev/null +++ b/SerialX-devtools/.classpath @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SerialX-devtools/.project b/SerialX-devtools/.project new file mode 100644 index 0000000..b5f340d --- /dev/null +++ b/SerialX-devtools/.project @@ -0,0 +1,23 @@ + + + SerialX-devtools + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/SerialX-devtools/.settings/org.eclipse.core.resources.prefs b/SerialX-devtools/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..29abf99 --- /dev/null +++ b/SerialX-devtools/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/SerialX-devtools/.settings/org.eclipse.jdt.core.prefs b/SerialX-devtools/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..2f5cc74 --- /dev/null +++ b/SerialX-devtools/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/SerialX-devtools/.settings/org.eclipse.m2e.core.prefs b/SerialX-devtools/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/SerialX-devtools/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/SerialX-devtools/pom.xml b/SerialX-devtools/pom.xml new file mode 100644 index 0000000..2140bc2 --- /dev/null +++ b/SerialX-devtools/pom.xml @@ -0,0 +1,23 @@ + + 4.0.0 + + org.ugp + serialx + ${revision} + + + org.ugp.serialx + devtools + 1.3.7 + + SerialX devtools + Tools for debugging... + + + + org.ugp.serialx + core + ${revision} + + + \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/SerializationDebugger.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java similarity index 63% rename from SerialX-core/src/main/java/org/ugp/serialx/SerializationDebugger.java rename to SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java index e19307c..a0f80d0 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/SerializationDebugger.java +++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java @@ -1,14 +1,14 @@ -package org.ugp.serialx; +package org.ugp.serialx.devtools; import java.util.Arrays; - import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.TreeMap; +import org.ugp.serialx.Registry; +import org.ugp.serialx.Serializer; import org.ugp.serialx.converters.DataConverter; -import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.devtools.converters.DebugParserRegistry; /** * Use this for debugging during parsing and converting by adding new instance of it into your parser {@link Registry} or in case of {@link Serializer} use !
@@ -26,11 +26,9 @@ public class SerializationDebugger implements DataConverter @Override public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { - synchronized (this) { - if (str.toLowerCase().startsWith(DEBUG_MARK)) - return printDebugs(myHomeRegistry instanceof DebugParserRegistry ? (DebugParserRegistry) myHomeRegistry : new DebugParserRegistry(myHomeRegistry), null, str, args); - return CONTINUE; - } + if (str.toLowerCase().startsWith(DEBUG_MARK)) + return printDebugs(myHomeRegistry instanceof DebugParserRegistry ? (DebugParserRegistry) myHomeRegistry : new DebugParserRegistry(myHomeRegistry), null, str, args); + return CONTINUE; } @Override @@ -72,8 +70,7 @@ public Object printDebugs(DebugParserRegistry myHomeRegistry, Object objToSerial } else if (args[99] instanceof Integer && (int) args[99] > 0) { - myHomeRegistry = myHomeRegistry.clone(); - myHomeRegistry.iterationStackTrace = new TreeMap<>(); + myHomeRegistry = myHomeRegistry.clone(false); } double t0 = System.nanoTime(); @@ -101,8 +98,7 @@ else if (args[99] instanceof Integer && (int) args[99] > 0) } else if (args[99] instanceof Integer && (int) args[99] > 0) { - myHomeRegistry = myHomeRegistry.clone(); - myHomeRegistry.iterationStackTrace = new TreeMap<>(); + myHomeRegistry = myHomeRegistry.clone(false); } double t0 = System.nanoTime(); @@ -228,7 +224,7 @@ else if (o instanceof Map) System.err.println(strTbs + entry.getKey() + ":\t" + String.valueOf(o)); } } - + /** * Use this during converting/serializing! * @@ -252,149 +248,4 @@ public DebugWrapper(Object yourObject) obj = yourObject; } } - - /** - * Special {@link ParserRegistry} that keeps track of its actions! Use only for debugging! - * - * @author PETO - * - * @since 1.3.5 - */ - public static class DebugParserRegistry extends ParserRegistry - { - /** - * - */ - private static final long serialVersionUID = 3445967263611388142L; - - protected Map iterationStackTrace = new TreeMap<>(); - - public DebugParserRegistry(ParserRegistry registry) - { - super(registry); - resetCache(registry.getParsingCache(), registry.getConverterCache()); - } - - @Override - public DebugParserRegistry clone() - { - DebugParserRegistry reg = new DebugParserRegistry(this); - reg.iterationStackTrace = this.iterationStackTrace; - return reg; - } - - @Override - public CharSequence toString(Object obj, Object... args) { - int iterationIndex = 0; - if (args.length > 99 && args[99] instanceof Integer) - { - iterationIndex = (int) args[99]; - args[99] = iterationIndex + 1; - } - - CharSequence str = null; - if (convertingCache != null) - for (int i = 0; i < convertingCache.length; i++) - { - DataParser parser = convertingCache[i]; - if (parser != null) - { - double t0 = System.nanoTime(); - str = ((DataConverter) parser).toString(this, obj, args); - double t = System.nanoTime(); - if (str != CONTINUE) - { - iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms (from cache)\n>>\t" + toStringAndCls(obj) + "\t -->\t\"" + str + "\""); - return str; - } - } - } - - for (int i = 0, size = size(); i < size; i++) - { - DataParser parser = get(i); - if (parser instanceof DataConverter) - { - double t0 = System.nanoTime(); - str = ((DataConverter) parser).toString(this, obj, args); - double t = System.nanoTime(); - if(str != CONTINUE) - { - if (convertingCache != null && i < convertingCache.length) - convertingCache[i] = parser; - iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms\n>>\t" + toStringAndCls(obj) + "\t -->\t\"" + str + "\""); - return str; - } - } - } - - LogProvider.instance.logErr(DataConverter.class.getSimpleName() + ": Unable to convert \"" + obj == null ? "null" : obj.getClass().getName() + "\" to string because none of registered converters were aplicable for this object!", null); - return null; - } - - @Override - public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ignore, Object... args) - { - int iterationIndex = 0; - if (args.length > 99 && args[99] instanceof Integer) - { - iterationIndex = (int) args[99]; - args[99] = iterationIndex + 1; - } - - Object obj = null; - if (parsingCache != null) - for (int i = 0; i < parsingCache.length; i++) - { - DataParser parser = parsingCache[i]; - if (parser != null) - { - double t0 = System.nanoTime(); - obj = parser.parse(this, str, args); - double t = System.nanoTime(); - if (obj != CONTINUE) - { - iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms (from cache)\n>>\t\"" + str + "\"\t -->\t" + toStringAndCls(obj)); - return obj; - } - } - } - - registryLoop: for (int i = 0, size = size(); i < size; i++) - { - DataParser parser = get(i); - if (ignore != null) - for (Class cls : ignore) - if (cls == parser.getClass()) - continue registryLoop; - - double t0 = System.nanoTime(); - obj = parser.parse(this, str, args); - double t = System.nanoTime(); - if (obj != CONTINUE) - { - if (parsingCache != null && i < parsingCache.length) - parsingCache[i] = parser; - iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms\n>>\t\"" + str + "\"\t -->\t" + toStringAndCls(obj)); - return obj; - } - } - - if (returnAsStringIfNotFound) - return str; - - LogProvider.instance.logErr(DataParser.class.getSimpleName() + ": Unable to parse \"" + str + "\" because none of registred parsers were suitable!", null); - return null; - } - - /** - * @return Ordered map of registry iterations generated by using it during parsing or converting! - * - * @since 1.3.5 - */ - public Map getRegistryIterationStackTrace() - { - return iterationStackTrace; - } - } } \ No newline at end of file diff --git a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java new file mode 100644 index 0000000..2ad0472 --- /dev/null +++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java @@ -0,0 +1,165 @@ +package org.ugp.serialx.devtools.converters; + +import java.util.Map; +import java.util.TreeMap; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.converters.DataConverter; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.converters.DataParser.ParserRegistry; +import org.ugp.serialx.devtools.SerializationDebugger; + +/** + * Special {@link ParserRegistry} that keeps track of its actions! Use only for debugging! + * + * @author PETO + * + * @since 1.3.5 + */ +public class DebugParserRegistry extends ParserRegistry +{ + private static final long serialVersionUID = 3445967263611388142L; + + protected Map iterationStackTrace = new TreeMap<>(); + + public DebugParserRegistry(ParserRegistry registry) + { + super(registry); + resetCache(registry.getParsingCache(), registry.getConverterCache()); + } + + @Override + public DebugParserRegistry clone() + { + return clone(true); + } + + /** + * @param copyStackTrace | If true, cloned object will share the same iterationStackTrace with original, otherwise it will get new empty one. + * + * @return Clone of this {@link DebugParserRegistry} + * + * @since 1.3.7 + */ + public DebugParserRegistry clone(boolean copyStackTrace) + { + DebugParserRegistry reg = new DebugParserRegistry(this); + if (copyStackTrace) + reg.iterationStackTrace = this.iterationStackTrace; + return reg; + } + + @Override + public CharSequence toString(Object obj, Object... args) { + int iterationIndex = 0; + if (args.length > 99 && args[99] instanceof Integer) + { + iterationIndex = (int) args[99]; + args[99] = iterationIndex + 1; + } + + CharSequence str = null; + if (convertingCache != null) + for (int i = 0; i < convertingCache.length; i++) + { + DataParser parser = convertingCache[i]; + if (parser != null) + { + double t0 = System.nanoTime(); + str = ((DataConverter) parser).toString(this, obj, args); + double t = System.nanoTime(); + if (str != SerializationDebugger.CONTINUE) + { + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms (from cache)\n>>\t" + SerializationDebugger.toStringAndCls(obj) + "\t -->\t\"" + str + "\""); + return str; + } + } + } + + for (int i = 0, size = size(); i < size; i++) + { + DataParser parser = get(i); + if (parser instanceof DataConverter) + { + double t0 = System.nanoTime(); + str = ((DataConverter) parser).toString(this, obj, args); + double t = System.nanoTime(); + if(str != SerializationDebugger.CONTINUE) + { + if (convertingCache != null && i < convertingCache.length) + convertingCache[i] = parser; + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms\n>>\t" + SerializationDebugger.toStringAndCls(obj) + "\t -->\t\"" + str + "\""); + return str; + } + } + } + + LogProvider.instance.logErr(DataConverter.class.getSimpleName() + ": Unable to convert \"" + obj == null ? "null" : obj.getClass().getName() + "\" to string because none of registered converters were aplicable for this object!", null); + return null; + } + + @Override + public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ignore, Object... args) + { + int iterationIndex = 0; + if (args.length > 99 && args[99] instanceof Integer) + { + iterationIndex = (int) args[99]; + args[99] = iterationIndex + 1; + } + + Object obj = null; + if (parsingCache != null) + for (int i = 0; i < parsingCache.length; i++) + { + DataParser parser = parsingCache[i]; + if (parser != null) + { + double t0 = System.nanoTime(); + obj = parser.parse(this, str, args); + double t = System.nanoTime(); + if (obj != SerializationDebugger.CONTINUE) + { + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms (from cache)\n>>\t\"" + str + "\"\t -->\t" + SerializationDebugger.toStringAndCls(obj)); + return obj; + } + } + } + + registryLoop: for (int i = 0, size = size(); i < size; i++) + { + DataParser parser = get(i); + if (ignore != null) + for (Class cls : ignore) + if (cls == parser.getClass()) + continue registryLoop; + + double t0 = System.nanoTime(); + obj = parser.parse(this, str, args); + double t = System.nanoTime(); + if (obj != SerializationDebugger.CONTINUE) + { + if (parsingCache != null && i < parsingCache.length) + parsingCache[i] = parser; + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms\n>>\t\"" + str + "\"\t -->\t" + SerializationDebugger.toStringAndCls(obj)); + return obj; + } + } + + if (returnAsStringIfNotFound) + return str; + + LogProvider.instance.logErr(DataParser.class.getSimpleName() + ": Unable to parse \"" + str + "\" because none of registred parsers were suitable!", null); + return null; + } + + /** + * @return Ordered map of registry iterations generated by using it during parsing or converting! + * + * @since 1.3.5 + */ + public Map getRegistryIterationStackTrace() + { + return iterationStackTrace; + } +} \ No newline at end of file diff --git a/SerialX-json/.settings/org.eclipse.core.resources.prefs b/SerialX-json/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..29abf99 --- /dev/null +++ b/SerialX-json/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/SerialX-json/pom.xml b/SerialX-json/pom.xml index 9b6b1be..bf6b4db 100644 --- a/SerialX-json/pom.xml +++ b/SerialX-json/pom.xml @@ -3,19 +3,21 @@ org.ugp serialx - 1.3.7 + ${revision} + org.ugp.serialx json + 1.3.7 - SerialX-json + SerialX json SerialX Json support org.ugp.serialx core - 1.3.7 + ${revision} \ No newline at end of file diff --git a/SerialX-operators/.classpath b/SerialX-operators/.classpath new file mode 100644 index 0000000..002ad57 --- /dev/null +++ b/SerialX-operators/.classpath @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SerialX-operators/.project b/SerialX-operators/.project new file mode 100644 index 0000000..27a03a7 --- /dev/null +++ b/SerialX-operators/.project @@ -0,0 +1,23 @@ + + + SerialX-operators + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/SerialX-operators/.settings/org.eclipse.core.resources.prefs b/SerialX-operators/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..29abf99 --- /dev/null +++ b/SerialX-operators/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/SerialX-operators/.settings/org.eclipse.jdt.core.prefs b/SerialX-operators/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..2f5cc74 --- /dev/null +++ b/SerialX-operators/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/SerialX-operators/.settings/org.eclipse.m2e.core.prefs b/SerialX-operators/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/SerialX-operators/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/SerialX-operators/pom.xml b/SerialX-operators/pom.xml new file mode 100644 index 0000000..f27574e --- /dev/null +++ b/SerialX-operators/pom.xml @@ -0,0 +1,23 @@ + + 4.0.0 + + org.ugp + serialx + ${revision} + + + org.ugp.serialx + operators + 1.3.7 + + SerialX operators + This modul contains basic operators contained in almost every programing language... + + + + org.ugp.serialx + core + ${revision} + + + \ No newline at end of file diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/Operators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/Operators.java new file mode 100644 index 0000000..64c0c9f --- /dev/null +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/Operators.java @@ -0,0 +1,69 @@ +package org.ugp.serialx.converters; + +import java.util.Arrays; + +import org.ugp.serialx.converters.DataParser.ParserRegistry; +import org.ugp.serialx.converters.operators.ArithmeticOperators; +import org.ugp.serialx.converters.operators.ComparisonOperators; +import org.ugp.serialx.converters.operators.ConditionalAssignmentOperators; +import org.ugp.serialx.converters.operators.LogicalOperators; +import org.ugp.serialx.converters.operators.NegationOperator; + +/** + * This class contains all operators that are provided by this module and it allows you to install it to your specific {@link ParserRegistry}! + * + * @see Operators#install(ParserRegistry) + * + * @since 1.3.7 + * + * @author PETO + */ +public class Operators { + + /** + * Array that contains all binary operators (operators that require 2 operands, one from left, one from right). This includes:
+ * {@link ConditionalAssignmentOperators}
+ * {@link LogicalOperators}
+ * {@link ComparisonOperators}
+ * {@link ArithmeticOperators}
+ * In given order! + * + * @since 1.3.7 + */ + public static final DataParser[] BINARY = { new ConditionalAssignmentOperators(), new LogicalOperators(), new ComparisonOperators(), new ArithmeticOperators() }; + + /** + * Array that contains all unary operators (operators that require only 1 operands, from left or right). This includes:
+ * {@link NegationOperator}
+ * In given order! + * + * @since 1.3.7 + */ + public static final DataParser[] UNARY = { new NegationOperator() }; + + /** + * @param registry | Registry to insert all operators provided by {@link Operators#BINARY} and {@link Operators#UNARY} into. This register is required to contains {@link StringConverter} and {@link BooleanConverter} in order for operators to be inserted in correct order and work in precedence they were meant to. + * + * @return The same registry with operators inserted! + * + * @since 1.3.7 + */ + public static ParserRegistry install(ParserRegistry registry) { + registry.addAllBefore(StringConverter.class, true, BINARY); + registry.addAllBefore(BooleanConverter.class, true, UNARY); + return registry; + } + + /** + * @param registry | Registry to remove all operators from! + * + * @return The same registry with no more operators! + * + * @since 1.3.7 + */ + public static ParserRegistry uninstall(ParserRegistry registry) { + registry.removeAll(Arrays.asList(BINARY)); + registry.removeAll(Arrays.asList(UNARY)); + return registry; + } +} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java similarity index 100% rename from SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java rename to SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java similarity index 100% rename from SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java rename to SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java similarity index 100% rename from SerialX-core/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java rename to SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java similarity index 99% rename from SerialX-core/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java rename to SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java index a0f8487..c8d4945 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java @@ -55,7 +55,7 @@ public Object parse(ParserRegistry myHomeRegistry, String s, Object... args) } else if (opr.equals("||")) { - cof1 = cofs.get(index); + cof1 = cofs.get(index); if (cof1 instanceof String) cof1 = myHomeRegistry.parse(cof1.toString().trim(), i > 0, new Class[] {getClass()}, args); if (cof1.equals(true)) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java similarity index 100% rename from SerialX-core/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java rename to SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java diff --git a/pom.xml b/pom.xml index c9a8d30..db0f207 100644 --- a/pom.xml +++ b/pom.xml @@ -3,12 +3,14 @@ org.ugp serialx - 1.3.7 + ${revision} pom SerialX-json SerialX-core + SerialX-devtools + SerialX-operators SerialX root @@ -37,21 +39,42 @@ https://github.com/SimplyProgrammer/ - - 1.8 - 1.8 + + 1.8 + 1.3.7 + + UTF-8 + ${java.version} + ${java.version} + serialx-${project.artifactId}-${project.version} + - org.apache.maven.plugins + org.apache.maven.plugins maven-compiler-plugin - 3.2 + 3.8.0 + - 1.8 - 1.8 + ${java.version} + ${java.version} + + eclipse + + + org.codehaus.plexus + plexus-compiler-eclipse + 2.8.8 + + + org.eclipse.jdt + ecj + 3.25.0 + + From 9357c4f79030db5379edf762db50349d9ea10b66 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Mon, 26 Jun 2023 16:07:23 +0200 Subject: [PATCH 05/48] further modularization and bug fixes --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 04f470d..a81c963 100644 --- a/.gitignore +++ b/.gitignore @@ -33,5 +33,6 @@ npm-debug.log* bin/ tmp/ .metadata +.settings target/ From 3902a4b082cac354425eda529c4e908a7c18b0a4 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Mon, 26 Jun 2023 16:08:47 +0200 Subject: [PATCH 06/48] further modularization and bug fixes --- .settings/org.eclipse.core.resources.prefs | 2 -- .settings/org.eclipse.jdt.core.prefs | 8 -------- .settings/org.eclipse.m2e.core.prefs | 4 ---- SerialX-core/.settings/org.eclipse.core.resources.prefs | 6 ------ SerialX-core/.settings/org.eclipse.jdt.core.prefs | 8 -------- SerialX-core/.settings/org.eclipse.m2e.core.prefs | 4 ---- .../.settings/org.eclipse.core.resources.prefs | 6 ------ SerialX-devtools/.settings/org.eclipse.jdt.core.prefs | 8 -------- SerialX-devtools/.settings/org.eclipse.m2e.core.prefs | 4 ---- SerialX-json/.settings/org.eclipse.core.resources.prefs | 6 ------ SerialX-json/.settings/org.eclipse.jdt.core.prefs | 8 -------- SerialX-json/.settings/org.eclipse.m2e.core.prefs | 4 ---- .../.settings/org.eclipse.core.resources.prefs | 6 ------ SerialX-operators/.settings/org.eclipse.jdt.core.prefs | 8 -------- SerialX-operators/.settings/org.eclipse.m2e.core.prefs | 4 ---- 15 files changed, 86 deletions(-) delete mode 100644 .settings/org.eclipse.core.resources.prefs delete mode 100644 .settings/org.eclipse.jdt.core.prefs delete mode 100644 .settings/org.eclipse.m2e.core.prefs delete mode 100644 SerialX-core/.settings/org.eclipse.core.resources.prefs delete mode 100644 SerialX-core/.settings/org.eclipse.jdt.core.prefs delete mode 100644 SerialX-core/.settings/org.eclipse.m2e.core.prefs delete mode 100644 SerialX-devtools/.settings/org.eclipse.core.resources.prefs delete mode 100644 SerialX-devtools/.settings/org.eclipse.jdt.core.prefs delete mode 100644 SerialX-devtools/.settings/org.eclipse.m2e.core.prefs delete mode 100644 SerialX-json/.settings/org.eclipse.core.resources.prefs delete mode 100644 SerialX-json/.settings/org.eclipse.jdt.core.prefs delete mode 100644 SerialX-json/.settings/org.eclipse.m2e.core.prefs delete mode 100644 SerialX-operators/.settings/org.eclipse.core.resources.prefs delete mode 100644 SerialX-operators/.settings/org.eclipse.jdt.core.prefs delete mode 100644 SerialX-operators/.settings/org.eclipse.m2e.core.prefs diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 99f26c0..0000000 --- a/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,2 +0,0 @@ -eclipse.preferences.version=1 -encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 2f5cc74..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,8 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore -org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/SerialX-core/.settings/org.eclipse.core.resources.prefs b/SerialX-core/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 29abf99..0000000 --- a/SerialX-core/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,6 +0,0 @@ -eclipse.preferences.version=1 -encoding//src/main/java=UTF-8 -encoding//src/main/resources=UTF-8 -encoding//src/test/java=UTF-8 -encoding//src/test/resources=UTF-8 -encoding/=UTF-8 diff --git a/SerialX-core/.settings/org.eclipse.jdt.core.prefs b/SerialX-core/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 2f5cc74..0000000 --- a/SerialX-core/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,8 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore -org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.8 diff --git a/SerialX-core/.settings/org.eclipse.m2e.core.prefs b/SerialX-core/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/SerialX-core/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/SerialX-devtools/.settings/org.eclipse.core.resources.prefs b/SerialX-devtools/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 29abf99..0000000 --- a/SerialX-devtools/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,6 +0,0 @@ -eclipse.preferences.version=1 -encoding//src/main/java=UTF-8 -encoding//src/main/resources=UTF-8 -encoding//src/test/java=UTF-8 -encoding//src/test/resources=UTF-8 -encoding/=UTF-8 diff --git a/SerialX-devtools/.settings/org.eclipse.jdt.core.prefs b/SerialX-devtools/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 2f5cc74..0000000 --- a/SerialX-devtools/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,8 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore -org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.8 diff --git a/SerialX-devtools/.settings/org.eclipse.m2e.core.prefs b/SerialX-devtools/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/SerialX-devtools/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/SerialX-json/.settings/org.eclipse.core.resources.prefs b/SerialX-json/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 29abf99..0000000 --- a/SerialX-json/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,6 +0,0 @@ -eclipse.preferences.version=1 -encoding//src/main/java=UTF-8 -encoding//src/main/resources=UTF-8 -encoding//src/test/java=UTF-8 -encoding//src/test/resources=UTF-8 -encoding/=UTF-8 diff --git a/SerialX-json/.settings/org.eclipse.jdt.core.prefs b/SerialX-json/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 2f5cc74..0000000 --- a/SerialX-json/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,8 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore -org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.8 diff --git a/SerialX-json/.settings/org.eclipse.m2e.core.prefs b/SerialX-json/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/SerialX-json/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/SerialX-operators/.settings/org.eclipse.core.resources.prefs b/SerialX-operators/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 29abf99..0000000 --- a/SerialX-operators/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,6 +0,0 @@ -eclipse.preferences.version=1 -encoding//src/main/java=UTF-8 -encoding//src/main/resources=UTF-8 -encoding//src/test/java=UTF-8 -encoding//src/test/resources=UTF-8 -encoding/=UTF-8 diff --git a/SerialX-operators/.settings/org.eclipse.jdt.core.prefs b/SerialX-operators/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 2f5cc74..0000000 --- a/SerialX-operators/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,8 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore -org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.8 diff --git a/SerialX-operators/.settings/org.eclipse.m2e.core.prefs b/SerialX-operators/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/SerialX-operators/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 From ced013115755c62b688b6932c9c9e2b6c1ece160 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 18 Jul 2023 22:43:32 +0200 Subject: [PATCH 07/48] ... --- .classpath | 9 - .gitignore | 2 + .project | 23 - SerialX-core/.classpath | 38 - SerialX-core/.project | 23 - .../java/org/ugp/serialx/GenericScope.java | 17 +- .../java/org/ugp/serialx/JussSerializer.java | 12 +- .../src/main/java/org/ugp/serialx/Scope.java | 3 +- .../main/java/org/ugp/serialx/Serializer.java | 783 +---------------- .../src/main/java/org/ugp/serialx/Utils.java | 806 ++++++++++++++++++ .../serialx/converters/ArrayConverter.java | 24 +- .../serialx/converters/BooleanConverter.java | 6 +- .../converters/CharacterConverter.java | 7 +- .../ugp/serialx/converters/DataParser.java | 1 - .../ugp/serialx/converters/NullConverter.java | 4 +- .../serialx/converters/NumberConverter.java | 109 ++- .../serialx/converters/ObjectConverter.java | 16 +- .../serialx/converters/OperationGroups.java | 2 +- .../serialx/converters/StringConverter.java | 4 +- .../serialx/converters/VariableConverter.java | 14 +- .../ugp/serialx/protocols/AutoProtocol.java | 3 +- .../UniversalObjectInstantiationProtocol.java | 4 +- SerialX-devtools/.classpath | 38 - SerialX-devtools/.project | 23 - .../devtools/SerializationDebugger.java | 8 +- SerialX-json/.classpath | 38 - SerialX-json/.project | 23 - .../org/ugp/serialx/json/JsonSerializer.java | 14 +- .../json/converters/JsonNumberConverter.java | 2 +- SerialX-juss/pom.xml | 15 + SerialX-operators/.classpath | 38 - SerialX-operators/.project | 23 - .../operators/ArithmeticOperators.java | 12 +- .../operators/ComparisonOperators.java | 2 +- .../ConditionalAssignmentOperators.java | 4 +- .../operators/LogicalOperators.java | 2 +- pom.xml | 4 +- 37 files changed, 974 insertions(+), 1182 deletions(-) delete mode 100644 .classpath delete mode 100644 .project delete mode 100644 SerialX-core/.classpath delete mode 100644 SerialX-core/.project create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/Utils.java delete mode 100644 SerialX-devtools/.classpath delete mode 100644 SerialX-devtools/.project delete mode 100644 SerialX-json/.classpath delete mode 100644 SerialX-json/.project create mode 100644 SerialX-juss/pom.xml delete mode 100644 SerialX-operators/.classpath delete mode 100644 SerialX-operators/.project diff --git a/.classpath b/.classpath deleted file mode 100644 index bd36355..0000000 --- a/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/.gitignore b/.gitignore index a81c963..2957f58 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,8 @@ npm-debug.log* bin/ tmp/ .metadata +.classpath .settings +.project target/ diff --git a/.project b/.project deleted file mode 100644 index fd37aa3..0000000 --- a/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - SerialXDev - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - diff --git a/SerialX-core/.classpath b/SerialX-core/.classpath deleted file mode 100644 index 002ad57..0000000 --- a/SerialX-core/.classpath +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SerialX-core/.project b/SerialX-core/.project deleted file mode 100644 index 75fcc6c..0000000 --- a/SerialX-core/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - SerialX-core - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index 9ad062b..bdb25df 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -1,5 +1,7 @@ package org.ugp.serialx; +import static org.ugp.serialx.Utils.Instantiate; + import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; @@ -14,6 +16,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.ugp.serialx.Utils.NULL; import org.ugp.serialx.converters.ArrayConverter; import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.protocols.SerializationProtocol; @@ -146,7 +149,7 @@ public GenericScope clone() @SuppressWarnings("unchecked") public > S clone(Class typeOfClone) throws Exception { - S clone = Serializer.Instantiate(typeOfClone); + S clone = Instantiate(typeOfClone); clone.values = (List) toValList(); clone.variables = (Map) toVarMap(); clone.parent = getParent(); @@ -167,7 +170,7 @@ public > S clone(Class typeOfClone) throws if (getClass() == newType) return (S) this; - GenericScope clone = (GenericScope) Serializer.Instantiate(newType); + GenericScope clone = (GenericScope) Instantiate(newType); clone.values = (List) values(); clone.variables = (Map) variables(); clone.parent = getParent(); @@ -275,7 +278,7 @@ public V get(KeyT variableKey, V defaultValue) V obj = (V) variables().get(variableKey); if (obj == null) return (V) defaultValue; - return obj instanceof Serializer.NULL ? null : obj; + return obj instanceof NULL ? null : obj; } /** @@ -317,7 +320,7 @@ public boolean containsIndependentValue(ValT value) public V get(int valueIndex) { V obj = (V) values().get(valueIndex < 0 ? valuesCount() + valueIndex : valueIndex); - return obj instanceof Serializer.NULL ? null : obj; + return obj instanceof NULL ? null : obj; } /** @@ -524,7 +527,7 @@ public GenericScope transform(Function trans, boolean incl try { Object obj = ent.getValue(); - obj = obj instanceof Serializer.NULL ? null : obj; + obj = obj instanceof NULL ? null : obj; if (obj instanceof GenericScope && includeSubScopes) { GenericScope sc = ((GenericScope) obj).transform(trans, includeSubScopes); @@ -539,7 +542,7 @@ else if ((obj = trans.apply((ValT) obj)) != DataParser.VOID) try { - GenericScope clone = Serializer.Instantiate(getClass()); + GenericScope clone = Instantiate(getClass()); clone.values = fltVals; clone.variables = fltVars; clone.parent = getParent(); @@ -580,7 +583,7 @@ public List map(Function trans, boolean includeSubScopes) for (Object obj : this) try { - obj = obj instanceof Serializer.NULL ? null : obj; + obj = obj instanceof NULL ? null : obj; if (obj instanceof GenericScope && includeSubScopes) { GenericScope sc = ((GenericScope) obj).transform(trans, includeSubScopes); diff --git a/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java b/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java index 008607d..7cb815e 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java @@ -1,5 +1,9 @@ package org.ugp.serialx; +import static org.ugp.serialx.Utils.Clone; +import static org.ugp.serialx.Utils.InvokeStaticFunc; +import static org.ugp.serialx.Utils.indexOfNotInObj; +import static org.ugp.serialx.Utils.multilpy; import static org.ugp.serialx.converters.DataParser.VOID; import java.beans.IntrospectionException; @@ -21,6 +25,7 @@ import java.util.Map; import java.util.Map.Entry; +import org.ugp.serialx.Utils.NULL; import org.ugp.serialx.converters.DataConverter; import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.converters.DataParser.ParserRegistry; @@ -38,6 +43,7 @@ * * @since 1.3.2 */ +//TODO: Separate to SerialX-juss together with parsers and stuff @SuppressWarnings("serial") public class JussSerializer extends Serializer implements ImportsProvider { @@ -483,7 +489,7 @@ else if (ch == '}' || ch == ']') else for (Map.Entry ent : parent.varEntrySet()) if (variables().get(ent.getKey()) == ent.getValue()) - variables().remove(ent.getKey()); + variables().remove(ent.getKey());//TODO: Prevent neccesity of scope parent inheritance. return (S) this; } @@ -695,7 +701,7 @@ public T cloneOf(String variableName , T defaultValue) T obj = get(variableName , defaultValue); if (obj == defaultValue) return defaultValue; - return Serializer.Clone(obj, getParsers(), new Object[] {-99999, 0, this, getProtocols(), isGenerateComments()}, this, null, null, getProtocols()); + return Clone(obj, getParsers(), new Object[] {-99999, 0, this, getProtocols(), isGenerateComments()}, this, null, null, getProtocols()); } /** @@ -711,7 +717,7 @@ public T cloneOf(String variableName , T defaultValue) public T cloneOf(int valueIndex) { T obj = get(valueIndex); - return Serializer.Clone(obj, getParsers(), new Object[] {-99999, 0, this, getProtocols(), isGenerateComments()}, this, null, null, getProtocols()); + return Clone(obj, getParsers(), new Object[] {-99999, 0, this, getProtocols(), isGenerateComments()}, this, null, null, getProtocols()); } /** diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java index 6cadf3c..61c5839 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java @@ -1,5 +1,6 @@ package org.ugp.serialx; +import static org.ugp.serialx.Utils.Instantiate; import static org.ugp.serialx.converters.DataParser.VOID; import java.beans.IntrospectionException; @@ -1100,7 +1101,7 @@ public static T intoNew(Class objCls, GenericScope fromScope, } } - return into(Serializer.Instantiate(objCls), fromScope, fieldNamesToUse); + return into(Instantiate(objCls), fromScope, fieldNamesToUse); } /** diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 9bd75d3..ccae28e 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -1,10 +1,12 @@ package org.ugp.serialx; -import static org.ugp.serialx.converters.DataParser.VOID; +import static org.ugp.serialx.Utils.Instantiate; +import static org.ugp.serialx.Utils.indexOfNotInObj; +import static org.ugp.serialx.Utils.multilpy; +import static org.ugp.serialx.Utils.post; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; -import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; @@ -17,23 +19,17 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.io.StringReader; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; -import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.Map; import java.util.function.Function; import org.ugp.serialx.converters.BooleanConverter; import org.ugp.serialx.converters.CharacterConverter; -import org.ugp.serialx.converters.DataConverter; import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.converters.DataParser.ParserRegistry; import org.ugp.serialx.converters.NullConverter; @@ -903,713 +899,6 @@ public T getParsed(String variableWithStringValue, Object... args) { return (T) getParsers().parse(getString(variableWithStringValue), args); } - - /** - * @param f | Source file. - * - * @return All lines from source file as string. - * @throws IOException - * - * @since 1.1.5 - */ - public static String LoadFileToString(File f) throws IOException - { - return LoadFileToString(f, 1); - } - - /** - * @param f | Source file. - * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
- * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! - * - * @return Content of file as string. - * @throws IOException - * - * @since 1.2.0 - */ - public static String LoadFileToString(File f, int endlMode) throws IOException - { - return StreamToString(new FileReader(f), endlMode); - } - - /** - * @param input | Input stream to read to string! - * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
- * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! - * - * @return Reader converted to string form! - * - * @throws IOException - * - * @since 1.3.5 - */ - public static String StreamToString(InputStream input, int endlMode) throws IOException - { - return StreamToString(new InputStreamReader(input), endlMode); - } - - /** - * @param input | Input reader! - * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
- * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! - * - * @return Reader converted to string form! - * - * @throws IOException - * - * @since 1.3.2 - */ - public static String StreamToString(Reader input, int endlMode) throws IOException - { - String l; - StringBuilder sb = new StringBuilder(); - - BufferedReader r = new BufferedReader(input); - while ((l = r.readLine()) != null) - { - sb.append(l); - if (endlMode == 1 || (endlMode > 1 && l.contains("//"))) - sb.append("\n"); - } - r.close(); - return sb.toString(); - } - - /** - * @param cls | Class to invoke method from. - * @param name | Name of public static method to be called. - * @param args | Arguments of method. Arguments should be certain if method is overloaded! - * - * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. - * - * @throws InvocationTargetException if called method throws and exception while calling! - * - * @since 1.2.2 - */ - public static Object InvokeStaticFunc(Class cls, String name, Object... args) throws InvocationTargetException - { - return InvokeFunc(null, cls, name, args); - } - - /** - * @param obj | The object the underlying method is invoked from! - * @param name | Name of public static method to be called. - * @param args | Arguments of method. Arguments should be certain if method is overloaded! - * - * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. - * - * @throws InvocationTargetException if called method throws and exception while calling! - * - * @since 1.3.5 - */ - public static Object InvokeFunc(Object obj, String name, Object... args) throws InvocationTargetException - { - return InvokeFunc(obj, obj.getClass(), name, args); - } - - /** - * @param obj | The object the underlying method is invoked from! - * @param cls | Class to invoke method from. - * @param name | Name of public static method to be called. - * @param args | Arguments of method. Arguments should be certain if method is overloaded! - * - * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. - * - * @throws InvocationTargetException if called method throws and exception while calling! - * - * @since 1.3.5 - */ - public static Object InvokeFunc(Object obj, Class objCls, String name, Object... args) throws InvocationTargetException - { - Object result = InvokeFunc(obj, objCls, name, ToClasses(args), args); - if (result != null) - return result; - result = InvokeFunc(obj, objCls, name, ToClasses(false, args), args); - if (result == null) - LogProvider.instance.logErr("Unable to call function \"" + name + "\" because inserted arguments " + Arrays.asList(args) + " cannot be applied or function does not exist in required class!", null); - return result; - } - - /** - * @param obj | The object the underlying method is invoked from! - * @param cls | Class to invoke method from. - * @param name | Name of public static method to be called. - * @param argClasses | Classes of args. - * @param args | Arguments of method. Arguments should be certain if method is overloaded! - * - * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. - * - * @throws InvocationTargetException if called method throws and exception while calling! - * - * @since 1.3.5 - */ - public static Object InvokeFunc(Object obj, Class objCls, String name, Class[] argClasses, Object... args) throws InvocationTargetException - { - try - { - Method method = objCls.getMethod(name, argClasses); - Object resualt = method.invoke(obj, args); - return method.getReturnType().equals(void.class) ? VOID : resualt; - } - catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException find) - { - for (Method method : objCls.getMethods()) - if (method.getName().equals(name)) - try - { - Object resualt = method.invoke(obj, args); - return method.getReturnType().equals(void.class) ? VOID : resualt; - } - catch (IllegalArgumentException e) - {} - catch (SecurityException | IllegalAccessException ex) - { - ex.printStackTrace(); - } - } - return null; - } - - - //Syntactical analyzes and fast string utility: - - /** - * @param obj | Object to clone. - * - * @return Cloned object using {@link DataParser}, {@link DataConverter} and {@link SerializationProtocol} or the same object as inserted one if cloning is not possible, for instance when protocol was not found and object is not instance of {@link Cloneable}. - * This clone function will always prioritized the Protocol variation, regular cloning is used only when there is no protocol registered or exception occurs.
- * Note: If there are protocols to serialize inserted object and all its sub-objects and variables then this clone will be absolute deep copy, meaning that making any changes to this cloned object or to its variables will not affect original one in any way! - * But keep in mind that this clone is absolute hoverer, based on protocols used, it does not need to be an 100% copy! - * - * @since 1.2.2 - */ - public static T Clone(T obj) - { - return Clone(obj, DataParser.REGISTRY, new Object[] {}, new Scope()); - } - - /** - * @param obj | Object to clone. - * @param - * @param converterArgs | Argument for {@link DataConverter#objToString(Registry, Object, Object...)}! - * @param parserArgs | Arguments for {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)}! - * - * @return Cloned object using {@link DataParser}, {@link DataConverter} and {@link SerializationProtocol} or the same object as inserted one if cloning is not possible, for instance when protocol was not found and object is not instance of {@link Cloneable}. - * This clone function will always prioritized the Protocol variation, regular cloning is used only when there is no protocol registered or exception occurs.
- * Note: If there are protocols to serialize inserted object and all its sub-objects and variables then this clone will be absolute deep copy, meaning that making any changes to this cloned object or to its variables will not affect original one in any way! - * But keep in mind that this clone is absolute hoverer, based on protocols used, it does not need to be an 100% copy! - * - * @since 1.3.2 - */ - @SuppressWarnings("unchecked") - public static T Clone(T obj, Registry parsersToUse, Object[] converterArgs, Object... parserArgs) - { - if (obj == null) - return obj; - else if (obj.getClass() == Byte.class) - return (T) new Byte((byte) obj); - else if (obj.getClass() == Short.class) - return (T) new Short((short) obj); - else if (obj.getClass() == Integer.class) - return (T) new Integer((int) obj); - else if (obj.getClass() == Long.class) - return (T) new Long((long) obj); - else if (obj.getClass() == Float.class) - return (T) new Float((float) obj); - else if (obj.getClass() == Double.class) - return (T) new Double((double) obj); - else if (obj.getClass() == Character.class) - return (T) new Character((char) obj); - else if (obj.getClass() == Boolean.class) - return (T) new Boolean((boolean) obj); - else if (obj.getClass() == String.class) - return (T) new String((String) obj); - else - { - ParserRegistry parsers = parsersToUse instanceof ParserRegistry ? (ParserRegistry) parsersToUse : new ParserRegistry(parsersToUse); - - Object cln = NULL.toOopNull(parsers.parse(parsers.toString(obj, converterArgs).toString(), parserArgs)); - if (cln != null && cln != VOID) - return (T) cln; - - if (obj instanceof Cloneable) - { - try - { - Method method = Object.class.getDeclaredMethod("clone"); - method.setAccessible(true); - return (T) method.invoke(obj); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } - LogProvider.instance.logErr("Unable to clone " + obj.getClass() + ": " + obj, null); - return obj; - } - } - - /** - * @param cls | Class to instantiate. - * - * @return New blank instance of required class created by calling shortest public constructor with default values!
- * Note: Do not use this when your class contains final fields! - * - * @throws NoSuchMethodException if there is no public constructor! - * @throws InvocationTargetException if called constructor throws and exception! - * - * @since 1.2.2 - */ - public static T Instantiate(Class cls) throws NoSuchMethodException, InvocationTargetException - { - return Instantiate(cls, true); - } - - /** - * @param cls | Class to instantiate. - * @param publicOnly | If true, only public constructors will be used to create the object! - * - * @return New blank instance of required class created by calling shortest constructor with default values!
- * Note: Do not use this when your class contains final fields! - * - * @throws NoSuchMethodException if there is no public constructor! - * @throws InvocationTargetException if called constructor throws and exception! - * - * @since 1.3.2 - */ - @SuppressWarnings("unchecked") - public static T Instantiate(Class cls, boolean publicOnly) throws NoSuchMethodException, InvocationTargetException - { - try - { - Constructor cons = publicOnly ? cls.getConstructor() : cls.getDeclaredConstructor(); - if (!publicOnly) - cons.setAccessible(true); - return cons.newInstance(); - } - catch (Exception e) - { - try - { - Constructor[] cnstrs = publicOnly ? cls.getConstructors() : cls.getDeclaredConstructors(); - if (cnstrs.length <= 0) - throw new NoSuchMethodException("No public constructors in class " + cls.getName() + "!"); - - for (int i = 1; i < cnstrs.length; i++) - { - if (!publicOnly) - cnstrs[0].setAccessible(true); - if (cnstrs[i].getParameterCount() < cnstrs[0].getParameterCount()) - cnstrs[0] = cnstrs[i]; - } - - Object[] args = new Object[cnstrs[0].getParameterCount()]; - Class[] argTypes = cnstrs[0].getParameterTypes(); - for (int i = 0; i < cnstrs[0].getParameterCount(); i++) - { - if (argTypes[i] == byte.class) - args[i] = (byte) 0; - else if (argTypes[i] == short.class) - args[i] = (short) 0; - else if (argTypes[i] == int.class) - args[i] = 0; - else if (argTypes[i] == long.class) - args[i] = 0l; - else if ( argTypes[i] == float.class) - args[i] = 0.0f; - else if (argTypes[i] == double.class) - args[i] = 0.0; - else if (argTypes[i] == char.class) - args[i] = (char) 0; - else if (argTypes[i] == boolean.class) - args[i] = false; - else if (argTypes[i] == String.class) - args[i] = ""; - else - args[i] = null; - } - return (T) cnstrs[0].newInstance(args); - } - catch (InstantiationException | IllegalAccessException | IllegalArgumentException | SecurityException e2) - { - e2.printStackTrace(); - } - } - return null; - } - - /** - * @param objs | Array of objects. - * - * @return Array of inserted objects class types. Wrapper types of primitive values will be converted to primitive types! For instance: Integer.class -> int.class - * - * @since 1.2.2 - */ - public static Class[] ToClasses(Object... objs) - { - return ToClasses(true, objs); - } - - /** - * @param objs | Array of objects. - * - * @return Array of inserted objects class types. Wrapper types of primitive values will be converted to primitive types! For instance: Integer.class -> int.class - * - * @since 1.3.5 - */ - public static Class[] ToClasses(boolean unwrapp, Object... objs) - { - Class[] classes = new Class[objs.length]; - if (unwrapp) - { - for (int i = 0; i < classes.length; i++) - { - if (objs[i] == null) - classes[i] = Object.class; - else if (objs[i].getClass() == Byte.class || objs[i] == Byte.class) - classes[i] = byte.class; - else if (objs[i].getClass() == Short.class || objs[i] == Short.class) - classes[i] = short.class; - else if (objs[i].getClass() == Integer.class || objs[i] == Integer.class) - classes[i] = int.class; - else if (objs[i].getClass() == Long.class || objs[i] == Long.class) - classes[i] = long.class; - else if (objs[i].getClass() == Float.class || objs[i] == Float.class) - classes[i] = float.class; - else if (objs[i].getClass() == Double.class || objs[i] == Double.class) - classes[i] = double.class; - else if (objs[i].getClass() == Character.class || objs[i] == Character.class) - classes[i] = char.class; - else if (objs[i].getClass() == Boolean.class || objs[i] == Boolean.class) - classes[i] = boolean.class; - else if (objs[i] instanceof Class) - classes[i] = (Class) objs[i]; - else - classes[i] = objs[i].getClass(); - } - - return classes; - } - - for (int i = 0; i < classes.length; i++) - classes[i] = objs[i].getClass(); - return classes; - } - - /** - * @param ch | String to multiply! - * @param times | Count of multiplication! - * - * @return Multiplied char, for example multilpy('a', 5) will return "aaaaa"; - * - * @since 1.3.2 - */ - public static StringBuilder multilpy(char ch, int times) - { - StringBuilder sb = new StringBuilder(); - while (times-- > 0) - sb.append(ch); - return sb; - } - - /** - * @param ch | String to multiply! - * @param str | Count of multiplication! - * - * @return Multiplied char, for example multilpy("a", 5) will return "aaaaa"; - * - * @since 1.3.0 - */ - public static StringBuilder multilpy(CharSequence str, int times) - { - StringBuilder sb = new StringBuilder(str); - while (times-- > 1) - sb.append(str); - return sb; - } - - /** - * @param s | String to split and check some syntax. - * @param splitter | Chars where string will be split! - * - * @return String splitted after splitters. If there is more than one splitter in row, it will be taken as one whole! - * - * @since 1.0.0 - */ - public static String[] splitValues(String s, char... splitter) - { - return splitValues(s, 0, true, splitter); - } - - /** - * @param s | String to split and check some syntax. - * @param limit | If 0 or less = no limit, 1 = no splitting, more than 1 = count of results! - * @param oneOrMore | If true, string will be splitted after one or more splitters in row, if false splitting will occur only after single splitter (this is similar to "+" in regex)! - * @param splitter | Chars where string will be split! - * - * @return String splitted after splitters according to arguments. If there is more than one splitter in row, it will be taken as one whole! - * - * @since 1.3.0 - */ - public static String[] splitValues(String s, int limit, boolean splitAfterSingleCharOnly, char... splitter) - { - return splitValues(s, limit, splitAfterSingleCharOnly, new char[0], splitter); - } - - /** - * @param s | String to split and check some syntax. - * @param limit | If 0 or less = no limit, 1 = no splitting, more than 1 = count of results! - * @param oneOrMore | If true, string will be splitted after one or more splitters in row, if false splitting will occur only after single splitter (this is similar to "+" in regex)! - * @param splitBreaks | When some of these characters is encountered, splitting is terminated for the rest of the string! - * @param splitter | Chars where string will be split! - * - * @return String splitted after splitters according to arguments. If there is more than one splitter in row, it will be taken as one whole! - * - * @since 1.3.5 - */ - public static String[] splitValues(String s, int limit, boolean oneOrMore, char[] splitBreaks, char... splitter) - { - if (splitter.length <= 0 || limit == 1) - return new String[] {s}; -// -// if (isOneOf(s.charAt(0), splitter)) -// return splitValues(" "+s, limit, oneOrMore, splitBreaks, splitter); - - List result = new ArrayList<>(); - - int brackets = 0, quote = 0, lastIndex = 0; - for (int i = 0, count = 1, len = s.length(), oldCh = splitter[0]; i < len && (limit <= 0 || count < limit); i++) - { - char ch = s.charAt(i); - if (ch == '"') - quote++; - - if (quote % 2 == 0) - { - if (isOneOf(ch, splitBreaks)) - { - brackets = quote = 0; - break; - } - - if (brackets == 0 && oldCh != ch && isOneOf(ch, splitter) && (oneOrMore || (i >= len-1 || !isOneOf(s.charAt(i+1), splitter)))) - { - result.add(s.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i).trim()); - count++; - } - else if (ch == '{' || ch == '[') - brackets++; - else if (ch == '}' || ch == ']') - { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing opening bracket in: " + s); - } - } - oldCh = ch; - } - - if (brackets > 0) - throw new IllegalArgumentException("Unclosed brackets in: " + s); - else if (quote % 2 != 0) - throw new IllegalArgumentException("Unclosed or missing quotes in: " + s); - else - { - result.add(s.substring(lastIndex == 0 ? 0 : lastIndex + 1, s.length()).trim()); - } - - return result.toArray(new String[0]); - } - - /** - * @param s | CharSequence to search! - * @param oneOf | Characters to find! - * - * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! - * - * @since 1.3.0 - */ - public static int indexOfNotInObj(CharSequence s, char... oneOf) - { - return indexOfNotInObj(s, true, oneOf); - } - - /** - * @param s | CharSequence to search! - * @param firstIndex | If true, first index will be returned, if false last index will be returned. - * @param oneOf | Characters to find! - * - * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! - * - * @since 1.3.5 - */ - public static int indexOfNotInObj(CharSequence s, boolean firstIndex, char... oneOf) - { - int found = -1; - for (int i = 0, brackets = 0, quote = 0, len = s.length(); i < len; i++) - { - char ch = s.charAt(i); - if (ch == '"') - quote++; - - if (quote % 2 == 0) - { - if (brackets == 0 && /*oneOf.length == 0 ? ch == oneOf[0] :*/ isOneOf(ch, oneOf)) - { - found = i; - if (firstIndex) - return found; - } - else if (ch == '{' || ch == '[') - brackets++; - else if (ch == '}' || ch == ']') - { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing closing bracket in: " + s); - } - } - } - return found; - } - - /** - * @param s | CharSequence to search! - * @param sequenceToFind | CharSequence to find! - * - * @return Index of first found CharSequence that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! - * - * @since 1.3.0 - */ - public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind) - { - return indexOfNotInObj(s, sequenceToFind, true); - } - - /** - * @param s | CharSequence to search! - * @param sequenceToFind | CharSequence to find! - * @param firstIndex | If true, first index will be returned, if false last index will be returned. - * - * @return Index of first found CharSequence that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! - * - * @since 1.3.5 - */ - public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind, boolean firstIndex) - { - int found = -1; - for (int i = 0, brackets = 0, quote = 0, match = 0, len = s.length(), lenToFind = sequenceToFind.length(); i < len; i++) - { - char ch = s.charAt(i); - if (ch == '"') - quote++; - - if (quote % 2 == 0) - { - if (brackets == 0 && ch == sequenceToFind.charAt(match++)) - { - if (match == lenToFind) - { - found = i - match + 1; - if (firstIndex) - return found; - match = 0; - } - } - else if (ch == '{' || ch == '[') - brackets++; - else if (ch == '}' || ch == ']') - { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing closing bracket in: " + s); - } - else - match = 0; - } - } - return found; - } - - /** - * @param str | String to do replacements in! - * @param target | Target to replace! - * @param replacement | Replacement for target! - * - * @return Inserted string after replacing all targets with replacements similar to {@link String#replace(CharSequence, CharSequence)} but faster! - * - * @since 1.2.0 - */ - public static String fastReplace(String str, String target, CharSequence replacement) - { - int targetLength = target.length(); - if (targetLength == 0) - return str; - - int i1 = 0, i2 = str.indexOf(target); - if (i2 < 0) - return str; - - StringBuilder sb = new StringBuilder(targetLength > replacement.length() ? str.length() : str.length() * 2); - do - { - sb.append(str, i1, i2).append(replacement); - i1 = i2 + targetLength; - i2 = str.indexOf(target, i1); - } while (i2 > 0); - - return sb.append(str, i1, str.length()).toString(); - } - - /** - * @param ch | Char to compare! - * @param chars | Chars to match! - * - * @return True if inserted char is any of inserted chars! - * - * @since 1.3.0 - */ - public static boolean isOneOf(int ch, char... chars) - { - if (chars.length > 0) - { - for (int i = 0, len = chars.length; i < len; i++) - if (chars[i] == ch) - return true; - } - return false; - } - - /** - * @return {@link String#contains(CharSequence)} for char sequence! - * - * @since 1.3.0 - */ - public static boolean contains(CharSequence str, char... oneOf) - { - for (int i = 0, len = str.length(); i < len; i++) - if (isOneOf(str.charAt(i), oneOf)) - return true; - return false; - } - - /** - * @param str | String to display! - * @param pos | Position to display! - * - * @return String with displayed position! - * Use for debugging or error printing! - * - * @since 1.3.2 - */ - public static String showPosInString(CharSequence str, int pos) - { - return str + "\n" + multilpy(' ', pos) + "^"; - } /** * @param obj | Object to map the serializer variables into! @@ -1829,68 +1118,4 @@ public static Serializer from(Serializer newInstance, Object fromObj, String... newInstance.addAll(Scope.from(fromObj, fieldNamesToUse)); return newInstance; } - - /** - * This will serialize serializer into http query post request however this is not the best networking and you should implement your own http client if you want SerialX to serialize and deserialize remote content! - * - * @param serializer | Serializer to post. - * @param conn | Http connection to use! - * - * @throws IOException if posting failed! - * - * @since 1.3.5 - */ - public static void post(Serializer serializer, HttpURLConnection conn) throws IOException - { - StringBuilder postData = new StringBuilder(); - for (Map.Entry param : serializer.varEntrySet()) - { - if (postData.length() != 0) - postData.append('&'); - postData.append(URLEncoder.encode(param.getKey(), "UTF-8")).append('='); - postData.append(URLEncoder.encode(serializer.getParsers().toString(param.getValue()).toString(), "UTF-8")); - } - - for (Object param : serializer) - { - if (postData.length() != 0) - postData.append('&'); - postData.append(URLEncoder.encode(serializer.getParsers().toString(param).toString(), "UTF-8")); - } - - byte[] postDataBytes = postData.toString().getBytes("UTF-8"); - conn.setRequestMethod("POST"); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); - conn.setDoOutput(true); - conn.getOutputStream().write(postDataBytes); - } - - /** - * This is a "dummy" class that {@link Serializer} uses internally as an OOP programmatic interpretation of null. In otherwise this is wrapper object for null. - * Note: You should not be able to come in contact with this during serialization and loading, if you did then you most likely encountered and bug and you should report it! - * - * @author PETO - * - * @since 1.2.2 - */ - public static final class NULL - { - public static Object toOopNull(Object obj) - { - return obj == null ? new NULL() : obj; - } - - @Override - public boolean equals(Object obj) - { - return obj == null || obj instanceof NULL; - } - - @Override - public String toString() - { - return "null"; - } - } } \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java new file mode 100644 index 0000000..a9b8d48 --- /dev/null +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -0,0 +1,806 @@ +package org.ugp.serialx; + +import static org.ugp.serialx.converters.DataParser.VOID; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.ugp.serialx.converters.DataConverter; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.converters.DataParser.ParserRegistry; +import org.ugp.serialx.protocols.SerializationProtocol; + + +public class Utils { + private Utils() {} + + /** + * @param f | Source file. + * + * @return All lines from source file as string. + * @throws IOException + * + * @since 1.1.5 + */ + public static String LoadFileToString(File f) throws IOException + { + return LoadFileToString(f, 1); + } + + /** + * @param f | Source file. + * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
+ * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! + * + * @return Content of file as string. + * @throws IOException + * + * @since 1.2.0 + */ + public static String LoadFileToString(File f, int endlMode) throws IOException + { + return StreamToString(new FileReader(f), endlMode); + } + + /** + * @param input | Input stream to read to string! + * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
+ * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! + * + * @return Reader converted to string form! + * + * @throws IOException + * + * @since 1.3.5 + */ + public static String StreamToString(InputStream input, int endlMode) throws IOException + { + return StreamToString(new InputStreamReader(input), endlMode); + } + + /** + * @param input | Input reader! + * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
+ * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! + * + * @return Reader converted to string form! + * + * @throws IOException + * + * @since 1.3.2 + */ + public static String StreamToString(Reader input, int endlMode) throws IOException + { + String l; + StringBuilder sb = new StringBuilder(); + + BufferedReader r = new BufferedReader(input); + while ((l = r.readLine()) != null) + { + sb.append(l); + if (endlMode == 1 || (endlMode > 1 && l.contains("//"))) + sb.append("\n"); + } + r.close(); + return sb.toString(); + } + + /** + * @param cls | Class to invoke method from. + * @param name | Name of public static method to be called. + * @param args | Arguments of method. Arguments should be certain if method is overloaded! + * + * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * + * @throws InvocationTargetException if called method throws and exception while calling! + * + * @since 1.2.2 + */ + public static Object InvokeStaticFunc(Class cls, String name, Object... args) throws InvocationTargetException + { + return InvokeFunc(null, cls, name, args); + } + + /** + * @param obj | The object the underlying method is invoked from! + * @param name | Name of public static method to be called. + * @param args | Arguments of method. Arguments should be certain if method is overloaded! + * + * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * + * @throws InvocationTargetException if called method throws and exception while calling! + * + * @since 1.3.5 + */ + public static Object InvokeFunc(Object obj, String name, Object... args) throws InvocationTargetException + { + return InvokeFunc(obj, obj.getClass(), name, args); + } + + /** + * @param obj | The object the underlying method is invoked from! + * @param cls | Class to invoke method from. + * @param name | Name of public static method to be called. + * @param args | Arguments of method. Arguments should be certain if method is overloaded! + * + * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * + * @throws InvocationTargetException if called method throws and exception while calling! + * + * @since 1.3.5 + */ + public static Object InvokeFunc(Object obj, Class objCls, String name, Object... args) throws InvocationTargetException + { + Object result = InvokeFunc(obj, objCls, name, ToClasses(args), args); + if (result != null) + return result; + result = InvokeFunc(obj, objCls, name, ToClasses(false, args), args); + if (result == null) + LogProvider.instance.logErr("Unable to call function \"" + name + "\" because inserted arguments " + Arrays.asList(args) + " cannot be applied or function does not exist in required class!", null); + return result; + } + + /** + * @param obj | The object the underlying method is invoked from! + * @param cls | Class to invoke method from. + * @param name | Name of public static method to be called. + * @param argClasses | Classes of args. + * @param args | Arguments of method. Arguments should be certain if method is overloaded! + * + * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * + * @throws InvocationTargetException if called method throws and exception while calling! + * + * @since 1.3.5 + */ + public static Object InvokeFunc(Object obj, Class objCls, String name, Class[] argClasses, Object... args) throws InvocationTargetException + { + try + { + Method method = objCls.getMethod(name, argClasses); + Object resualt = method.invoke(obj, args); + return method.getReturnType().equals(void.class) ? VOID : resualt; + } + catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException find) + { + for (Method method : objCls.getMethods()) + if (method.getName().equals(name)) + try + { + Object resualt = method.invoke(obj, args); + return method.getReturnType().equals(void.class) ? VOID : resualt; + } + catch (IllegalArgumentException e) + {} + catch (SecurityException | IllegalAccessException ex) + { + ex.printStackTrace(); + } + } + return null; + } + + + //Syntactical analyzes and fast string utility: + + /** + * @param obj | Object to clone. + * + * @return Cloned object using {@link DataParser}, {@link DataConverter} and {@link SerializationProtocol} or the same object as inserted one if cloning is not possible, for instance when protocol was not found and object is not instance of {@link Cloneable}. + * This clone function will always prioritized the Protocol variation, regular cloning is used only when there is no protocol registered or exception occurs.
+ * Note: If there are protocols to serialize inserted object and all its sub-objects and variables then this clone will be absolute deep copy, meaning that making any changes to this cloned object or to its variables will not affect original one in any way! + * But keep in mind that this clone is absolute hoverer, based on protocols used, it does not need to be an 100% copy! + * + * @since 1.2.2 + */ + public static T Clone(T obj) + { + return Clone(obj, DataParser.REGISTRY, new Object[] {}, new Scope()); + } + + /** + * @param obj | Object to clone. + * @param + * @param converterArgs | Argument for {@link DataConverter#objToString(Registry, Object, Object...)}! + * @param parserArgs | Arguments for {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)}! + * + * @return Cloned object using {@link DataParser}, {@link DataConverter} and {@link SerializationProtocol} or the same object as inserted one if cloning is not possible, for instance when protocol was not found and object is not instance of {@link Cloneable}. + * This clone function will always prioritized the Protocol variation, regular cloning is used only when there is no protocol registered or exception occurs.
+ * Note: If there are protocols to serialize inserted object and all its sub-objects and variables then this clone will be absolute deep copy, meaning that making any changes to this cloned object or to its variables will not affect original one in any way! + * But keep in mind that this clone is absolute hoverer, based on protocols used, it does not need to be an 100% copy! + * + * @since 1.3.2 + */ + @SuppressWarnings("unchecked") + public static T Clone(T obj, Registry parsersToUse, Object[] converterArgs, Object... parserArgs) + { + if (obj == null) + return obj; + else if (obj.getClass() == Byte.class) + return (T) new Byte((byte) obj); + else if (obj.getClass() == Short.class) + return (T) new Short((short) obj); + else if (obj.getClass() == Integer.class) + return (T) new Integer((int) obj); + else if (obj.getClass() == Long.class) + return (T) new Long((long) obj); + else if (obj.getClass() == Float.class) + return (T) new Float((float) obj); + else if (obj.getClass() == Double.class) + return (T) new Double((double) obj); + else if (obj.getClass() == Character.class) + return (T) new Character((char) obj); + else if (obj.getClass() == Boolean.class) + return (T) new Boolean((boolean) obj); + else if (obj.getClass() == String.class) + return (T) new String((String) obj); + else + { + ParserRegistry parsers = parsersToUse instanceof ParserRegistry ? (ParserRegistry) parsersToUse : new ParserRegistry(parsersToUse); + + Object cln = NULL.toOopNull(parsers.parse(parsers.toString(obj, converterArgs).toString(), parserArgs)); + if (cln != null && cln != VOID) + return (T) cln; + + if (obj instanceof Cloneable) + { + try + { + Method method = Object.class.getDeclaredMethod("clone"); + method.setAccessible(true); + return (T) method.invoke(obj); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + LogProvider.instance.logErr("Unable to clone " + obj.getClass() + ": " + obj, null); + return obj; + } + } + + /** + * @param cls | Class to instantiate. + * + * @return New blank instance of required class created by calling shortest public constructor with default values!
+ * Note: Do not use this when your class contains final fields! + * + * @throws NoSuchMethodException if there is no public constructor! + * @throws InvocationTargetException if called constructor throws and exception! + * + * @since 1.2.2 + */ + public static T Instantiate(Class cls) throws NoSuchMethodException, InvocationTargetException + { + return Instantiate(cls, true); + } + + /** + * @param cls | Class to instantiate. + * @param publicOnly | If true, only public constructors will be used to create the object! + * + * @return New blank instance of required class created by calling shortest constructor with default values!
+ * Note: Do not use this when your class contains final fields! + * + * @throws NoSuchMethodException if there is no public constructor! + * @throws InvocationTargetException if called constructor throws and exception! + * + * @since 1.3.2 + */ + @SuppressWarnings("unchecked") + public static T Instantiate(Class cls, boolean publicOnly) throws NoSuchMethodException, InvocationTargetException + { + try + { + Constructor cons = publicOnly ? cls.getConstructor() : cls.getDeclaredConstructor(); + if (!publicOnly) + cons.setAccessible(true); + return cons.newInstance(); + } + catch (Exception e) + { + try + { + Constructor[] cnstrs = publicOnly ? cls.getConstructors() : cls.getDeclaredConstructors(); + if (cnstrs.length <= 0) + throw new NoSuchMethodException("No public constructors in class " + cls.getName() + "!"); + + for (int i = 1; i < cnstrs.length; i++) + { + if (!publicOnly) + cnstrs[0].setAccessible(true); + if (cnstrs[i].getParameterCount() < cnstrs[0].getParameterCount()) + cnstrs[0] = cnstrs[i]; + } + + Object[] args = new Object[cnstrs[0].getParameterCount()]; + Class[] argTypes = cnstrs[0].getParameterTypes(); + for (int i = 0; i < cnstrs[0].getParameterCount(); i++) + { + if (argTypes[i] == byte.class) + args[i] = (byte) 0; + else if (argTypes[i] == short.class) + args[i] = (short) 0; + else if (argTypes[i] == int.class) + args[i] = 0; + else if (argTypes[i] == long.class) + args[i] = 0l; + else if ( argTypes[i] == float.class) + args[i] = 0.0f; + else if (argTypes[i] == double.class) + args[i] = 0.0; + else if (argTypes[i] == char.class) + args[i] = (char) 0; + else if (argTypes[i] == boolean.class) + args[i] = false; + else if (argTypes[i] == String.class) + args[i] = ""; + else + args[i] = null; + } + return (T) cnstrs[0].newInstance(args); + } + catch (InstantiationException | IllegalAccessException | IllegalArgumentException | SecurityException e2) + { + e2.printStackTrace(); + } + } + return null; + } + + /** + * @param objs | Array of objects. + * + * @return Array of inserted objects class types. Wrapper types of primitive values will be converted to primitive types! For instance: Integer.class -> int.class + * + * @since 1.2.2 + */ + public static Class[] ToClasses(Object... objs) + { + return ToClasses(true, objs); + } + + /** + * @param objs | Array of objects. + * + * @return Array of inserted objects class types. Wrapper types of primitive values will be converted to primitive types! For instance: Integer.class -> int.class + * + * @since 1.3.5 + */ + public static Class[] ToClasses(boolean unwrapp, Object... objs) + { + Class[] classes = new Class[objs.length]; + if (unwrapp) + { + for (int i = 0; i < classes.length; i++) + { + if (objs[i] == null) + classes[i] = Object.class; + else if (objs[i].getClass() == Byte.class || objs[i] == Byte.class) + classes[i] = byte.class; + else if (objs[i].getClass() == Short.class || objs[i] == Short.class) + classes[i] = short.class; + else if (objs[i].getClass() == Integer.class || objs[i] == Integer.class) + classes[i] = int.class; + else if (objs[i].getClass() == Long.class || objs[i] == Long.class) + classes[i] = long.class; + else if (objs[i].getClass() == Float.class || objs[i] == Float.class) + classes[i] = float.class; + else if (objs[i].getClass() == Double.class || objs[i] == Double.class) + classes[i] = double.class; + else if (objs[i].getClass() == Character.class || objs[i] == Character.class) + classes[i] = char.class; + else if (objs[i].getClass() == Boolean.class || objs[i] == Boolean.class) + classes[i] = boolean.class; + else if (objs[i] instanceof Class) + classes[i] = (Class) objs[i]; + else + classes[i] = objs[i].getClass(); + } + + return classes; + } + + for (int i = 0; i < classes.length; i++) + classes[i] = objs[i].getClass(); + return classes; + } + + /** + * @param ch | String to multiply! + * @param times | Count of multiplication! + * + * @return Multiplied char, for example multilpy('a', 5) will return "aaaaa"; + * + * @since 1.3.2 + */ + public static StringBuilder multilpy(char ch, int times) + { + StringBuilder sb = new StringBuilder(); + while (times-- > 0) + sb.append(ch); + return sb; + } + + /** + * @param ch | String to multiply! + * @param str | Count of multiplication! + * + * @return Multiplied char, for example multilpy("a", 5) will return "aaaaa"; + * + * @since 1.3.0 + */ + public static StringBuilder multilpy(CharSequence str, int times) + { + StringBuilder sb = new StringBuilder(str); + while (times-- > 1) + sb.append(str); + return sb; + } + + /** + * @param s | String to split and check some syntax. + * @param splitter | Chars where string will be split! + * + * @return String splitted after splitters. If there is more than one splitter in row, it will be taken as one whole! + * + * @since 1.0.0 + */ + public static String[] splitValues(String s, char... splitter) + { + return splitValues(s, 0, true, splitter); + } + + /** + * @param s | String to split and check some syntax. + * @param limit | If 0 or less = no limit, 1 = no splitting, more than 1 = count of results! + * @param oneOrMore | If true, string will be splitted after one or more splitters in row, if false splitting will occur only after single splitter (this is similar to "+" in regex)! + * @param splitter | Chars where string will be split! + * + * @return String splitted after splitters according to arguments. If there is more than one splitter in row, it will be taken as one whole! + * + * @since 1.3.0 + */ + public static String[] splitValues(String s, int limit, boolean splitAfterSingleCharOnly, char... splitter) + { + return splitValues(s, limit, splitAfterSingleCharOnly, new char[0], splitter); + } + + /** + * @param s | String to split and check some syntax. + * @param limit | If 0 or less = no limit, 1 = no splitting, more than 1 = count of results! + * @param oneOrMore | If true, string will be splitted after one or more splitters in row, if false splitting will occur only after single splitter (this is similar to "+" in regex)! + * @param splitBreaks | When some of these characters is encountered, splitting is terminated for the rest of the string! + * @param splitter | Chars where string will be split! + * + * @return String splitted after splitters according to arguments. If there is more than one splitter in row, it will be taken as one whole! + * + * @since 1.3.5 + */ + public static String[] splitValues(String s, int limit, boolean oneOrMore, char[] splitBreaks, char... splitter) + { + if (splitter.length <= 0 || limit == 1) + return new String[] {s}; +// +// if (isOneOf(s.charAt(0), splitter)) +// return splitValues(" "+s, limit, oneOrMore, splitBreaks, splitter); + + List result = new ArrayList<>(); + + int brackets = 0, quote = 0, lastIndex = 0; + for (int i = 0, count = 1, len = s.length(), oldCh = splitter[0]; i < len && (limit <= 0 || count < limit); i++) + { + char ch = s.charAt(i); + if (ch == '"') + quote++; + + if (quote % 2 == 0) + { + if (isOneOf(ch, splitBreaks)) + { + brackets = quote = 0; + break; + } + + if (brackets == 0 && oldCh != ch && isOneOf(ch, splitter) && (oneOrMore || (i >= len-1 || !isOneOf(s.charAt(i+1), splitter)))) + { + result.add(s.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i).trim()); + count++; + } + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing opening bracket in: " + s); + } + } + oldCh = ch; + } + + if (brackets > 0) + throw new IllegalArgumentException("Unclosed brackets in: " + s); + else if (quote % 2 != 0) + throw new IllegalArgumentException("Unclosed or missing quotes in: " + s); + else + { + result.add(s.substring(lastIndex == 0 ? 0 : lastIndex + 1, s.length()).trim()); + } + + return result.toArray(new String[0]); + } + + /** + * @param s | CharSequence to search! + * @param oneOf | Characters to find! + * + * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! + * + * @since 1.3.0 + */ + public static int indexOfNotInObj(CharSequence s, char... oneOf) + { + return indexOfNotInObj(s, true, oneOf); + } + + /** + * @param s | CharSequence to search! + * @param firstIndex | If true, first index will be returned, if false last index will be returned. + * @param oneOf | Characters to find! + * + * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! + * + * @since 1.3.5 + */ + public static int indexOfNotInObj(CharSequence s, boolean firstIndex, char... oneOf) + { + int found = -1; + for (int i = 0, brackets = 0, quote = 0, len = s.length(); i < len; i++) + { + char ch = s.charAt(i); + if (ch == '"') + quote++; + + if (quote % 2 == 0) + { + if (brackets == 0 && /*oneOf.length == 0 ? ch == oneOf[0] :*/ isOneOf(ch, oneOf)) + { + found = i; + if (firstIndex) + return found; + } + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing closing bracket in: " + s); + } + } + } + return found; + } + + /** + * @param s | CharSequence to search! + * @param sequenceToFind | CharSequence to find! + * + * @return Index of first found CharSequence that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! + * + * @since 1.3.0 + */ + public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind) + { + return indexOfNotInObj(s, sequenceToFind, true); + } + + /** + * @param s | CharSequence to search! + * @param sequenceToFind | CharSequence to find! + * @param firstIndex | If true, first index will be returned, if false last index will be returned. + * + * @return Index of first found CharSequence that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! + * + * @since 1.3.5 + */ + public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind, boolean firstIndex) + { + int found = -1; + for (int i = 0, brackets = 0, quote = 0, match = 0, len = s.length(), lenToFind = sequenceToFind.length(); i < len; i++) + { + char ch = s.charAt(i); + if (ch == '"') + quote++; + + if (quote % 2 == 0) + { + if (brackets == 0 && ch == sequenceToFind.charAt(match++)) + { + if (match == lenToFind) + { + found = i - match + 1; + if (firstIndex) + return found; + match = 0; + } + } + else if (ch == '{' || ch == '[') + brackets++; + else if (ch == '}' || ch == ']') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing closing bracket in: " + s); + } + else + match = 0; + } + } + return found; + } + + /** + * @param str | String to do replacements in! + * @param target | Target to replace! + * @param replacement | Replacement for target! + * + * @return Inserted string after replacing all targets with replacements similar to {@link String#replace(CharSequence, CharSequence)} but faster! + * + * @since 1.2.0 + */ + public static String fastReplace(String str, String target, CharSequence replacement) + { + int targetLength = target.length(); + if (targetLength == 0) + return str; + + int i1 = 0, i2 = str.indexOf(target); + if (i2 < 0) + return str; + + StringBuilder sb = new StringBuilder(targetLength > replacement.length() ? str.length() : str.length() * 2); + do + { + sb.append(str, i1, i2).append(replacement); + i1 = i2 + targetLength; + i2 = str.indexOf(target, i1); + } while (i2 > 0); + + return sb.append(str, i1, str.length()).toString(); + } + + /** + * @param ch | Char to compare! + * @param chars | Chars to match! + * + * @return True if inserted char is any of inserted chars! + * + * @since 1.3.0 + */ + public static boolean isOneOf(int ch, char... chars) + { + if (chars.length > 0) + { + for (int i = 0, len = chars.length; i < len; i++) + if (chars[i] == ch) + return true; + } + return false; + } + + /** + * @return {@link String#contains(CharSequence)} for char sequence! + * + * @since 1.3.0 + */ + public static boolean contains(CharSequence str, char... oneOf) + { + if (oneOf.length == 1) + for (int i = 0, len = str.length(); i < len; i++) + if (str.charAt(i) == oneOf[0]) + return true; + + for (int i = 0, len = str.length(); i < len; i++) + if (isOneOf(str.charAt(i), oneOf)) + return true; + return false; + } + + /** + * @param str | String to display! + * @param pos | Position to display! + * + * @return String with displayed position! + * Use for debugging or error printing! + * + * @since 1.3.2 + */ + public static String showPosInString(CharSequence str, int pos) + { + return str + "\n" + multilpy(' ', pos) + "^"; + } + + /** + * This will serialize serializer into http query post request however this is not the best networking and you should implement your own http client if you want SerialX to serialize and deserialize remote content! + * + * @param serializer | Serializer to post. + * @param conn | Http connection to use! + * + * @throws IOException if posting failed! + * + * @since 1.3.5 + */ + public static void post(Serializer serializer, HttpURLConnection conn) throws IOException + { + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : serializer.varEntrySet()) + { + if (postData.length() != 0) + postData.append('&'); + postData.append(URLEncoder.encode(param.getKey(), "UTF-8")).append('='); + postData.append(URLEncoder.encode(serializer.getParsers().toString(param.getValue()).toString(), "UTF-8")); + } + + for (Object param : serializer) + { + if (postData.length() != 0) + postData.append('&'); + postData.append(URLEncoder.encode(serializer.getParsers().toString(param).toString(), "UTF-8")); + } + + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + conn.setDoOutput(true); + conn.getOutputStream().write(postDataBytes); + } + + /** + * This is a "dummy" class that {@link Serializer} uses internally as an OOP programmatic interpretation of null. In otherwise this is wrapper object for null. + * Note: You should not be able to come in contact with this during serialization and loading, if you did then you most likely encountered and bug and you should report it! + * + * @author PETO + * + * @since 1.2.2 + */ + public static final class NULL + { + public static Object toOopNull(Object obj) + { + return obj == null ? new NULL() : obj; + } + + @Override + public boolean equals(Object obj) + { + return obj == null || obj instanceof NULL; + } + + @Override + public String toString() + { + return "null"; + } + } +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java index ab77cc0..45e756a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java @@ -1,12 +1,14 @@ package org.ugp.serialx.converters; -import static org.ugp.serialx.Serializer.ToClasses; -import static org.ugp.serialx.Serializer.indexOfNotInObj; -import static org.ugp.serialx.Serializer.splitValues; +import static org.ugp.serialx.Utils.ToClasses; +import static org.ugp.serialx.Utils.indexOfNotInObj; +import static org.ugp.serialx.Utils.splitValues; import java.lang.reflect.Array; import java.util.Arrays; +import org.ugp.serialx.converters.imports.ImportsProvider; + /** * This converter is capable of converting primitive arrays. * Its case sensitive! @@ -99,10 +101,11 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object.. if (args.length > 2) args[2] = index + 1; + Object[] elms = fromAmbiguous(obj); StringBuilder sb = new StringBuilder(); - for (int i = 0, length = Array.getLength(obj), sizeEndl = 10000; i < length; i++) + for (int i = 0, length = elms.length, sizeEndl = 10000; i < length; i++) { - CharSequence str = myHomeRegistry.toString(Array.get(obj, i), args); + CharSequence str = myHomeRegistry.toString(elms[i], args); char ch = str.charAt(0); if (ch == '{' || ch == '[') sb.append("("+str+")"); @@ -182,7 +185,7 @@ public static Object[] mergeArrays(Object arr1, Object arr2) /** * @param array | Object that might be array! * - * @return Object transformed in to primitive array! + * @return Object transformed in to primitive array! If array is already an instance of primitive array then it will be simply returned! * * @throws IllegalArgumentException if the specified object is not an array! * @@ -190,9 +193,12 @@ public static Object[] mergeArrays(Object arr1, Object arr2) */ public static Object[] fromAmbiguous(Object array) { - int len1 = Array.getLength(array); - Object[] arr = new Object[len1]; - for (int i = 0; i < len1; i++) + if (array instanceof Object[]) + return (Object[]) array; + + int len = Array.getLength(array); + Object[] arr = new Object[len]; + for (int i = 0; i < len; i++) arr[i] = Array.get(array, i); return arr; } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java index 094c4be..871a2c4 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java @@ -54,11 +54,11 @@ public BooleanConverter(boolean shorten) } @Override - public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) + public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) { - if (arg.equalsIgnoreCase("t") || arg.equalsIgnoreCase("true")) + if (arg.equalsIgnoreCase("T") || arg.equalsIgnoreCase("true")) return new Boolean(true); - else if (arg.equalsIgnoreCase("f") || arg.equalsIgnoreCase("false")) + if (arg.equalsIgnoreCase("F") || arg.equalsIgnoreCase("false")) return new Boolean(false); return CONTINUE; } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java index 90c775b..3db9a41 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java @@ -1,6 +1,6 @@ package org.ugp.serialx.converters; -import static org.ugp.serialx.Serializer.fastReplace; +import static org.ugp.serialx.Utils.fastReplace; /** * This converter is capable of converting {@link Character}. @@ -41,10 +41,9 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) if (str.length() > 1 && str.charAt(0) == '\'' && str.charAt(str.length()-1) == '\'') try { - if (str.equals("''")) + if (str.equals("''")) // TODO: str.length() == 2 + mby cache len return new Character(' '); - else - return new Character((char) Integer.parseInt(str = fastReplace(str, "'", ""))); + return new Character((char) Integer.parseInt(str = fastReplace(str, "'", ""))); } catch (Exception e) { diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index d50616c..1eee489 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -41,7 +41,6 @@ public interface DataParser * * @since 1.3.0 */ - //TODO ParserRegistry public static final ParserRegistry REGISTRY = new ParserRegistry(new OperationGroups(), new VariableConverter(), new StringConverter(), new ObjectConverter(), new ArrayConverter(), new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter()); /** diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java index ce04a67..1d772b3 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java @@ -1,6 +1,6 @@ package org.ugp.serialx.converters; -import org.ugp.serialx.Serializer.NULL; +import org.ugp.serialx.Utils.NULL; /** * This converter is capable of converting "nothing" otherwise known as null and {@link DataParser#VOID}. @@ -40,7 +40,7 @@ public Object parse(ParserRegistry registry, String str, Object... args) { if (str.equalsIgnoreCase("null")) return null; - else if (str.equalsIgnoreCase("void")) + if (str.equalsIgnoreCase("void")) return VOID; return CONTINUE; } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java index dc69f63..68b0d6c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -1,7 +1,7 @@ package org.ugp.serialx.converters; -import static org.ugp.serialx.Serializer.contains; -import static org.ugp.serialx.Serializer.fastReplace; +import static org.ugp.serialx.Utils.contains; +import static org.ugp.serialx.Utils.fastReplace; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; @@ -80,8 +80,11 @@ public class NumberConverter implements DataConverter * Set this on null and decimal numbers will not be formated! Do this when you need accuracy! * * @serial 1.1.0 (moved to {@link NumberConverter} since 1.3.0) + * + * @deprecated DO NOT USE! Override {@link NumberConverter#format(Object)} and write your format logic there instead! */ - protected DecimalFormat decimalFormatter = new DecimalFormat("#.###", DecimalFormatSymbols.getInstance(Locale.US)); + @Deprecated + public static DecimalFormat decimalFormatter = new DecimalFormat("#.###", DecimalFormatSymbols.getInstance(Locale.US)); @Override public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) @@ -91,43 +94,42 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) char ch = arg.charAt(0); if (ch == '+' || ch == '-' || ch == '.' || (ch >= '0' && ch <= '9')) { - arg = formatNum(arg.toLowerCase()); - if (arg.equals(".")) + arg = normFormatNum(arg.toLowerCase()); + ch = arg.charAt(arg.length()-1); //ch = last char + + if (ch == '.') return CONTINUE; - if (contains(arg, '.') || (!arg.startsWith("0x") && arg.endsWith("f") || arg.endsWith("d"))) + if (contains(arg, '.') || (!arg.startsWith("0x") && ch == 'f' || ch == 'd')) { - if (arg.endsWith("f")) + if (ch == 'f') return new Float(fastReplace(arg, "f", "")); - else - return new Double(fastReplace(arg, "d", "")); + return new Double(fastReplace(arg, "d", "")); + } + + try + { + // TODO: Use decode method instead of this mess if possible... + if (ch == 'l') + return new Long(Long.parseLong(fastReplace(fastReplace(fastReplace(arg, "l", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); + if (ch == 's') + return new Short(Short.parseShort(fastReplace(fastReplace(fastReplace(arg, "s", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); + if (ch == 'y') + return new Byte(Byte.parseByte(fastReplace(fastReplace(arg, "y", ""), "0b", ""), arg.startsWith("0b") ? 2 : 10)); + return new Integer(Integer.parseInt(fastReplace(fastReplace(arg, "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); + } + catch (NumberFormatException e) + { + if (arg.matches("[0-9.]+")) + try + { + return new Long(Long.parseLong(fastReplace(fastReplace(fastReplace(arg, "l", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); + } + catch (NumberFormatException e2) + { + LogProvider.instance.logErr("Number " + arg + " is too big for its datatype! Try to change its datatype to double (suffix D)!", e2); + return null; + } } - else - try - { - Number integer; - if (arg.endsWith("l")) - integer = new Long(Long.parseLong(fastReplace(fastReplace(fastReplace(arg, "l", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); - else if (arg.endsWith("s")) - integer = new Short(Short.parseShort(fastReplace(fastReplace(fastReplace(arg, "s", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); - else if (arg.endsWith("y")) - integer = new Byte(Byte.parseByte(fastReplace(fastReplace(arg, "y", ""), "0b", ""), arg.startsWith("0b") ? 2 : 10)); - else - integer = new Integer(Integer.parseInt(fastReplace(fastReplace(arg, "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); - return integer; - } - catch (NumberFormatException e) - { - if (arg.matches("[0-9.]+")) - try - { - return new Long(Long.parseLong(fastReplace(fastReplace(fastReplace(arg, "l", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); - } - catch (NumberFormatException e2) - { - LogProvider.instance.logErr("Number " + arg + " is too big for its datatype! Try to change its datatype to double (suffix D)!", e2); - return null; - } - } } } return CONTINUE; @@ -138,17 +140,17 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object.. { if (obj instanceof Number) { - String str = decimalFormatter != null ? decimalFormatter.format(obj) : obj.toString(); - if (!contains(str, '.') && obj instanceof Double) - str += "D"; + StringBuilder str = new StringBuilder(format((Number) obj)); + if (obj instanceof Double && !contains(str, '.')) + str.append('D'); else if (obj instanceof Float) - str += "F"; + str.append('F'); else if (obj instanceof Long) - str += "L"; - if (obj instanceof Short) - str += "S"; + str.append('L'); + else if (obj instanceof Short) + str.append('S'); else if (obj instanceof Byte) - str += "Y"; + str.append('Y'); return str; } return CONTINUE; @@ -161,22 +163,15 @@ public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Ob } /** - * @return {@link DecimalFormat} to format decimal numbers (double, float) during serialization or null if there is none! - * Value of {@link NumberConverter#decimalFormatter} + * @param num | Number to format before converting it to string by this converter! * - * @since 1.3.7 - */ - public DecimalFormat getDecimalFormatter() { - return decimalFormatter; - } - - /** - * @param decimalFormatter | New {@link DecimalFormat} to set for formating decimal numbers (double, float)! + * @return Number formated to string! * * @since 1.3.7 */ - public void setDecimalFormatter(DecimalFormat decimalFormatter) { - this.decimalFormatter = decimalFormatter; + public String format(Number num) + { + return num.toString(); } /** @@ -186,7 +181,7 @@ public void setDecimalFormatter(DecimalFormat decimalFormatter) { * * @since 1.3.0 */ - public static String formatNum(String num) + public static String normFormatNum(String num) { if (num.length() > 2) for (boolean minus = num.startsWith("+-") || num.startsWith("-+"); minus || num.startsWith("++") || num.startsWith("--"); minus = num.startsWith("+-") || num.startsWith("-+")) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java index 02c0f90..021a6b0 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java @@ -1,9 +1,10 @@ package org.ugp.serialx.converters; -import static org.ugp.serialx.Serializer.InvokeStaticFunc; -import static org.ugp.serialx.Serializer.indexOfNotInObj; -import static org.ugp.serialx.Serializer.isOneOf; -import static org.ugp.serialx.Serializer.splitValues; +import static org.ugp.serialx.Utils.Instantiate; +import static org.ugp.serialx.Utils.InvokeStaticFunc; +import static org.ugp.serialx.Utils.indexOfNotInObj; +import static org.ugp.serialx.Utils.isOneOf; +import static org.ugp.serialx.Utils.splitValues; import java.io.IOException; import java.io.Serializable; @@ -83,7 +84,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... compile if (str.length() > 0 && ((hasOp = (ch = str.charAt(0)) == '{' || ch == '[') && (hasCls = (ch = str.charAt(str.length()-1)) == '}' || ch == ']') /*|| containsNotInObj(str, ' ')*/ || (objectClass = getProtocolExprClass(str, compilerArgs)) != null)) { - if (objectClass != null) + if (objectClass != null) //TODO: Preferably separate this to ProtocolConverter { if (objectClass == IsSelectorScope.class) { @@ -121,7 +122,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... compile try { compilerArgs[4] = oldObjectClass; - return clsAttr[1].equals("class") ? objectClass : clsAttr[1].equals("new") ? Serializer.Instantiate(objectClass) : objectClass.getField(clsAttr[1]).get(null); + return clsAttr[1].equals("class") ? objectClass : clsAttr[1].equals("new") ? Instantiate(objectClass) : objectClass.getField(clsAttr[1]).get(null); } catch (NoSuchFieldException e) { @@ -208,6 +209,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... compile { compilerArgs = compilerArgs.clone(); compilerArgs[0] = false; + //TODO: Prevent neccesity of scope parent inheritance. return ((Serializer) scope.inheritParent()).LoadFrom(new StringReader(str), compilerArgs); } @@ -307,7 +309,7 @@ else if (args.length > 0 && args[0] instanceof Serializer) throw new RuntimeException(e); } } - else + else //TODO: Preferably separate this to ProtocolConverter { if (preferedProtocol != null || (preferedProtocol = (SerializationProtocol) getProtocolFor(arg, SerializationProtocol.MODE_SERIALIZE, args)) != null) { diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java index 161f254..8374a40 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java @@ -1,6 +1,6 @@ package org.ugp.serialx.converters; -import static org.ugp.serialx.Serializer.isOneOf; +import static org.ugp.serialx.Utils.isOneOf; import java.util.Arrays; import java.util.HashMap; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java index 206dd48..33984bb 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java @@ -1,7 +1,7 @@ package org.ugp.serialx.converters; -import static org.ugp.serialx.Serializer.contains; -import static org.ugp.serialx.Serializer.indexOfNotInObj; +import static org.ugp.serialx.Utils.contains; +import static org.ugp.serialx.Utils.indexOfNotInObj; import org.ugp.serialx.Registry; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java index 6937c7b..7d51f0b 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java @@ -1,10 +1,10 @@ package org.ugp.serialx.converters; -import static org.ugp.serialx.Serializer.Clone; -import static org.ugp.serialx.Serializer.contains; -import static org.ugp.serialx.Serializer.fastReplace; -import static org.ugp.serialx.Serializer.multilpy; -import static org.ugp.serialx.Serializer.splitValues; +import static org.ugp.serialx.Utils.Clone; +import static org.ugp.serialx.Utils.contains; +import static org.ugp.serialx.Utils.fastReplace; +import static org.ugp.serialx.Utils.multilpy; +import static org.ugp.serialx.Utils.splitValues; import java.util.AbstractMap; import java.util.Arrays; @@ -14,7 +14,7 @@ import org.ugp.serialx.GenericScope; import org.ugp.serialx.LogProvider; import org.ugp.serialx.Scope; -import org.ugp.serialx.Serializer.NULL; +import org.ugp.serialx.Utils.NULL; /** * This converter is capable of converting {@link Map.Entry} and reading variables from {@link Scope} via "$"! @@ -108,7 +108,7 @@ else if (arg.charAt(0) == '$' && !contains(arg, ' ', '+', '-', '*', '/', '%', '> if ((arg = fastReplace(arg, "$", "")).indexOf('.') > -1) { Object[] tree = splitValues(fastReplace(fastReplace(arg, "::new", ""), "::class", ""), '.'); - GenericScope sc = (GenericScope) scope.getGenericScope(Arrays.copyOfRange(tree, 0, tree.length-1)); + GenericScope sc = (GenericScope) scope.getGenericScope(Arrays.copyOfRange(tree, 0, tree.length-1)); //TODO: Prevent neccesity of scope parent inheritance. obj = sc == null ? null : sc.variables().get(tree[tree.length-1]); /*if (sc == null || !sc.containsVariable(tree[tree.length-1])) LogProvider.instance.logErr("Variable \"" + tree[tree.length-1] + "\" was not declared in \"" + arg.substring(0, arg.length() - tree[tree.length-1].length() - 1) + "\"! Defaulting to null!");*/ diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java index 2246d6d..cb717f7 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java @@ -8,6 +8,7 @@ import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; +import org.ugp.serialx.Utils; /** * This is automatic protocol that will automatically serialize every or selected field in object that has valid and public getter and setter! @@ -127,7 +128,7 @@ public AutoProtocol(Class applicableFor, boolean useScope, List objectClass) throws Exception { - return Serializer.Instantiate(objectClass); + return Utils.Instantiate(objectClass); } @Override diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java index 414c37f..c058b89 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java @@ -4,7 +4,7 @@ import java.util.Arrays; import org.ugp.serialx.LogProvider; -import org.ugp.serialx.Serializer; +import org.ugp.serialx.Utils; /** * Universal protocol for deserializing any object using its constructor. Args array of {@link UniversalObjectInstantiationProtocol#unserialize(Class, Object...)} must have elements applicable as arguments for some constructor of required objects class! @@ -30,7 +30,7 @@ public T unserialize(Class objectClass, Object... args) throws Exce { try { - return objectClass.getConstructor(Serializer.ToClasses(args)).newInstance(args); + return objectClass.getConstructor(Utils.ToClasses(args)).newInstance(args); } catch (Exception e0) { diff --git a/SerialX-devtools/.classpath b/SerialX-devtools/.classpath deleted file mode 100644 index 002ad57..0000000 --- a/SerialX-devtools/.classpath +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SerialX-devtools/.project b/SerialX-devtools/.project deleted file mode 100644 index b5f340d..0000000 --- a/SerialX-devtools/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - SerialX-devtools - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - diff --git a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java index a0f80d0..0476abd 100644 --- a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java +++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java @@ -1,5 +1,7 @@ package org.ugp.serialx.devtools; +import static org.ugp.serialx.Utils.multilpy; + import java.util.Arrays; import java.util.List; import java.util.Map; @@ -194,13 +196,13 @@ public static void print(String text, List objs, int tabs) for (int i = 0, i2 = 0; i < objs.size(); i++) { Object o = objs.get(i); - String strTbs = Serializer.multilpy('\t', tabs).toString(); + String strTbs = multilpy('\t', tabs).toString(); if (o instanceof List) print(strTbs + (i2++) + ":\t" + o.getClass().getName() + ":", (List) o, tabs+1); else if (o instanceof Map) print(strTbs + (i2++) + ":\t" + o.getClass().getName() + ":", (Map) o, tabs+1); else - System.err.println(Serializer.multilpy('\t', tabs).toString() + (i2++) + ":\t" + String.valueOf(o)); + System.err.println(multilpy('\t', tabs).toString() + (i2++) + ":\t" + String.valueOf(o)); } } @@ -215,7 +217,7 @@ public static void print(String text, Map map, int tabs) for (Entry entry : map.entrySet()) { Object o = entry.getValue(); - String strTbs = Serializer.multilpy('\t', tabs).toString(); + String strTbs = multilpy('\t', tabs).toString(); if (o instanceof List) print(strTbs + (entry.getKey()) + ":\t" + o.getClass().getName() + ":", (List) o, tabs+1); else if (o instanceof Map) diff --git a/SerialX-json/.classpath b/SerialX-json/.classpath deleted file mode 100644 index 002ad57..0000000 --- a/SerialX-json/.classpath +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SerialX-json/.project b/SerialX-json/.project deleted file mode 100644 index 873aaef..0000000 --- a/SerialX-json/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - SerialX-json - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java index f468198..45060e3 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java @@ -1,5 +1,9 @@ package org.ugp.serialx.json; +import static org.ugp.serialx.Utils.indexOfNotInObj; +import static org.ugp.serialx.Utils.isOneOf; +import static org.ugp.serialx.Utils.multilpy; + import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.io.File; @@ -22,15 +26,17 @@ import org.ugp.serialx.converters.BooleanConverter; import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.converters.DataParser.ParserRegistry; -import org.ugp.serialx.json.converters.JsonCharacterConverter; -import org.ugp.serialx.json.converters.JsonNumberConverter; -import org.ugp.serialx.json.converters.JsonObjectConverter; import org.ugp.serialx.converters.NullConverter; import org.ugp.serialx.converters.StringConverter; import org.ugp.serialx.converters.VariableConverter; +import org.ugp.serialx.json.converters.JsonCharacterConverter; +import org.ugp.serialx.json.converters.JsonNumberConverter; +import org.ugp.serialx.json.converters.JsonObjectConverter; import org.ugp.serialx.protocols.SerializationProtocol; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; +import javafx.beans.binding.When; + /** * This is implementation of {@link JussSerializer} for serializing in Json! * It should generate and work with .json files! @@ -143,7 +149,7 @@ public String Var(String name, T value, boolean isValue) @Override public Object put(String variableName, Object variableValue) { - if (Serializer.isOneOf(variableName.charAt(0), '"', '\'') && Serializer.isOneOf(variableName.charAt(variableName.length()-1), '"', '\'')) + if (isOneOf(variableName.charAt(0), '"', '\'') && isOneOf(variableName.charAt(variableName.length()-1), '"', '\'')) variableName = variableName.substring(1, variableName.length()-1); return super.put(variableName, variableValue); } diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java index 4850d18..1aaec5b 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java @@ -8,7 +8,7 @@ public class JsonNumberConverter extends NumberConverter { public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) { if (obj instanceof Number) - return decimalFormatter != null ? decimalFormatter.format(obj) : obj.toString(); + return format((Number) obj); return CONTINUE; } } diff --git a/SerialX-juss/pom.xml b/SerialX-juss/pom.xml new file mode 100644 index 0000000..bc08a57 --- /dev/null +++ b/SerialX-juss/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + org.ugp + serialx + ${revision} + + + org.ugp.serialx + juss + 1.3.7 + + SerialX-juss + SerialX support for Java Universal Serial Script data format, custom default format of SerialX! + \ No newline at end of file diff --git a/SerialX-operators/.classpath b/SerialX-operators/.classpath deleted file mode 100644 index 002ad57..0000000 --- a/SerialX-operators/.classpath +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SerialX-operators/.project b/SerialX-operators/.project deleted file mode 100644 index 27a03a7..0000000 --- a/SerialX-operators/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - SerialX-operators - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java index f1d1466..ab17c54 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -1,7 +1,8 @@ package org.ugp.serialx.converters.operators; -import static org.ugp.serialx.Serializer.fastReplace; -import static org.ugp.serialx.Serializer.isOneOf; +import static org.ugp.serialx.Utils.fastReplace; +import static org.ugp.serialx.Utils.isOneOf; +import static org.ugp.serialx.Utils.multilpy; import java.util.ArrayList; import java.util.Arrays; @@ -10,7 +11,6 @@ import org.ugp.serialx.LogProvider; import org.ugp.serialx.Scope; -import org.ugp.serialx.Serializer; import org.ugp.serialx.converters.ArrayConverter; import org.ugp.serialx.converters.DataParser; @@ -260,7 +260,7 @@ public static Object mult(Object cof, Object cof2, int sign) if (cof2 instanceof Number) { if (!(cof instanceof Number)) - return Serializer.multilpy(cof.toString(), ((Number) cof2).intValue() * sign).toString(); + return multilpy(cof.toString(), ((Number) cof2).intValue() * sign).toString(); if (cof instanceof Double || cof2 instanceof Double) return ((Number) cof).doubleValue() * ((Number) cof2).doubleValue() * sign; @@ -274,7 +274,7 @@ public static Object mult(Object cof, Object cof2, int sign) return ((Number) cof).doubleValue() * ((Number) cof2).doubleValue() * sign; } - return Serializer.multilpy(cof2.toString(), ((Number) cof).intValue() * sign).toString(); + return multilpy(cof2.toString(), ((Number) cof).intValue() * sign).toString(); } /** @@ -426,7 +426,7 @@ else if (ch == '}' || ch == ']') brackets--; else if (brackets == 0) { - if (Serializer.isOneOf(ch, operators)) + if (isOneOf(ch, operators)) hasOpr = isCof = 0; else if (oldCh <= 32 && isCof == 1) return false; diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java index 44b593d..7509862 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java @@ -1,6 +1,6 @@ package org.ugp.serialx.converters.operators; -import static org.ugp.serialx.Serializer.indexOfNotInObj; +import static org.ugp.serialx.Utils.indexOfNotInObj; import java.lang.reflect.Array; import java.util.Collection; diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java index ffeee37..9925c3a 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java @@ -1,9 +1,9 @@ package org.ugp.serialx.converters.operators; -import static org.ugp.serialx.Serializer.indexOfNotInObj; +import static org.ugp.serialx.Utils.indexOfNotInObj; import org.ugp.serialx.LogProvider; -import org.ugp.serialx.Serializer.NULL; +import org.ugp.serialx.Utils.NULL; import org.ugp.serialx.converters.DataParser; /** diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java index c8d4945..9bd7cb6 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java @@ -1,6 +1,6 @@ package org.ugp.serialx.converters.operators; -import static org.ugp.serialx.Serializer.indexOfNotInObj; +import static org.ugp.serialx.Utils.indexOfNotInObj; import static org.ugp.serialx.converters.operators.ArithmeticOperators.getTerms; import java.util.List; diff --git a/pom.xml b/pom.xml index db0f207..00e37a7 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ SerialX-core SerialX-devtools SerialX-operators + SerialX-juss SerialX root @@ -40,7 +41,7 @@ - 1.8 + 8 1.3.7 UTF-8 @@ -55,7 +56,6 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 ${java.version} From 3a1d678a5254c3905b7f762ea9f67525e317ef2d Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Mon, 13 Nov 2023 16:16:17 +0100 Subject: [PATCH 08/48] refactor ObjectConverter, creating Utils, bitwise optimizations, preparation for variable deserialization and abolishment of scope runtime temporary inharitance, other refactorings, --- .../java/org/ugp/serialx/GenericScope.java | 161 +++++-- .../java/org/ugp/serialx/LogProvider.java | 10 +- .../src/main/java/org/ugp/serialx/Scope.java | 124 +++--- .../main/java/org/ugp/serialx/Serializer.java | 23 +- .../src/main/java/org/ugp/serialx/Utils.java | 95 +++- .../ugp/serialx/converters/DataParser.java | 2 +- .../serialx/converters/ProtocolConverter.java | 412 ++++++++++++++++++ .../serialx/converters/imports/Import.java | 19 +- .../converters/imports/ImportConverter.java | 267 ------------ .../converters/imports/ImportsProvider.java | 223 +++++++++- .../protocols/SelfSerializableProtocol.java | 11 +- .../protocols/SerializationProtocol.java | 2 +- .../UniversalObjectInstantiationProtocol.java | 15 +- SerialX-json/pom.xml | 2 +- .../org/ugp/serialx/json/JsonSerializer.java | 4 +- .../json/converters/JsonObjectConverter.java | 6 +- SerialX-juss/pom.xml | 8 + .../org/ugp/serialx/juss}/JussSerializer.java | 41 +- .../juss}/converters/ArrayConverter.java | 70 +-- .../juss/converters/ImportConverter.java | 79 ++++ .../juss/converters/ObjectConverter.java | 199 +++++++++ .../juss/converters/ObjectConverterOld.java | 23 +- .../juss}/converters/OperationGroups.java | 11 +- .../juss}/converters/VariableConverter.java | 14 +- .../operators/ArithmeticOperators.java | 20 +- .../ConditionalAssignmentOperators.java | 8 +- 26 files changed, 1316 insertions(+), 533 deletions(-) create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java delete mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportConverter.java rename {SerialX-core/src/main/java/org/ugp/serialx => SerialX-juss/src/main/java/org/ugp/serialx/juss}/JussSerializer.java (94%) rename {SerialX-core/src/main/java/org/ugp/serialx => SerialX-juss/src/main/java/org/ugp/serialx/juss}/converters/ArrayConverter.java (64%) create mode 100644 SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ImportConverter.java create mode 100644 SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java rename SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java => SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverterOld.java (96%) rename {SerialX-core/src/main/java/org/ugp/serialx => SerialX-juss/src/main/java/org/ugp/serialx/juss}/converters/OperationGroups.java (96%) rename {SerialX-core/src/main/java/org/ugp/serialx => SerialX-juss/src/main/java/org/ugp/serialx/juss}/converters/VariableConverter.java (95%) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index bdb25df..3ca29a7 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -17,7 +17,6 @@ import java.util.function.Predicate; import org.ugp.serialx.Utils.NULL; -import org.ugp.serialx.converters.ArrayConverter; import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.protocols.SerializationProtocol; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; @@ -110,7 +109,7 @@ else if (obj instanceof Collection) else if (obj instanceof Map) return valuesCount() <= 0 && variables().equals(obj); else if (obj != null && obj.getClass().isArray()) - return variablesCount() <= 0 && Objects.deepEquals(toValArray(), ArrayConverter.fromAmbiguous(obj)); + return variablesCount() <= 0 && Objects.deepEquals(toValArray(), Utils.fromAmbiguousArray(obj)); return super.equals(obj); } @@ -277,10 +276,82 @@ public V get(KeyT variableKey, V defaultValue) { V obj = (V) variables().get(variableKey); if (obj == null) - return (V) defaultValue; + return defaultValue; return obj instanceof NULL ? null : obj; } + /** + * @param pathToValue | Array with variables creating path to required value, nested in multiple sub-scopes. + * + * @return Value of variable at given path. If no path is given (length is 0) then this {@link GenericScope} will be returned.
+ * If 1 path argument is given then this behaves similarly to {@link GenericScope#get(Object)}.
+ * if 2+ path arguments are given then it will search the sub-scopes and return first match value. For example:
+ * Consider this scope tree:
+ *
+	 * 
+	 * {
+	 *   125: {
+	 *   	"hello": {
+	 *   		"value" true
+	 *   	}
+	 *   }
+	 * }
+	 * 
+	 * 
+ * Then to get value of "value" you can do scope.get(125, "hello", "value")!
+ * If there is no other variable called "value" in the scope tree then you can also simplify it to scope.get("value"), but make sure that there is no equally-named variable!
+ * Note: Make sure that you are not calling {@link GenericScope#get(Object, Object)} by accident when you are using inline vargas array (unspecified count of arguments)! + * + * @since 1.3.7 + */ + @SuppressWarnings("unchecked") + public V get(KeyT... pathToValue) + { + try + { + if (pathToValue.length <= 0) + return (V) this; + Object obj = get((KeyT) pathToValue[0]); + if (obj instanceof GenericScope) + return ((GenericScope) obj).get(pathToValue = Arrays.copyOfRange(pathToValue, 1, pathToValue.length)); + for (Map.Entry var : varEntrySet()) + if (var.getValue() instanceof GenericScope) + try + { + GenericScope sc = (GenericScope) var.getValue(); + if ((sc = sc.getGenericScope(pathToValue[0])) != null) + return sc.get(pathToValue = Arrays.copyOfRange(pathToValue, 1, pathToValue.length)); + } + catch (Exception e) {} + + return (V) obj; + } + catch (ClassCastException e) + {} + return null; + } + + /** + * @param variableKey | Variables name. + * @param cls | Default value to return. + * @param defaultValue | Class that you want the obtained object to be converted into! Exact conversion algorithm can differ based on its implementations. + * + * @return Value of variable with name given converted to object of cls or defaultValue if there is no such a one! + * + * @throws Exception | If converting to object of cls failed from some reason! This can differ from implementation to implementation! By default it uses {@link GenericScope#toObject(cls)} + * + * @since 1.3.7 + */ + public V get(KeyT variableKey, Class cls, V defaultValue) throws Exception + { + V obj = get(variableKey, defaultValue); + if (obj != null && obj.getClass() == cls) + return obj; + if (obj instanceof GenericScope) + return ((GenericScope) obj).toObject(cls); + return obj; + } + /** * @param variableKey | Variables name to search for. * @@ -312,7 +383,7 @@ public boolean containsIndependentValue(ValT value) * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! * {@link IndexOutOfBoundsException} will be thrown if index is too big! * - * @return Independent value with valueIndex. + * @return Independent value with valueIndex of this {@link GenericScope}! * * @since 1.2.0 */ @@ -323,6 +394,26 @@ public V get(int valueIndex) return obj instanceof NULL ? null : obj; } + /** + * @param valueIndex | Index of independent value. Also can be negative, in this case u will get elements from back! + * @param cls | Class that you want the obtained object to be converted into! Exact conversion algorithm can differ based on its implementations. + * + * @return Independent value with valueIndex of this converted to object of cls! + * + * @throws Exception | If converting to object of cls failed from some reason! This can differ from implementation to implementation! + * + * @since 1.3.7 + */ + public V get(int valueIndex, Class cls) throws Exception + { + V obj = get(valueIndex); + if (obj != null && obj.getClass() == cls) + return obj; + if (obj instanceof GenericScope) + return ((GenericScope) obj).toObject(cls); + return obj; + } + /** * @param value | Independent value to add into array of values. * @@ -383,10 +474,10 @@ public GenericScope getGenericScope(int scopeValueIndex) } /** - * @param scopesPath | Array with variables creating path to required scope. + * @param pathToScope | Array with variables creating path to required scope. * - * @return Sub-scope stored by variable with required name (last element) in inserted path or null if there is no such a one in inserted path. If there is more than one result, the first one found will be returned! - * This search will also includes sub-scopes of scope but variables from lower ones are prioritize!
+ * @return Sub-scope stored by variable with required name (last element of pathToScope) or null if there is no such a one in inserted path. If there is more than one result, the first one found will be returned! + * This search will also includes sub-scopes stored by variables of this scope while variables from lower ones are prioritize!
* If this function is called with no arguments then self will be returned! * Note: Remember that this search includes variables only, no values!
* Note: Also remember that this function will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope}) @@ -394,30 +485,14 @@ public GenericScope getGenericScope(int scopeValueIndex) * @since 1.2.0 */ @SuppressWarnings("unchecked") - public GenericScope getGenericScope(K... scopesPath) + public GenericScope getGenericScope(K... pathToScope) { - try - { - if (scopesPath.length <= 0) - return (GenericScope) this; - Object obj = get((KeyT) scopesPath[0]); - if (obj instanceof GenericScope) - return ((GenericScope) obj).getGenericScope(scopesPath = Arrays.copyOfRange(scopesPath, 1, scopesPath.length)); - for (Map.Entry var : varEntrySet()) - if (var.getValue() instanceof GenericScope) - try - { - GenericScope sc = (GenericScope) var.getValue(); - if ((sc = sc.getGenericScope(scopesPath[0])) != null) - return sc.getGenericScope(scopesPath = Arrays.copyOfRange(scopesPath, 1, scopesPath.length)); - } - catch (Exception e) {} - - if (containsVariable((KeyT) scopesPath[0])) - LogProvider.instance.logErr("Variable with name \"" + scopesPath[0] + "\" does exists! However its value is not instance of scope, use \"get\" function instead if possible!", null); - } - catch (ClassCastException e) - {} + Object obj = get((KeyT[]) pathToScope); + if (obj instanceof GenericScope) + return (GenericScope) obj; + + if (containsVariable((KeyT) pathToScope[0])) + LogProvider.instance.logErr("Variable with name \"" + pathToScope[0] + "\" does exists! However its value is not instance of scope, use \"get\" function instead if possible!", null); return null; } @@ -657,7 +732,7 @@ public GenericScope inheritParent() * * @since 1.3.0 */ - public GenericScope addAll(GenericScope scope) + public GenericScope addAll(GenericScope scope) { values().addAll(scope.values()); variables().putAll(scope.variables()); @@ -719,23 +794,27 @@ public boolean isEmpty() */ public GenericScope getParent() { - return getParent(false); + return getParent(1); } /** - * @param absoluteParent | If true, absolute parent of this scope will be returned (parent of parent of parent...)! - * - * @return The parent scope of this scope or null if this scope has no parent such as default one in file. + * @param depth | Positive number representing how many times will this method call itself...
For example 0 or less = this, 1 = parent, 2 = parentOfParent (parent.getParent()) and so on... + * If you want to get the root parent (the one that has no parent), simply put a big number as depth. 99 should be enough! + * + * @return The parent scope based on depth or null if this scope has no parent which means its already root (default one in file). + * If depth was bigger than 1, null will be never returned, last not null parent will be returned instead!
* * @since 1.3.2 */ - public GenericScope getParent(boolean absoluteParent) + public GenericScope getParent(int depth) { - if (!absoluteParent) - return parent; - GenericScope parent = this.parent; - for (GenericScope tmpPar; parent != null && (tmpPar = parent.getParent()) != null; parent = tmpPar); - return parent; + if (depth < 1) + return this; + + GenericScope parentsParent; + if (depth == 1 || parent == null || (parentsParent = parent.getParent(--depth)) == null) + return parent; + return parentsParent; } /** diff --git a/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java b/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java index 79c3039..5ab4f08 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java @@ -15,19 +15,21 @@ public class LogProvider public static LogProvider instance = new LogProvider(); /** - * @param object | Object to log in normal mode! + * @param obj | Object to log in normal mode! * * @since 1.3.5 */ - public void logOut(Object object) + public void logOut(Object obj) { - System.out.println(object); + System.out.println(obj); } /** - * @param object | Object to log in error mode! + * @param obj | Object to log in error mode! * @param ex | Exception that cause the error! * + * @throws RuntimeException | Of "ex" if exception re-throwing is enabled! + * * @since 1.3.5 */ public void logErr(Object obj, Throwable ex) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java index 61c5839..c0defa6 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java @@ -17,7 +17,6 @@ import java.util.Objects; import java.util.function.Predicate; -import org.ugp.serialx.converters.ArrayConverter; import org.ugp.serialx.protocols.SerializationProtocol; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; @@ -101,7 +100,46 @@ public Scope(Map variablesMap, Collection values, GenericScope T toObject(Class objClass, ProtocolRegistry protocolsToUse) throws Exception + { + T obj = super.toObject(objClass, protocolsToUse); + if (obj != null) + return obj; + + try + { + return into(objClass); + } + catch (Exception e) + { + LogProvider.instance.logErr("Unable to create new instance of " + objClass.getName() + " because none of provided protocols were suitable and class introspection has failed as well!", e); + return null; + } } /** @@ -590,11 +628,13 @@ public Scope getSubScope(int subscopesOrderIndex) } /** - * @param scopesPath | Array with variable names creating path to required scope. + * @param pathToScope | Array with variable names creating path to required scope. * - * @return Sub-scope stored by variable with required name (last element) in inserted path or null if there is no such a one in inserted path. If there is more than one result, the first one found will be returned! - * This search will also includes sub-scopes of scope but variables from lower ones are prioritize!
+ * @return Sub-scope stored by variable with required name (last element of pathToScope) or null if there is no such a one in inserted path. If there is more than one result, the first one found will be returned! + * This search will also includes sub-scopes stored by variables of this scope while variables from lower ones are prioritize!
* If this function is called with no arguments then self will be returned! + * Note: Remember that this search includes variables only, no values!
+ * Note: Also remember that this function will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope}) *
*
 	 * 
@@ -614,11 +654,11 @@ public Scope getSubScope(int subscopesOrderIndex)
 	 * 
 	 * @since 1.2.0
 	 */
-	public Scope getScope(String... scopesPath)
+	public Scope getScope(String... pathToScope)
 	{
 		try
 		{
-			return (Scope) getGenericScope(scopesPath);
+			return (Scope) getGenericScope(pathToScope);
 		}
 		catch (ClassCastException e)
 		{
@@ -807,7 +847,7 @@ public Scope getScopesWith(String varName, Predicate condition)
 	public Scope getScopesWith(String varName, Predicate condition, boolean includeSubScopes)
 	{
 		Scope result = new Scope(null, null, getParent());
-		
+
 		for (Entry myVar : varEntrySet())
 			if (myVar.getValue() instanceof Scope)
 				try
@@ -835,37 +875,6 @@ else if (includeSubScopes)
 		return result;
 	}
 	
-	/**
-	 * @param objClass | Object of class to create using protocols.
-	 * @param protocolsToUse | Registry of protocols to use.
-	 * 
-	 * @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}! 
-	 * If there were no suitable deserialization protocols found, {@link Scope#into(Class, String...)} will be used!
-	 * 
-	 * @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}!
-	 * 
-	 * @see Scope#into(Class, String...)
-	 * @see Scope#intoNew(Class, GenericScope, String...)
-	 * 
-	 * @since 1.3.5
-	 */
-	public  T toObject(Class objClass, ProtocolRegistry protocolsToUse) throws Exception
-	{
-		T obj = super.toObject(objClass, protocolsToUse);
-		if (obj != null)
-			return obj;
-		
-		try
-		{
-			return into(objClass);
-		}
-		catch (Exception e)
-		{
-			LogProvider.instance.logErr("Unable to create new instance of " + objClass.getName() + " because none of provided protocols were suitable and class introspection has failed as well!", e);
-			return null;
-		}
-	}
-	
 	/**
 	 * @param objCls | Class of object to instantiate!
 	 * @param fieldNamesToUse | Array of objCls field names to map/populate instantiated object from scopes variables using setters (write method)! PropertyDescriptors of these fields will be obtained using Scope.getPropertyDescriptorsOf(Class, String)! This is used only as a last (default) option!
@@ -897,7 +906,7 @@ public  T into(Class objCls, String... fieldNamesToUse) throws Introspecti
 	 * 
 	 * @since 1.3.5  
 	 */
-	public  T into(Object obj, String... fieldNamesToUse) throws IntrospectionException, Exception
+	public  T into(T obj, String... fieldNamesToUse) throws IntrospectionException, Exception
 	{
 		return into(obj, this, fieldNamesToUse);
 	}
@@ -957,7 +966,7 @@ public static Scope from(Object obj, String... fieldNamesToUse) throws Exception
 			return new Scope();
 		
 		if (obj.getClass().isArray())
-			return new Scope(ArrayConverter.fromAmbiguous(obj));
+			return new Scope(Utils.fromAmbiguousArray(obj));
 		
 		if (obj instanceof Scope)
 		{
@@ -996,22 +1005,23 @@ public static Scope from(Object obj, List fieldsToUse) throw
 	}
 	
 	/**
-	 * @param newInstance | New instance of specific {@link Scope}!
+	 * @param newInstance | New instance of specific {@link GenericScope} with {@link String} keys!
 	 * @param obj | Object to create scope from!
 	 * @param fieldsToUse | List of {@link PropertyDescriptor}s representing fields of object to map into scopes variables using getters (read method)!
 	 * 
-	 * @return Scope (newInstance) structured from given obj by mapping obj's fields into variables of created scope via given {@link PropertyDescriptor}s (fieldsToUse)!
+	 * @return Scope (newInstance) structured/populated from given obj by mapping obj's fields into variables of created scope via given {@link PropertyDescriptor}s (fieldsToUse)!
 	 * 
 	 * @throws Exception if calling of some {@link PropertyDescriptor}s read method fails (should not happen often)!
 	 * 
 	 * @since 1.3.5
 	 */
-	public static Scope from(Scope newInstance, Object obj, List fieldsToUse) throws Exception
+	@SuppressWarnings("unchecked")
+	public static > S from(S newInstance, Object obj, List fieldsToUse) throws Exception
 	{
 		//if (variablesToUse != null)
 		//variablesToUse = AutoProtocol.getPropertyDescriptorsOf(obj.getClass());
 		for (PropertyDescriptor var : fieldsToUse) 
-			newInstance.put(var.getName(), var.getReadMethod().invoke(obj));
+			((GenericScope) newInstance).put(var.getName(), var.getReadMethod().invoke(obj));
 		return newInstance;
 	}
 	
@@ -1064,7 +1074,7 @@ New object instance (return)
 	 * @since 1.3.5
 	 */
 	@SuppressWarnings("unchecked")
-	public static  T intoNew(Class objCls, GenericScope fromScope, String... fieldNamesToUse) throws IntrospectionException, Exception
+	public static  T intoNew(Class objCls, GenericScope fromScope, String... fieldNamesToUse) throws IntrospectionException, Exception
 	{
 		if (objCls == null)
 			return null;
@@ -1079,7 +1089,7 @@ public static  T intoNew(Class objCls, GenericScope fromScope,
 		
 		if (GenericScope.class.isAssignableFrom(objCls))
 		{
-			GenericScope result = ((GenericScope) fromScope).clone((Class>)objCls);
+			GenericScope result = ((GenericScope) fromScope).clone((Class>)objCls);
 			if (fieldNamesToUse != null && fieldNamesToUse.length > 0)
 				result.variables().keySet().retainAll(Arrays.asList(fieldNamesToUse));
 			return (T) result;
@@ -1154,7 +1164,7 @@ Action with obj (return)
 	 * @since 1.3.5
 	 */
 	@SuppressWarnings("unchecked")
-	public static  T into(Object obj, GenericScope fromScope, String... fieldNamesToUse) throws IntrospectionException, Exception
+	public static  T into(T obj, GenericScope fromScope, String... fieldNamesToUse) throws IntrospectionException, Exception
 	{
 		if (obj == null)
 			return null;
@@ -1162,21 +1172,21 @@ public static  T into(Object obj, GenericScope fromScope, String..
 		{
 			for (int i = 0, arrLen = Array.getLength(obj), scSize = fromScope.valuesCount(); i < arrLen && i < scSize; i++)
 				Array.set(obj, i, fromScope.get(i));
-			return (T) obj;
+			return obj;
 		}
 		
 		if (obj instanceof GenericScope)
 		{
-			((GenericScope) obj).addAll(fromScope);
+			((GenericScope) obj).addAll(fromScope);
 			if (fieldNamesToUse != null && fieldNamesToUse.length > 0)
-				((GenericScope) obj).variables().keySet().retainAll(Arrays.asList(fieldNamesToUse));
-			return (T) obj;
+				((GenericScope) obj).variables().keySet().retainAll(Arrays.asList(fieldNamesToUse));
+			return obj;
 		}
 		
 		if (obj instanceof Collection)
 		{	
 			((Collection) obj).addAll(fromScope.values());
-			return (T) obj;
+			return obj;
 		}
 		
 		if (obj instanceof Map)
@@ -1184,10 +1194,10 @@ public static  T into(Object obj, GenericScope fromScope, String..
 			((Map) obj).putAll(fromScope.variables());
 			if (fieldNamesToUse != null && fieldNamesToUse.length > 0)
 				((Map) obj).keySet().retainAll(Arrays.asList(fieldNamesToUse));
-			return (T) obj;
+			return obj;
 		}
 		
-		return (T) into(obj, fromScope, getPropertyDescriptorsOf(obj.getClass(), fieldNamesToUse));
+		return into(obj, fromScope, getPropertyDescriptorsOf(obj.getClass(), fieldNamesToUse));
 	}
 	
 	/**
@@ -1202,11 +1212,11 @@ public static  T into(Object obj, GenericScope fromScope, String..
 	 * @since 1.3.5
 	 */
 	@SuppressWarnings("unchecked")
-	public static  T into(T obj, GenericScope fromScope, List fieldsToUse) throws Exception
+	public static  T into(T obj, GenericScope fromScope, List fieldsToUse) throws Exception
 	{
 		for (PropertyDescriptor var : fieldsToUse) 
 		{
-			Object varValue = ((GenericScope) fromScope).get(var.getName(), VOID);
+			Object varValue = ((GenericScope) fromScope).get(var.getName(), VOID);
 			if (varValue != VOID)
 				var.getWriteMethod().invoke(obj, varValue);
 		}
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java
index ccae28e..9b5476b 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java
@@ -56,7 +56,7 @@ public abstract class Serializer extends Scope
 	 * 
 	 * @since 1.3.2
 	 */
-	public static final ParserRegistry COMMON_PARSERS = new ParserRegistry(new StringConverter(), new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter());
+	public static final ParserRegistry COMMON_PARSERS = new ParserRegistry(new StringConverter(), /* TODO: new ProtocolConverter() */ new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter());
 	
 	protected ParserRegistry parsers;
 	protected ProtocolRegistry protocols;
@@ -132,19 +132,6 @@ public Serializer(Registry parsers, ProtocolRegistry protocols, Map<
 		if (protocols != null)
 			setProtocols(protocols);
 	}
-	
-	@Override
-	public Scope clone() 
-	{
-		try 
-		{
-			return clone(getClass());
-		}
-		catch (Exception e) 
-		{
-			return new JussSerializer(variables(), values(), getParent());
-		}
-	}
 
 	@Override
 	public > S clone(Class typeOfClone) throws Exception
@@ -186,7 +173,7 @@ public  T toObject(Class objClass) throws Exception
 	 * @see Serializer#into(Object, Serializer, String...)
 	 */
 	@Override
-	public  T into(Object obj, String... fieldNamesToUse) throws IntrospectionException, Exception 
+	public  T into(T obj, String... fieldNamesToUse) throws IntrospectionException, Exception 
 	{
 		return Serializer.into(obj, this, fieldNamesToUse);
 	}
@@ -702,7 +689,7 @@ else if (ch == '/' && i < len-1)
 						}
 						else
 						{
-							if (ch == '{' || ch == '[')
+							if (ch | ' ') == '{' || ch == '[')
 								brackets++;
 							else if (ch == '}' || ch == ']')
 							{
@@ -844,7 +831,7 @@ else if (ch == '/' && fromIndex < len-1)
 					}
 					else 
 					{
-						if (ch == '{' || ch == '[')
+						if (ch | ' ') == '{' || ch == '[')
 							brackets++;
 						else if (ch == '}' || ch == ']')
 						{
@@ -1022,7 +1009,7 @@ public static  T into(Object obj, Serializer fromSerializer, String... fieldN
 		catch (IOException e)
 		{}
 		
-		return Scope.into(obj, fromSerializer, fieldNamesToUse);
+		return (T) Scope.into(obj, fromSerializer, fieldNamesToUse);
 	}
 	
 	/**
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java
index a9b8d48..11e1025 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java
@@ -9,6 +9,7 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -24,8 +25,14 @@
 import org.ugp.serialx.converters.DataParser.ParserRegistry;
 import org.ugp.serialx.protocols.SerializationProtocol;
 
-
-public class Utils {
+/**
+ * Provides general utility used across SerialX library, mostly string analysis/manipulation and reflection.
+ * 
+ * @author PETO
+ * 
+ * @since 1.3.7
+ */
+public final class Utils {
 	private Utils() {}
 	
 	/**
@@ -99,6 +106,8 @@ public static String StreamToString(Reader input, int endlMode) throws IOExcepti
 		return sb.toString();
 	}
 	
+	/* Reflect */
+	
 	/**
 	 * @param cls | Class to invoke method from.
 	 * @param name | Name of public static method to be called.
@@ -421,6 +430,8 @@ else if (objs[i] instanceof Class)
 		return classes;
 	}
 	
+	/* Characters */
+	
 	/**
 	 * @param ch | String to multiply!
 	 * @param times | Count of multiplication!
@@ -522,9 +533,9 @@ public static String[] splitValues(String s, int limit, boolean oneOrMore, char[
 					result.add(s.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i).trim());
 					count++;
 				}
-				else if (ch == '{' || ch == '[')
+				else if ((ch | ' ') == '{')
 					brackets++;
-				else if (ch == '}' || ch == ']')
+				else if ((ch | ' ') == '}')
 				{
 					if (brackets > 0)
 						brackets--;
@@ -551,7 +562,7 @@ else if (quote % 2 != 0)
 	 * @param s | CharSequence to search!
 	 * @param oneOf | Characters to find!
 	 * 
-	 * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'!
+	 * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}', otherwise -1!
 	 * 
 	 * @since 1.3.0
 	 */
@@ -565,7 +576,7 @@ public static int indexOfNotInObj(CharSequence s, char... oneOf)
 	 * @param firstIndex | If true, first index will be returned, if false last index will be returned.
 	 * @param oneOf | Characters to find!
 	 * 
-	 * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'!
+	 * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}', otherwise -1!
 	 * 
 	 * @since 1.3.5
 	 */
@@ -586,9 +597,9 @@ public static int indexOfNotInObj(CharSequence s, boolean firstIndex, char... on
 					if (firstIndex)
 						return found;
 				}
-				else if (ch == '{' || ch == '[')
+				else if ((ch | ' ') == '{')
 					brackets++;
-				else if (ch == '}' || ch == ']')
+				else if ((ch | ' ') == '}')
 				{
 					if (brackets > 0)
 						brackets--;
@@ -643,9 +654,9 @@ public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind, b
 						match = 0;
 					}
 				}
-				else if (ch == '{' || ch == '[')
+				else if ((ch | ' ') == '{')
 					brackets++;
-				else if (ch == '}' || ch == ']')
+				else if ((ch | ' ') == '}')
 				{
 					if (brackets > 0)
 						brackets--;
@@ -673,11 +684,11 @@ public static String fastReplace(String str, String target, CharSequence replace
 	    int targetLength = target.length();
 	    if (targetLength == 0) 
 	        return str;
-	    
+
 	    int i1 = 0, i2 = str.indexOf(target);
 	    if (i2 < 0) 
 	        return str;
-	    
+
 	    StringBuilder sb = new StringBuilder(targetLength > replacement.length() ? str.length() : str.length() * 2);
 	    do 
 	    {
@@ -740,6 +751,66 @@ public static String showPosInString(CharSequence str, int pos)
 		return str + "\n" + multilpy(' ', pos) + "^";	
 	}
 	
+	/* Arrays */
+	
+	/**
+	 * @param sourceArray | Array to cast!
+	 * @param toType | Type to cast array in to!
+	 * 
+	 * @return Array object casted in to required type!
+	 * 
+	 * @since 1.3.2
+	 */
+	public static Object castArray(Object[] sourceArray, Class toType)
+	{
+		int len = sourceArray.length;
+		Object arr = Array.newInstance(ToClasses(toType)[0], len);
+		for (int i = 0; i < len; i++) 
+			Array.set(arr, i, sourceArray[i]);
+		return arr;
+	}
+	
+	/**
+	 * @param arr1 | Object one that might be array!
+	 * @param arr2 | Object two that might be array!
+	 * 
+	 * @return New array consisting of array 1 and array 2!
+	 * 
+	 * @throws IllegalArgumentException if object one is not an array!
+	 * 
+	 * @since 1.3.2
+	 */
+	public static Object[] mergeArrays(Object arr1, Object arr2) 
+	{
+		Object[] array1 = fromAmbiguousArray(arr1), array2 = arr2.getClass().isArray() ? fromAmbiguousArray(arr2) : new Object[] { arr2 };
+		Object[] result = Arrays.copyOf(array1, array1.length + array2.length);
+	    System.arraycopy(array2, 0, result, array1.length, array2.length);
+	    return result;
+	}
+	
+	/**
+	 * @param array | Object that might be array!
+	 * 
+	 * @return Object transformed in to primitive array! If array is already an instance of primitive array then it will be simply returned!
+	 * 
+	 * @throws IllegalArgumentException if the specified object is not an array!
+	 * 
+	 * @since 1.3.2 (since 1.3.7 moved from ArrayConverter)
+	 */
+	public static Object[] fromAmbiguousArray(Object array)
+	{
+		if (array instanceof Object[])
+			return (Object[]) array;
+		
+		int len = Array.getLength(array);
+		Object[] arr = new Object[len];
+		for (int i = 0; i < len; i++) 
+			arr[i] = Array.get(array, i);
+		return arr;
+	}
+	
+	/* Others... */
+	
 	/**
 	 * This will serialize serializer into http query post request however this is not the best networking and you should implement your own http client if you want SerialX to serialize and deserialize remote content!
 	 * 
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java
index 1eee489..b53fb83 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java
@@ -41,7 +41,7 @@ public interface DataParser
 	 * 
 	 * @since 1.3.0
 	 */
-	public static final ParserRegistry REGISTRY = new ParserRegistry(new OperationGroups(), new VariableConverter(), new StringConverter(), new ObjectConverter(), new ArrayConverter(), new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter());
+	public static final ParserRegistry REGISTRY = new ParserRegistry(/* new OperationGroups(), new VariableConverter(),*/ new StringConverter(), /*new ObjectConverter(),*/ /*TODO: remove new ArrayConverter(),*/ new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter());
 	
 	/**
 	 * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)!
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java
new file mode 100644
index 0000000..bb04719
--- /dev/null
+++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java
@@ -0,0 +1,412 @@
+package org.ugp.serialx.converters;
+
+import static org.ugp.serialx.Utils.Instantiate;
+import static org.ugp.serialx.Utils.indexOfNotInObj;
+import static org.ugp.serialx.Utils.isOneOf;
+import static org.ugp.serialx.Utils.splitValues;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+
+import org.ugp.serialx.GenericScope;
+import org.ugp.serialx.LogProvider;
+import org.ugp.serialx.Registry;
+import org.ugp.serialx.Scope;
+import org.ugp.serialx.Serializer;
+import org.ugp.serialx.Utils;
+import org.ugp.serialx.converters.imports.ImportsProvider;
+import org.ugp.serialx.protocols.SerializationProtocol;
+import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry;
+
+/**
+ * This converter is capable of converting any Object using {@link SerializationProtocol} as well as invoking static functions!
+ * This is also responsible for {@link Scope}!
+ * Its case sensitive!
+ * 
+ *
+ * Table of sample string <--> object conversions: + * + + + + + + + + + + + + + +
StringObject
ArrayList 2 4 6new ArrayList<>(Arrays.asList(2, 4, 6))
java.lang.Math::max 10 510
+
+ This parser requires additional parser arg at index 0 of type {@link GenericScope} or {@link Serializer} that will be used for further parsing and operating (default new {@link JussSerializer}).
+ This parser requires additional parser arg at index 3 of type {@link ProtocolRegistry} or {@link SerializationProtocol} itself that will be used for parsing protocol expressions (default {@link SerializationProtocol#REGISTRY}).
+ * This parser will insert one additional argument into array of additional parser args at index 4, in case of serialization index 5, that will be of type {@link Class} and it will contains information about class of object that is being unserialized or serialized using protocol!
+ * + * @author PETO + * + * @since 1.3.0 + */ +public class ProtocolConverter implements DataConverter +{ + /** + * Set this on true to force program to use {@link Base64} serialization on {@link Serializable} objects. + * Doing this might result into some form of encryption but its less flexible and tends to be slower than SerialX {@link SerializationProtocol} system! + * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. + * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
+ * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
+ * Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! + * + * @since 1.0.0 (moved to {@link SerializableBase64Converter} since 1.3.0 and since 1.3.5 into {@link ObjectConverter}) + */ + protected boolean useBase64IfCan = false; + + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... compilerArgs) + { + int len; + if ((len = str.length()) > 0) + { + if ((str.charAt(0) | ' ') == '{' && (str.charAt(--len) | ' ') == '}') // Unwrap if wrapped in {} + str = str.substring(1, len).trim(); + + Class objClass; + if ((objClass = getProtocolExprClass(str, compilerArgs)) != null) // Get class of protocol expr or continue if there is none + return parse(myHomeRegistry, objClass, str, compilerArgs); + } + return CONTINUE; + } + + /** + * @param myHomeRegistry | Same as {@link DataParser#parse(ParserRegistry, String, Object...)}. + * @param objClass | Class of object to parse using {@link SerializationProtocol}. + * @param str | String that starts with {@link Class} of object to deserialized (it will be used with {@link SerializationProtocol#unserializeObj(ProtocolRegistry, Class, Object...)}). + * @param compilerArgs | Same as {@link DataParser#parse(ParserRegistry, String, Object...)}. + * + * @return Object od objClass parsed from str in accordance with compilerArgs! + * + * @since 1.3.7 + */ + protected Object parse(ParserRegistry myHomeRegistry, Class objClass, String str, Object... compilerArgs) + { + if (objClass == IsSelectorScope.class) + { + StringBuilder sb = new StringBuilder(str); + sb.setCharAt(str.indexOf(' '), '='); + return myHomeRegistry.parse(sb.toString(), compilerArgs); + } + + if (compilerArgs.length < 5) + compilerArgs = Arrays.copyOf(compilerArgs, 5); + Class oldObjectClass = (Class) compilerArgs[4]; + compilerArgs[4] = objClass; + + String[] args = splitValues(str, ' '); + int nameIndex; + if (!isOneOf(args[0].charAt(0), '{', '[') && (nameIndex = args[0].indexOf("::")) > -1) //Is static member invocation + { + String memberName = args[0].substring(nameIndex + 2); + if (args.length > 1) + return InvokeStaticFunc(objClass, oldObjectClass, memberName, parseAll(myHomeRegistry, args, 1, true, compilerArgs), compilerArgs); + + try + { + compilerArgs[4] = oldObjectClass; + return memberName.equals("class") ? objClass : memberName.equals("new") ? Instantiate(objClass) : objClass.getField(memberName).get(null); + } + catch (NoSuchFieldException e) + { + return InvokeStaticFunc(objClass, oldObjectClass, memberName, parseAll(myHomeRegistry, args, 1, true, compilerArgs), compilerArgs); + } + catch (Exception e) + { + LogProvider.instance.logErr("Unable to obtain value of field \"" + memberName + "\" in class \"" + objClass.getSimpleName() + "\" because:", e); + e.printStackTrace(); + return null; + } + } + + try + { +// if ((ch = str.charAt(str.length()-1)) == ';' || ch == ',') +// throw new ClassNotFoundException(); + + Object[] objArgs = parseAll(myHomeRegistry, args, 1, true, compilerArgs); + if (objArgs.length == 1 && objArgs[0] instanceof Scope && Scope.class.isAssignableFrom(objClass)) + return objArgs[0]; + compilerArgs[4] = oldObjectClass; + return SerializationProtocol.unserializeObj(compilerArgs.length > 3 && compilerArgs[3] instanceof ProtocolRegistry ? (ProtocolRegistry) compilerArgs[3] : SerializationProtocol.REGISTRY, objClass, objArgs); + } + catch (Exception e) + { + LogProvider.instance.logErr("Exception while unserializing instance of \"" + objClass.getName() + "\":", e); + e.printStackTrace(); + return null; + } + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) + { + return toString(myHomeRegistry, arg, null, args); + } + + /** + * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @param obj | Object to convert into string! + * @param preferedProtocol | Protocol to use preferably. + * @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)! + * + * @return Object converted to string. Easiest way to do this is obj.toString() but you most likely want some more sofisticated formating. + * 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! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, SerializationProtocol preferedProtocol, Object... args) + { + if (arg == null) + return CONTINUE; + + if (useBase64IfCan && arg instanceof Serializable) + return CONTINUE; + + if (preferedProtocol != null || (preferedProtocol = (SerializationProtocol) getProtocolFor(arg, SerializationProtocol.MODE_SERIALIZE, args)) != null) + { + Object[] objArgs; + Class oldObjectClass = null; + try + { + int tabs = 0, index = 0; + if (args.length > 1 && args[1] instanceof Integer) + tabs = (int) args[1]; + + if (args.length > 2 && args[2] instanceof Integer) + index = (int) args[2]; + + if (args.length < 5) + args = Arrays.copyOf(args, 5); + oldObjectClass = (Class) args[4]; + args[4] = arg.getClass();; + + objArgs = preferedProtocol.serialize(arg); + StringBuilder sb = new StringBuilder(ImportsProvider.getAliasFor(args.length > 0 ? args[0] : null, arg.getClass()) + (objArgs.length <= 0 ? "" : " ")); + + args = args.clone(); + for (int i = 0, sizeEndl = 10000; i < objArgs.length; i++) + { + if (args.length > 2) + args[2] = index + 1; + sb.append(myHomeRegistry.toString(objArgs[i], args)); + if (i < objArgs.length-1) + if (sb.length() > sizeEndl) + { + sb.append('\n'); + for (int j = 0; j < tabs+1; j++) + sb.append('\t'); + sizeEndl += 10000; + } + else + sb.append(' '); + } + + args[4] = oldObjectClass; + return index > 0 && objArgs.length > 0 ? sb.insert(0, '{').append('}') : sb; + } + catch (Exception e) + { + LogProvider.instance.logErr("Exception while serializing instance of \"" + arg.getClass().getName() + "\":", e); + e.printStackTrace(); + } + args[4] = oldObjectClass; + } + return CONTINUE; + } + + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) + { + if (obj instanceof Scope && ((Scope) obj).isEmpty()) + return "Empty scope!"; + else if (obj instanceof CharSequence && indexOfNotInObj((CharSequence) obj, '\n', '\r') != -1) + return "Multiline char sequence!"; + return new StringBuilder("Object of ").append(obj.getClass().getName()).append(": \"").append(obj.toString()).append("\" serialized using ").append(getProtocolFor(obj, SerializationProtocol.MODE_ALL, argsUsedConvert).toString()).append("!"); + } + + /** + * @return True if program is forced to use {@link Base64} serialization on {@link Serializable} objects. + * This might result into some form of encryption but its less flexible and tends to be slower than SerialX {@link SerializationProtocol} system! + * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. + * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
+ * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
+ * Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! + * + * @since 1.3.5 + */ + public boolean isUseBase64IfCan() + { + return useBase64IfCan; + } + + /** + * @param useBase64IfCan | Set this on true to force program to use {@link Base64} serialization on {@link Serializable} objects. + * Doing this might result into some form of encryption but its less flexible and tends to be slower than SerialX {@link SerializationProtocol} system! + * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. + * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
+ * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
+ * Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! + * + * @since 1.3.5 + */ + public void setUseBase64IfCan(boolean useBase64IfCan) + { + this.useBase64IfCan = useBase64IfCan; + } + + /** + * @param obj | Object to get protocol for! + * @param mode | Protocol mode! + * @param args | Parser args to get protocol from! + * + * @return Protocol obtained from args or from {@link SerializationProtocol#REGISTRY} if there is no protocol or {@link ProtocolRegistry} in args (index 3).
+ * Note: This is mainly used by {@link ObjectConverter}! + * + * @since 1.3.5 + */ + public static SerializationProtocol getProtocolFor(Object obj, byte mode, Object[] args) + { + if (args.length > 3) + { + if (args[3] instanceof ProtocolRegistry) + return ((ProtocolRegistry) args[3]).GetProtocolFor(obj, mode); + else if (args[3] instanceof SerializationProtocol) + return (SerializationProtocol) args[3]; + } + + return SerializationProtocol.REGISTRY.GetProtocolFor(obj, mode); + } + + /** + * @param str | String to check protocol class for! + * + * @return Class of the protocol or null if inserted statement is not protocol expression! + * For example: getProtocolExprClass("java.util.ArrayList 1 2 3 4 5") will return {@link ArrayList} but "Hello world!" will return null! + * + * @since 1.3.0 + */ + public static Class getProtocolExprClass(String str, Object... compilerArgs) + { + int i = 0, len = str.length(); + for (char ch; i < len; i++) + if ((ch = str.charAt(i)) == ' ' || ch == ':') + break; + + try + { + Class cls = ImportsProvider.forName(compilerArgs.length > 0 ? compilerArgs[0] : null, str.substring(0, i), false, ProtocolConverter.class.getClassLoader()); + if (cls != null) + return cls; + for (char ch; i < len; i++) + { + if ((ch = str.charAt(i)) > 32) + if ((ch | ' ') == '{') + return IsSelectorScope.class; + else + return null; + } + } + catch (ClassNotFoundException e) + {} + return null; + } + + /** + * @param registry | Registry to use! + * @param strs | Source strings to parse using suitable parser from registry. + * @param from | Start index to begin from! + * @param trim | If true, all strings will be trimed before parsing! + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @return Array of parsed objects, each parsed using {@link DataParser#parseObj(String, Object...)} + * + * @since 1.3.0 + */ + public static Object[] parseAll(ParserRegistry registry, String strs[], int from, boolean trim, Object... args) + { + Object[] objs = new Object[strs.length-from]; + for (int i = 0; from < strs.length; from++, i++) + objs[i] = registry.parse(trim ? strs[from].trim() : strs[from], args); + return objs; + } + + /** + * @return Array with 2 preferred sub-scope wrapping chars that are used during serialization by default. { and } + * + * @since 1.3.5 + */ + public static char[] primarySubscopeWrappers() + { + return new char[] {'{', '}'}; + } + + /** + * @return Array with 2 secondary sub-scope wrapping char. [ and ] + * + * @since 1.3.5 + */ + public static char[] secondarySubscopeWrappers() + { + return new char[] {'[', ']'}; + } + + /** + * @param cls | Class to invoke method from. + * @param oldCls | Old class to set (obtained from compilerArgs[4]). + * @param name | Name of public static method to be called. + * @param args | Arguments of method. Arguments should be certain if method is overloaded! + * @param compilerArgs | Arguments provided by parser. + * + * @return {@link Utils#InvokeStaticFunc(Class, String, Object...)} or null if {@link InvocationTargetException} occurred.
+ * Note: If you are not sure what this does, preferably use {@link Utils#InvokeStaticFunc(Class, String, Object...)}! + * + * @since 1.3.7 + */ + public static Object InvokeStaticFunc(Class cls, Class oldCls, String name, Object[] args, Object... compilerArgs) { + try + { + compilerArgs[4] = oldCls; + return Utils.InvokeStaticFunc(cls, name, args); + } + catch (InvocationTargetException e) + { + LogProvider.instance.logErr("Exception while calling method \"" + name + "\":", e); + e.printStackTrace(); + return null; + } + } + + /** + * Used internally by {@link ObjectConverter}!
+ * Dummy class with no purpose except to be mark (.class) for shortened scope expression such as: + * + * shortenedSelectorLikeScope {

+ * //stuff... + * }; + *
+ * + * @author PETO + * + * @since 1.3.0 + */ + protected static class IsSelectorScope {}; +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java index 5ea69be..e2a9662 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java @@ -3,7 +3,7 @@ import java.lang.reflect.Type; import org.ugp.serialx.Serializer; -import org.ugp.serialx.converters.imports.ImportConverter.Imports; +import org.ugp.serialx.converters.imports.ImportsProvider.Imports; /** * This class is represents single import. It stores target class of import and its alias!
@@ -59,13 +59,24 @@ public Import(Class cls, String alias) * @param alias | Alias of class! * @param owner | Owner/provider of this Import! * + * @throws IllegalArgumentException | When alias is invalid! Alias should follow java class naming conventions without necessity of package specification! + * * @since 1.3.5 */ - public Import(Class cls, String alias, ImportsProvider owner) + public Import(Class cls, String alias, ImportsProvider owner) throws IllegalArgumentException { this.cls = cls; - this.alias = alias; - this.owner = owner; + + if (alias.isEmpty()) + throw new IllegalArgumentException("Import alias cant be empty! Try \"" + cls.getSimpleName() + "\" instead!"); + int ch0 = alias.charAt(0); + if (ch0 == '_' || (ch0 = ch0 | ' ') >= 'a' && ch0 <= 'z') + { + this.alias = alias; + this.owner = owner; + } + else + throw new IllegalArgumentException("Import alias \"" + alias + "\" is illegal! Alias cant begin with special char or number! Try \"_" + alias + "\" instead!"); } @Override diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportConverter.java deleted file mode 100644 index 92f8524..0000000 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportConverter.java +++ /dev/null @@ -1,267 +0,0 @@ -package org.ugp.serialx.converters.imports; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; - -import org.ugp.serialx.LogProvider; -import org.ugp.serialx.Scope; -import org.ugp.serialx.Serializer; -import org.ugp.serialx.converters.DataConverter; -import org.ugp.serialx.converters.DataParser; - -/** - * This parser maintains list of {@link Imports#IMPORTS} represented as {@link Import}s. Where are registered imports imported by user as well as temporary imports that are parsed! Result of parsing will be always added to imports list and {@link DataParser#VOID} will be returned! - * Parsing example: import java.util.ArrayList will add temporary {@link Import} of java.util.ArrayList or java.lang.String => Word will import java.lang.String as Word! - * Imports will be converted to string just by calling toString!
- *
- * This parser requires additional parser arg at index 0 of type {@link ImportsProvider} that will obtain managed imports! This arg is required during both parsing and converting! - * - * @author PETO - * - * @since 1.3.0 - */ -public class ImportConverter implements DataConverter -{ - /** - * List of global shared common registered imports! - * - * @since 1.3.0 - */ - public static final Imports IMPORTS = new Imports(new Import(Serializer.class), new Import(Scope.class), new Import(ArrayList.class), new Import(Math.class), new Import(Double.class), new Import(Integer.class), new Import(Double.class, "double"), new Import(Integer.class, "int"), new Import(String.class), new Import(System.class)); - - @Override - public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) - { - if (args.length > 0 && args[0] instanceof ImportsProvider) - { - Imports imports = ((ImportsProvider) args[0]).getImports(); - int index; - if (str.startsWith("import ")) - { - try - { - if ((str = str.substring(7).trim()).indexOf("=>") > -1) - return parse(myHomeRegistry, str, args); - imports.add(new Import(imports.forName(str), (ImportsProvider) args[0])); - } - catch (ClassNotFoundException e) - { - LogProvider.instance.logErr("Unable to import " + str + " because there is no such a class!", e); - } - return VOID; - } - else if ((index = (str = str.trim()).indexOf("=>")) > -1) - { - try - { - imports.add(new Import(imports.forName(str.substring(0, index).trim()), str.substring(index+2).trim(), (ImportsProvider) args[0])); - } - catch (ClassNotFoundException e) - { - LogProvider.instance.logErr("Unable to import " + str.substring(0, index).trim() + " because there is no such a class!", e); - } - return VOID; - } - } - return CONTINUE; - } - - @Override - public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) - { - if (args.length > 0 && args[0] instanceof ImportsProvider && obj instanceof Import) - { - return obj.toString(); - } - return CONTINUE; - } - - @Override - public String getDescription(ParserRegistry myHomeRegistry, Object objToDescribe, Object... argsUsedConvert) - { - return "Import of " + ((Import) objToDescribe).getCls() + " as " + ((Import) objToDescribe).getClsAlias(); - } - - /** - * Collection used to store and operate with {@link Import}! - * - * @author PETO - * - * @since 1.3.5 - * - * @see ImportsProvider - */ - public static class Imports extends ArrayList implements Cloneable, ImportsProvider - { - private static final long serialVersionUID = 8487976264622823940L; - - /** - * Constructs an {@link Imports} with the specified initial capacity. - * - * @param initialSize | Initial capacity. - * - * @since 1.3.5 - */ - public Imports(int initialSize) - { - super(initialSize); - } - - /** - * Constructs an {@link Imports} with inserted imports c. - * - * @param c | Initial content of registry. - * - * @since 1.3.5 - */ - public Imports(Collection c) - { - super(c); - } - - /** - * Constructs an {@link Imports} with inserted imports. - * - * @param parsers | Initial content of registry. - * - * @since 1.3.5 - */ - public Imports(Import... imports) - { - addAll(imports); - } - - @Override - public Imports clone() - { - return new Imports(this); - } - - @Override - public Imports getImports() - { - return this; - } - - /** - * @param imports | Imports to add. - * - * @return {@link ArrayList#addAll(Collection)}; - * - * @since 1.3.5 - */ - public boolean addAll(Import... imports) - { - return super.addAll(Arrays.asList(imports)); - } - - /** - * @param aliasOrName | Alias of class or its full name! - * - * @return Class with inserted alias picked from {@link Imports#IMPORTS} similar to {@link Imports#getClassFor(String)} but this will also search via {@link Class#forName(String, boolean, ClassLoader)} if there is no import with required alias! - * - * @throws ClassNotFoundException when {@link Class#forName(String, boolean, ClassLoader)} throws! - * - * @since 1.3.5 - */ - public Class forName(String aliasOrName) throws ClassNotFoundException - { - return forName(aliasOrName, true, Imports.class.getClassLoader()); - } - - /** - * @param aliasOrName | Alias of class or its full name! - * @param initialize | If true the class will be initialized. See Section 12.4 of The Java Language Specification. - * @param loader | Class loader from which the class must be loaded. - * - * @return Class with inserted alias picked from {@link Imports#IMPORTS} similar to {@link Imports#getClassFor(String)} but this will also search via {@link Class#forName(String, boolean, ClassLoader)} if there is no import with required alias! - * If there are no dots in required alias and alias is not imported then null will be returned! - * - * @throws ClassNotFoundException when {@link Class#forName(String, boolean, ClassLoader)} throws! - * - * @since 1.3.5 - */ - public Class forName(String aliasOrName, boolean initialize, ClassLoader loader) throws ClassNotFoundException - { - Class cls = getClassFor(aliasOrName); - if (cls != null) - return cls; - if (aliasOrName.indexOf('.') > 0) - return Class.forName(aliasOrName, initialize, loader); - /*try - { - return Class.forName("java.lang."+aliasOrName, initialize, loader); - } - catch (Exception e) - { - return null; - }*/ - return null; - } - - /** - * @param cls | Class to get alias for! - * - * @return Alias of class picked from {@link Imports#IMPORTS} or name of class if there is no import for this class! - * - * @since 1.3.5 - */ - public String getAliasFor(Class cls) - { - for (int i = size() - 1; i >= 0; i--) - { - Import imp = get(i); - if (imp.equals(cls)) - return imp.getClsAlias(); - } - return cls.getName(); - } - - /** - * @param alias | Alias of class to obtain! - * - * @return Class with inserted alias picked from {@link Imports#IMPORTS} or null if there is no import with required alias! - * - * @since 1.3.5 - */ - public Class getClassFor(String alias) - { - for (int i = size() - 1; i >= 0; i--) - { - Import imp = get(i); - if (imp.equals(alias)) - return imp.getCls(); - } - return null; - } - - /** - * @param owner | Owner of imports to get! - * - * @return Imports of provided owner stored by this list! - * - * @since 1.3.5 - */ - public Imports importsOf(ImportsProvider owner) - { - Imports imports = new Imports(); - for (Import imp : imports) - if (imp.getOwner() == owner) - imports.add(imp); - return imports; - } - - /** - * @param owner | Owner of imports to remove from this list! - * - * @since 1.3.5 - */ - public void removeImportsOf(ImportsProvider owner) - { - for (int i = size() - 1; i >= 0; i--) - if (get(i).getOwner() == owner) - remove(i); - } - } -} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java index 5afa8a4..06a89a7 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java @@ -1,8 +1,13 @@ package org.ugp.serialx.converters.imports; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; -import org.ugp.serialx.converters.imports.ImportConverter.Imports; +import org.ugp.serialx.Scope; +import org.ugp.serialx.Serializer; /** * This interface is supposed to be implemented by class that can provide array of imports! @@ -13,6 +18,21 @@ */ public interface ImportsProvider { + /** + * Cache of Classes to their respective names/aliases.
+ * Note: Treat as read only if possible! + * + * @since 1.3.7 + */ + public static final Map> CLASS_CACHE = new HashMap>(); + + /** + * List of global shared common registered imports! + * + * @since 1.3.0 + */ + public static final Imports IMPORTS = new Imports(new Import(Serializer.class), new Import(Scope.class), new Import(ArrayList.class), new Import(Math.class), new Import(Double.class), new Import(Integer.class), new Import(Double.class, "double"), new Import(Integer.class, "int"), new Import(String.class), new Import(System.class)); + /** * @return Array of provided imports! * @@ -83,8 +103,16 @@ public static Class forName(Object importProvider, String aliasOrName, boolea Class cls = getClassFor(importProvider, aliasOrName); if (cls != null) return cls; - if (aliasOrName.indexOf('.') > 0) - return Class.forName(aliasOrName, initialize, loader); + + if ((cls = CLASS_CACHE.get(aliasOrName)) != null) + return cls; + if (aliasOrName.indexOf('.') > 0) + { + cls = Class.forName(aliasOrName, initialize, loader); + CLASS_CACHE.put(aliasOrName, cls); + return cls; + } + /*try { return Class.forName("java.lang."+aliasOrName, initialize, loader); @@ -127,4 +155,193 @@ public static Class getClassFor(Object importProvider, String alias) Imports imports = importsOf(importProvider); return imports != null ? imports.getClassFor(alias) : null; } + + /** + * Collection used to store and operate with {@link Import}! + * + * @author PETO + * + * @since 1.3.5 + * + * @see ImportsProvider + */ + public static class Imports extends ArrayList implements Cloneable, ImportsProvider + { + private static final long serialVersionUID = 8487976264622823940L; + + /** + * Constructs an {@link Imports} with the specified initial capacity. + * + * @param initialSize | Initial capacity. + * + * @since 1.3.5 + */ + public Imports(int initialSize) + { + super(initialSize); + } + + /** + * Constructs an {@link Imports} with inserted imports c. + * + * @param c | Initial content of registry. + * + * @since 1.3.5 + */ + public Imports(Collection c) + { + super(c); + } + + /** + * Constructs an {@link Imports} with inserted imports. + * + * @param parsers | Initial content of registry. + * + * @since 1.3.5 + */ + public Imports(Import... imports) + { + addAll(imports); + } + + @Override + public Imports clone() + { + return new Imports(this); + } + + @Override + public Imports getImports() + { + return this; + } + + /** + * @param imports | Imports to add. + * + * @return {@link ArrayList#addAll(Collection)}; + * + * @since 1.3.5 + */ + public boolean addAll(Import... imports) + { + return super.addAll(Arrays.asList(imports)); + } + + /** + * @param aliasOrName | Alias of class or its full name! + * + * @return Class with inserted alias picked from {@link Imports#IMPORTS} similar to {@link Imports#getClassFor(String)} but this will also search via {@link Class#forName(String, boolean, ClassLoader)} if there is no import with required alias! + * + * @throws ClassNotFoundException when {@link Class#forName(String, boolean, ClassLoader)} throws! + * + * @since 1.3.5 + */ + public Class forName(String aliasOrName) throws ClassNotFoundException + { + return forName(aliasOrName, true, Imports.class.getClassLoader()); + } + + /** + * @param aliasOrName | Alias of class or its full name! + * @param initialize | If true the class will be initialized. See Section 12.4 of The Java Language Specification. + * @param loader | Class loader from which the class must be loaded. + * + * @return Class with inserted alias picked from {@link Imports#IMPORTS} similar to {@link Imports#getClassFor(String)} but this will also search via {@link Class#forName(String, boolean, ClassLoader)} if there is no import with required alias! + * If there are no dots in required alias and alias is not imported then null will be returned! + * + * @throws ClassNotFoundException when {@link Class#forName(String, boolean, ClassLoader)} throws! + * + * @since 1.3.5 + */ + public Class forName(String aliasOrName, boolean initialize, ClassLoader loader) throws ClassNotFoundException + { + Class cls = getClassFor(aliasOrName); + if (cls != null) + return cls; + + if ((cls = CLASS_CACHE.get(aliasOrName)) != null) + return cls; + if (aliasOrName.indexOf('.') > 0) + { + cls = Class.forName(aliasOrName, initialize, loader); + CLASS_CACHE.put(aliasOrName, cls); + return cls; + } + /*try + { + return Class.forName("java.lang."+aliasOrName, initialize, loader); + } + catch (Exception e) + { + return null; + }*/ + return null; + } + + /** + * @param cls | Class to get alias for! + * + * @return Alias of class picked from {@link Imports#IMPORTS} or name of class if there is no import for this class! + * + * @since 1.3.5 + */ + public String getAliasFor(Class cls) + { + for (int i = size() - 1; i >= 0; i--) + { + Import imp = get(i); + if (imp.equals(cls)) + return imp.getClsAlias(); + } + return cls.getName(); + } + + /** + * @param alias | Alias of class to obtain! + * + * @return Class with inserted alias picked from {@link Imports#IMPORTS} or null if there is no import with required alias! + * + * @since 1.3.5 + */ + public Class getClassFor(String alias) + { + for (int i = size() - 1; i >= 0; i--) + { + Import imp = get(i); + if (imp.equals(alias)) + return imp.getCls(); + } + return null; + } + + /** + * @param owner | Owner of imports to get! + * + * @return Imports of provided owner stored by this list! + * + * @since 1.3.5 + */ + public Imports importsOf(ImportsProvider owner) + { + Imports imports = new Imports(); + for (Import imp : imports) + if (imp.getOwner() == owner) + imports.add(imp); + return imports; + } + + /** + * @param owner | Owner of imports to remove from this list! + * + * @since 1.3.5 + */ + public void removeImportsOf(ImportsProvider owner) + { + for (int i = size() - 1; i >= 0; i--) + if (get(i).getOwner() == owner) + remove(i); + } + } } \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializableProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializableProtocol.java index 466a06c..d4eac0d 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializableProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializableProtocol.java @@ -11,16 +11,15 @@ */ public class SelfSerializableProtocol extends UniversalObjectInstantiationProtocol { - @Override - public Object[] serialize(SelfSerializable object) + public SelfSerializableProtocol() { - return object.serialize(); + super(SelfSerializable.class); } - + @Override - public Class applicableFor() + public Object[] serialize(SelfSerializable object) { - return SelfSerializable.class; + return object.serialize(); } @Override diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java index 16e65ba..7aab546 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java @@ -30,7 +30,7 @@ public abstract class SerializationProtocol * * @since 1.3.0 */ - public static final ProtocolRegistry REGISTRY = new ProtocolRegistry(new UniversalObjectInstantiationProtocol(), new ListProtocol(), new MapProtocol(), new StringProtocol(), new ScopeProtocol(), new SelfSerializableProtocol(), new EnumProtocol()); + public static final ProtocolRegistry REGISTRY = new ProtocolRegistry(new UniversalObjectInstantiationProtocol<>(Object.class), new ListProtocol(), new MapProtocol(), new StringProtocol(), new ScopeProtocol(), new SelfSerializableProtocol(), new EnumProtocol()); /** * This mode is for protocols that are used for serialization only! diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java index c058b89..b941f2b 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java @@ -18,6 +18,18 @@ */ public class UniversalObjectInstantiationProtocol extends SerializationProtocol { + protected final Class applicableFor; + + /** + * @param applicableFor | Class that can be serialized using this protocol. + * + * @since 1.3.7 + */ + public UniversalObjectInstantiationProtocol(Class applicableFor) + { + this.applicableFor = applicableFor; + } + @Override public Object[] serialize(T object) { @@ -46,11 +58,10 @@ public T unserialize(Class objectClass, Object... args) throws Exce return null; } - @SuppressWarnings("unchecked") @Override public Class applicableFor() { - return (Class) Object.class; + return applicableFor; } @Override diff --git a/SerialX-json/pom.xml b/SerialX-json/pom.xml index bf6b4db..3477e6c 100644 --- a/SerialX-json/pom.xml +++ b/SerialX-json/pom.xml @@ -16,7 +16,7 @@ org.ugp.serialx - core + juss ${revision} diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java index 45060e3..ef140db 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java @@ -19,7 +19,6 @@ import java.util.Map.Entry; import org.ugp.serialx.GenericScope; -import org.ugp.serialx.JussSerializer; import org.ugp.serialx.Registry; import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; @@ -28,10 +27,11 @@ import org.ugp.serialx.converters.DataParser.ParserRegistry; import org.ugp.serialx.converters.NullConverter; import org.ugp.serialx.converters.StringConverter; -import org.ugp.serialx.converters.VariableConverter; import org.ugp.serialx.json.converters.JsonCharacterConverter; import org.ugp.serialx.json.converters.JsonNumberConverter; import org.ugp.serialx.json.converters.JsonObjectConverter; +import org.ugp.serialx.juss.JussSerializer; +import org.ugp.serialx.juss.converters.VariableConverter; import org.ugp.serialx.protocols.SerializationProtocol; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java index 255591d..1807b9e 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java @@ -2,9 +2,9 @@ import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; -import org.ugp.serialx.converters.ArrayConverter; -import org.ugp.serialx.converters.ObjectConverter; +import org.ugp.serialx.Utils; import org.ugp.serialx.json.JsonSerializer; +import org.ugp.serialx.juss.converters.ObjectConverter; import org.ugp.serialx.protocols.SerializationProtocol; /** @@ -21,7 +21,7 @@ public class JsonObjectConverter extends ObjectConverter public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) { if (arg.getClass().isArray()) - arg = new Scope(ArrayConverter.fromAmbiguous(arg)); + arg = new Scope(Utils.fromAmbiguousArray(arg)); SerializationProtocol prot = (SerializationProtocol) getProtocolFor(arg, SerializationProtocol.MODE_SERIALIZE, args); diff --git a/SerialX-juss/pom.xml b/SerialX-juss/pom.xml index bc08a57..2c451bd 100644 --- a/SerialX-juss/pom.xml +++ b/SerialX-juss/pom.xml @@ -12,4 +12,12 @@ SerialX-juss SerialX support for Java Universal Serial Script data format, custom default format of SerialX! + + + + org.ugp.serialx + core + ${revision} + + \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java similarity index 94% rename from SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java rename to SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index 7cb815e..fa667f3 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -1,4 +1,4 @@ -package org.ugp.serialx; +package org.ugp.serialx.juss; import static org.ugp.serialx.Utils.Clone; import static org.ugp.serialx.Utils.InvokeStaticFunc; @@ -25,14 +25,26 @@ import java.util.Map; import java.util.Map.Entry; +import org.ugp.serialx.GenericScope; +import org.ugp.serialx.Registry; +import org.ugp.serialx.Scope; +import org.ugp.serialx.Serializer; import org.ugp.serialx.Utils.NULL; +import org.ugp.serialx.converters.BooleanConverter; +import org.ugp.serialx.converters.CharacterConverter; import org.ugp.serialx.converters.DataConverter; import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.converters.DataParser.ParserRegistry; -import org.ugp.serialx.converters.ObjectConverter; -import org.ugp.serialx.converters.imports.ImportConverter; -import org.ugp.serialx.converters.imports.ImportConverter.Imports; +import org.ugp.serialx.converters.NullConverter; +import org.ugp.serialx.converters.NumberConverter; +import org.ugp.serialx.converters.SerializableBase64Converter; +import org.ugp.serialx.converters.StringConverter; import org.ugp.serialx.converters.imports.ImportsProvider; +import org.ugp.serialx.juss.converters.ArrayConverter; +import org.ugp.serialx.juss.converters.ImportConverter; +import org.ugp.serialx.juss.converters.ObjectConverter; +import org.ugp.serialx.juss.converters.OperationGroups; +import org.ugp.serialx.juss.converters.VariableConverter; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; /** @@ -43,7 +55,6 @@ * * @since 1.3.2 */ -//TODO: Separate to SerialX-juss together with parsers and stuff @SuppressWarnings("serial") public class JussSerializer extends Serializer implements ImportsProvider { @@ -52,7 +63,7 @@ public class JussSerializer extends Serializer implements ImportsProvider * * @since 1.3.2 */ - public static final ParserRegistry JUSS_PARSERS = DataParser.REGISTRY.clone(); + public static final ParserRegistry JUSS_PARSERS = new ParserRegistry(new OperationGroups(), new VariableConverter(), new StringConverter(), new ObjectConverter(), new ArrayConverter(), new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter()); /** * {@link ParserRegistry} with all parsers required to parse JUSS with additional operators. @@ -185,7 +196,7 @@ public ParserRegistry getParsers() public Imports getImports() { if (imports == null) - imports = ImportConverter.IMPORTS.clone(); + imports = ImportsProvider.IMPORTS.clone(); return imports; } @@ -439,7 +450,7 @@ else if (notString && ch == '/' && i < len-1 && line.charAt(i+1) == '*') { if (notString) { - if (ch == '{' || ch == '[') + if (ch | ' ') == '{' || ch == '[') brackets++; else if (ch == '}' || ch == ']') { @@ -486,10 +497,10 @@ else if (ch == '}' || ch == ']') if (parent == null) getImports().removeImportsOf(this); - else - for (Map.Entry ent : parent.varEntrySet()) - if (variables().get(ent.getKey()) == ent.getValue()) - variables().remove(ent.getKey());//TODO: Prevent neccesity of scope parent inheritance. +// else +// for (Map.Entry ent : parent.varEntrySet()) +// if (variables().get(ent.getKey()) == ent.getValue()) +// variables().remove(ent.getKey());//TODO: Prevent neccesity of scope parent inheritance. return (S) this; } @@ -538,7 +549,7 @@ else if (notString && ch >= 9 && ch <= 13) { /*if (notString) { - if (ch == '{' || ch == '[') + if (ch | ' ') == '{' || ch == '[') brackets++; else if (ch == '}' || ch == ']') { @@ -614,9 +625,9 @@ protected List splitAndParse(String formattedStr, int offset, Object... } //add = 1; } - else if (ch == '{' || ch == '[') + else if ((ch | ' ') == '{') brackets++; - else if (ch == '}' || ch == ']') + else if ((ch | ' ') == '}') { if (brackets > 0) brackets--; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java similarity index 64% rename from SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java rename to SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java index 45e756a..7ba3db7 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ArrayConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java @@ -1,13 +1,11 @@ -package org.ugp.serialx.converters; +package org.ugp.serialx.juss.converters; -import static org.ugp.serialx.Utils.ToClasses; +import static org.ugp.serialx.Utils.castArray; +import static org.ugp.serialx.Utils.fromAmbiguousArray; import static org.ugp.serialx.Utils.indexOfNotInObj; import static org.ugp.serialx.Utils.splitValues; -import java.lang.reflect.Array; -import java.util.Arrays; - -import org.ugp.serialx.converters.imports.ImportsProvider; +import org.ugp.serialx.converters.DataConverter; /** * This converter is capable of converting primitive arrays. @@ -101,13 +99,13 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object.. if (args.length > 2) args[2] = index + 1; - Object[] elms = fromAmbiguous(obj); + Object[] elms = fromAmbiguousArray(obj); StringBuilder sb = new StringBuilder(); for (int i = 0, length = elms.length, sizeEndl = 10000; i < length; i++) { CharSequence str = myHomeRegistry.toString(elms[i], args); char ch = str.charAt(0); - if (ch == '{' || ch == '[') + if ((ch | ' ') == '{') sb.append("("+str+")"); else sb.append(str); @@ -146,60 +144,4 @@ public String[] tokenize(String str) { return splitValues(str, ' '); } - - /** - * @param sourceArray | Array to cast! - * @param toType | Type to cast array in to! - * - * @return Array object casted in to required type! - * - * @since 1.3.2 - */ - public static Object castArray(Object[] sourceArray, Class toType) - { - int len = sourceArray.length; - Object arr = Array.newInstance(ToClasses(toType)[0], len); - for (int i = 0; i < len; i++) - Array.set(arr, i, sourceArray[i]); - return arr; - } - - /** - * @param arr1 | Object one that might be array! - * @param arr2 | Object two that might be array! - * - * @return New array consisting of array 1 and array 2! - * - * @throws IllegalArgumentException if object one is not an array! - * - * @since 1.3.2 - */ - public static Object[] mergeArrays(Object arr1, Object arr2) - { - Object[] array1 = fromAmbiguous(arr1), array2 = arr2.getClass().isArray() ? fromAmbiguous(arr2) : new Object[] {arr2}; - Object[] result = Arrays.copyOf(array1, array1.length + array2.length); - System.arraycopy(array2, 0, result, array1.length, array2.length); - return result; - } - - /** - * @param array | Object that might be array! - * - * @return Object transformed in to primitive array! If array is already an instance of primitive array then it will be simply returned! - * - * @throws IllegalArgumentException if the specified object is not an array! - * - * @since 1.3.2 - */ - public static Object[] fromAmbiguous(Object array) - { - if (array instanceof Object[]) - return (Object[]) array; - - int len = Array.getLength(array); - Object[] arr = new Object[len]; - for (int i = 0; i < len; i++) - arr[i] = Array.get(array, i); - return arr; - } } \ No newline at end of file diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ImportConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ImportConverter.java new file mode 100644 index 0000000..9812b9d --- /dev/null +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ImportConverter.java @@ -0,0 +1,79 @@ +package org.ugp.serialx.juss.converters; + +import org.ugp.serialx.LogProvider; +import org.ugp.serialx.converters.DataConverter; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.converters.imports.Import; +import org.ugp.serialx.converters.imports.ImportsProvider; +import org.ugp.serialx.converters.imports.ImportsProvider.Imports; + +/** + * This parser maintains list of {@link Imports#IMPORTS} represented as {@link Import}s. Where are registered imports imported by user as well as temporary imports that are parsed! Result of parsing will be always added to imports list and {@link DataParser#VOID} will be returned! + * Parsing example: import java.util.ArrayList will add temporary {@link Import} of java.util.ArrayList or java.lang.String => Word will import java.lang.String as Word! + * Imports will be converted to string just by calling toString!
+ *
+ * This parser requires additional parser arg at index 0 of type {@link ImportsProvider} that will obtain managed imports! This arg is required during both parsing and converting! + * + * @author PETO + * + * @since 1.3.0 + */ +public class ImportConverter implements DataConverter +{ + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + if (args.length > 0 && args[0] instanceof ImportsProvider) + { + Imports imports = ((ImportsProvider) args[0]).getImports(); + int index; + if (str.startsWith("import ")) + { + try + { + if ((str = str.substring(7).trim()).indexOf("=>") > -1) + return parse(myHomeRegistry, str, args); + imports.add(new Import(imports.forName(str), (ImportsProvider) args[0])); + } + catch (ClassNotFoundException e) + { + LogProvider.instance.logErr("Unable to import " + str + " because there is no such a class!", e); + } + return VOID; + } + else if ((index = (str = str.trim()).indexOf("=>")) > -1) + { + try + { + imports.add(new Import(imports.forName(str.substring(0, index).trim()), str.substring(index+2).trim(), (ImportsProvider) args[0])); + } + catch (ClassNotFoundException e) + { + LogProvider.instance.logErr("Unable to import " + str.substring(0, index).trim() + " because there is no such a class!", e); + } + catch (Exception e2) + { + LogProvider.instance.logErr(e2.getMessage(), e2); + } + return VOID; + } + } + return CONTINUE; + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) + { + if (args.length > 0 && args[0] instanceof ImportsProvider && obj instanceof Import) + { + return obj.toString(); + } + return CONTINUE; + } + + @Override + public String getDescription(ParserRegistry myHomeRegistry, Object objToDescribe, Object... argsUsedConvert) + { + return "Import of " + ((Import) objToDescribe).getCls() + " as " + ((Import) objToDescribe).getClsAlias(); + } +} \ No newline at end of file diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java new file mode 100644 index 0000000..57c222f --- /dev/null +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java @@ -0,0 +1,199 @@ +package org.ugp.serialx.juss.converters; + +import static org.ugp.serialx.Utils.indexOfNotInObj; + +import java.io.IOException; +import java.io.Serializable; +import java.io.StringReader; +import java.util.Arrays; +import java.util.Base64; + +import org.ugp.serialx.GenericScope; +import org.ugp.serialx.Registry; +import org.ugp.serialx.Scope; +import org.ugp.serialx.Serializer; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.converters.ProtocolConverter; +import org.ugp.serialx.converters.SerializableBase64Converter; +import org.ugp.serialx.converters.imports.ImportsProvider; +import org.ugp.serialx.juss.JussSerializer; +import org.ugp.serialx.protocols.SerializationProtocol; +import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; + +/** + * This converter is capable of converting any Object using {@link SerializationProtocol} as well as invoking static functions! + * This is also responsible for {@link Scope}! + * Its case sensitive! + *
+ *
+ * Table of sample string <--> object conversions: + * + + + + + + + + + + + + + +
StringObject
ArrayList 2 4 6new ArrayList<>(Arrays.asList(2, 4, 6))
java.lang.Math::max 10 510
+
+ This parser requires additional parser arg at index 0 of type {@link GenericScope} or {@link Serializer} that will be used for further parsing and operating (default new {@link JussSerializer}).
+ This parser requires additional parser arg at index 3 of type {@link ProtocolRegistry} or {@link SerializationProtocol} itself that will be used for parsing protocol expressions (default {@link SerializationProtocol#REGISTRY}).
+ * This parser will insert one additional argument into array of additional parser args at index 4, in case of serialization index 5, that will be of type {@link Class} and it will contains information about class of object that is being unserialized or serialized using protocol!
+ * + * @author PETO + * + * @since 1.3.0 + */ +public class ObjectConverter extends ProtocolConverter +{ + /** + * Set this on true to force program to use {@link Base64} serialization on {@link Serializable} objects. + * Doing this might result into some form of encryption but its less flexible and tends to be slower than SerialX {@link SerializationProtocol} system! + * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. + * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
+ * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
+ * Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! + * + * @since 1.0.0 (moved to {@link SerializableBase64Converter} since 1.3.0 and since 1.3.5 into {@link ObjectConverter}) + */ + protected boolean useBase64IfCan = false; + + @SuppressWarnings("unchecked") + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... compilerArgs) + { + int len; + if ((len = str.length()) > 0) + { + boolean hasOp, hasCls = false; + if ((hasOp = (str.charAt(0) | ' ') == '{') && (hasCls = (str.charAt(--len) | ' ') == '}')) // Unwrap if wrapped in {} + len = (str = str.substring(1, len).trim()).length(); + + Class objClass; + int chI; + if (((chI = indexOfNotInObj(str, '=', ':', ';', ',')) < 0 || (++chI < len && str.charAt(chI) == ':')) && (objClass = getProtocolExprClass(str, compilerArgs)) != null) // Is protocol expr + return parse(myHomeRegistry, objClass, str, compilerArgs); + + if (hasOp && hasCls) //Is scope + { + Serializer scope; + try //Create desired new empty instance of scope/serializer + { + if (compilerArgs.length > 0 && compilerArgs[0] instanceof Serializer) + { + if (compilerArgs.length > 4 && compilerArgs[4] instanceof Class && Serializer.class.isAssignableFrom((Class) compilerArgs[4])) + scope = ((Serializer) compilerArgs[0]).emptyClone((Class) compilerArgs[4], (GenericScope) compilerArgs[0]); + else + scope = ((Serializer) compilerArgs[0]).emptyClone(); + } + else + scope = getPreferredSerializer(); + } + catch (Exception e) + { + scope = getPreferredSerializer(); + } + + //TODO: Prevent neccesity of scope parent inheritance. + return str.isEmpty() ? scope : ((Serializer) scope/*.inheritParent()*/).LoadFrom(new StringReader(str), compilerArgs); + } + } + return CONTINUE; + } + + @Override + public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) + { + return toString(myHomeRegistry, arg, null, args); + } + + /** + * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @param obj | Object to convert into string! + * @param preferedProtocol | Protocol to use preferably. + * @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)! + * + * @return Object converted to string. Easiest way to do this is obj.toString() but you most likely want some more sofisticated formating. + * 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! + * + * @since 1.3.5 + */ + @SuppressWarnings("unchecked") + public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, SerializationProtocol preferedProtocol, Object... args) + { + if (arg instanceof Scope) + { + Serializer serializer; + try + { + if (arg instanceof Serializer) + serializer = (Serializer) arg; + else if (args.length > 0 && args[0] instanceof Serializer) + (serializer = ((Serializer) args[0]).emptyClone()).addAll((GenericScope) arg); + else + serializer = getPreferredSerializer(); + } + catch (Exception e) + { + serializer = getPreferredSerializer(); + } + + if (serializer instanceof JussSerializer) + ((JussSerializer) serializer).setGenerateComments(args.length > 5 && args[5] instanceof Boolean && (boolean) args[5]); + + try + { + if (args.length < 4) + args = Arrays.copyOf(args, 4); + else + args = args.clone(); + args[2] = 0; + args[3] = serializer.getProtocols(); + + StringBuilder sb = new StringBuilder(); + GenericScope parent; + if ((parent = serializer.getParent()) == null || serializer.getClass() != parent.getClass()) + sb.append(ImportsProvider.getAliasFor(serializer, getClass()) + " "); + return serializer.SerializeAsSubscope(sb, args); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + return super.toString(myHomeRegistry, arg, preferedProtocol, args); + } + + @Override + public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) + { + if (obj instanceof Scope && ((Scope) obj).isEmpty()) + return "Empty scope!"; + else if (obj instanceof CharSequence && indexOfNotInObj((CharSequence) obj, '\n', '\r') != -1) + return "Multiline char sequence!"; + return new StringBuilder("Object of ").append(obj.getClass().getName()).append(": \"").append(obj.toString()).append("\" serialized using ").append(getProtocolFor(obj, SerializationProtocol.MODE_ALL, argsUsedConvert).toString()).append("!"); + } + + /** + * @return Serializer that is supposed to be used for serializing sub-scopes if there is no other option. This should never return null! + * + * @since 1.3.5 + */ + public Serializer getPreferredSerializer() + { + return new JussSerializer(); + } +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverterOld.java similarity index 96% rename from SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java rename to SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverterOld.java index 021a6b0..f4d2d3a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ObjectConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverterOld.java @@ -1,4 +1,4 @@ -package org.ugp.serialx.converters; +package org.ugp.serialx.juss.converters; import static org.ugp.serialx.Utils.Instantiate; import static org.ugp.serialx.Utils.InvokeStaticFunc; @@ -15,12 +15,16 @@ import java.util.Base64; import org.ugp.serialx.GenericScope; -import org.ugp.serialx.JussSerializer; import org.ugp.serialx.LogProvider; import org.ugp.serialx.Registry; import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; +import org.ugp.serialx.converters.DataConverter; +import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.converters.DataParser.ParserRegistry; +import org.ugp.serialx.converters.SerializableBase64Converter; import org.ugp.serialx.converters.imports.ImportsProvider; +import org.ugp.serialx.juss.JussSerializer; import org.ugp.serialx.protocols.SerializationProtocol; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; @@ -60,7 +64,7 @@ * * @since 1.3.0 */ -public class ObjectConverter implements DataConverter +public class ObjectConverterOld implements DataConverter { /** * Set this on true to force program to use {@link Base64} serialization on {@link Serializable} objects. @@ -70,7 +74,7 @@ public class ObjectConverter implements DataConverter * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
* Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! * - * @since 1.0.0 (moved to {@link SerializableBase64Converter} since 1.3.0 and since 1.3.5 into {@link ObjectConverter}) + * @since 1.0.0 (moved to {@link SerializableBase64Converter} since 1.3.0 and since 1.3.5 into {@link ObjectConverterOld}) */ protected boolean useBase64IfCan = false; @@ -86,7 +90,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... compile { if (objectClass != null) //TODO: Preferably separate this to ProtocolConverter { - if (objectClass == IsSelectorScope.class) + if (objectClass == IsSelectorScope.class) { StringBuilder sb = new StringBuilder(str); sb.setCharAt(str.indexOf(' '), '='); @@ -420,7 +424,7 @@ public void setUseBase64IfCan(boolean useBase64IfCan) * @param args | Parser args to get protocol from! * * @return Protocol obtained from args or from {@link SerializationProtocol#REGISTRY} if there is no protocol or {@link ProtocolRegistry} in args (index 3).
- * Note: This is mainly used by {@link ObjectConverter}! + * Note: This is mainly used by {@link ObjectConverterOld}! * * @since 1.3.5 */ @@ -451,10 +455,9 @@ public static Class getProtocolExprClass(String str, Object[] compilerArgs) for (char ch; i < len; i++) if ((ch = str.charAt(i)) == ' ' || ch == ':') break; - try { - Class cls = ImportsProvider.forName(compilerArgs.length > 0 ? compilerArgs[0] : null, str.substring(0, i), false, ObjectConverter.class.getClassLoader()); + Class cls = ImportsProvider.forName(compilerArgs.length > 0 ? compilerArgs[0] : null, str.substring(0, i), false, ObjectConverterOld.class.getClassLoader()); if (cls != null) return cls; for (char ch; i < len; i++) @@ -511,7 +514,7 @@ public static char[] secondarySubscopeWrappers() } /** - * Used internally by {@link ObjectConverter}!
+ * Used internally by {@link ObjectConverterOld}!
* Dummy class with no purpose except to be mark (.class) for shortened scope expression such as: * * shortenedSelectorLikeScope {

@@ -523,5 +526,5 @@ public static char[] secondarySubscopeWrappers() * * @since 1.3.0 */ - protected static class IsSelectorScope {}; + public static class IsSelectorScope {}; } \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java similarity index 96% rename from SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java rename to SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java index 8374a40..005603d 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/OperationGroups.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java @@ -1,4 +1,4 @@ -package org.ugp.serialx.converters; +package org.ugp.serialx.juss.converters; import static org.ugp.serialx.Utils.isOneOf; @@ -8,6 +8,7 @@ import org.ugp.serialx.LogProvider; import org.ugp.serialx.Serializer; +import org.ugp.serialx.converters.DataParser; /** * This parser provides ability to use expression groups that can define order of expression evaluation and compilation! @@ -122,9 +123,9 @@ public static int indexOfOpening(CharSequence str, int from, char... openings) quote++; else if (quote % 2 == 0) { - if (ch == '{' || ch == '[') + if ((ch | ' ') == '{') brackets++; - else if (ch == '}' || ch == ']') + else if ((ch | ' ') == '}') { if (brackets > 0) brackets--; @@ -158,9 +159,9 @@ public static int indexOfClosing(CharSequence str, int from, char[] openings, ch quote++; else if (quote % 2 == 0) { - if (ch == '{' || ch == '[') + if ((ch | ' ') == '{') brackets++; - else if (ch == '}' || ch == ']') + else if ((ch | ' ') == '}') { if (brackets > 0) brackets--; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java similarity index 95% rename from SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java rename to SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index 7d51f0b..a7374d4 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -1,4 +1,4 @@ -package org.ugp.serialx.converters; +package org.ugp.serialx.juss.converters; import static org.ugp.serialx.Utils.Clone; import static org.ugp.serialx.Utils.contains; @@ -15,6 +15,7 @@ import org.ugp.serialx.LogProvider; import org.ugp.serialx.Scope; import org.ugp.serialx.Utils.NULL; +import org.ugp.serialx.converters.DataConverter; /** * This converter is capable of converting {@link Map.Entry} and reading variables from {@link Scope} via "$"! @@ -194,9 +195,9 @@ public static boolean isVarAssignment(CharSequence s) return false; else if (brackets == 0 && (ch == '=' || ch == ':') && !(oldCh == '=' || oldCh == ':' || oldCh == '!' || oldCh == '>'|| oldCh == '<') && (i >= len-1 || !((chNext = s.charAt(i+1)) == '=' || chNext == ':' || chNext == '!' || chNext == '>'|| chNext == '<'))) return true; - else if (ch == '{' || ch == '[') + else if ((ch | ' ') == '{') brackets++; - else if (ch == '}' || ch == ']') + else if ((ch | ' ') == '}') if (brackets > 0) brackets--; } @@ -205,6 +206,13 @@ else if (ch == '}' || ch == ']') return false; } +// public static V getValueOf(GenericScope scope, K... pathToScope) +// { +// +// if (scope.containsVariable(pathToScope[0])) +// return scope.getGenericScope(pathToScope); +// } + /** * @param varName | Name of variable. * @param varValue | Value of variable. diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java index ab17c54..c05f137 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -11,7 +11,7 @@ import org.ugp.serialx.LogProvider; import org.ugp.serialx.Scope; -import org.ugp.serialx.converters.ArrayConverter; +import org.ugp.serialx.Utils; import org.ugp.serialx.converters.DataParser; /** @@ -64,7 +64,7 @@ protected Object eval(ParserRegistry registryForParsers, String expr, Object... cof1 = cofs.get(index = index < 0 ? 0 : index); if (cof1 instanceof String) - cof1 = registryForParsers.parse(cof1.toString().trim(), i > 0, new Class[] {getClass(), ArrayConverter.class}, argsForParsers); + cof1 = registryForParsers.parse(cof1.toString().trim(), i > 0, new Class[] {getClass()}, argsForParsers); cof1 = cof1 instanceof ResultWrapper ? ((ResultWrapper) cof1).obj : cof1; cof2 = cofs.remove(index + 1); @@ -186,14 +186,14 @@ public static Object add(Object cof, Object cof2) } if (cof.getClass().isArray()) - return ArrayConverter.mergeArrays(cof, cof2); + return Utils.mergeArrays(cof, cof2); if (cof instanceof Collection) { if (cof2 instanceof Collection) ((Collection) cof).addAll(((Collection) cof2)); else if (cof2.getClass().isArray()) - ((Collection) cof).addAll(Arrays.asList(ArrayConverter.fromAmbiguous(cof2))); + ((Collection) cof).addAll(Arrays.asList(Utils.fromAmbiguousArray(cof2))); else ((Collection) cof).add(cof2); return cof; @@ -206,7 +206,7 @@ else if (cof2.getClass().isArray()) else if (cof2 instanceof Collection) ((Scope) cof).addAll((Collection) cof2); else if (cof2.getClass().isArray()) - ((Scope) cof).addAll(ArrayConverter.fromAmbiguous(cof2)); + ((Scope) cof).addAll(Utils.fromAmbiguousArray(cof2)); else ((Scope) cof).add(cof2); return cof; @@ -241,7 +241,7 @@ public static Object sub(Object cof, Object cof2) if (cof2 instanceof Collection) ((Collection) cof).removeAll(((Collection) cof2)); else if (cof2.getClass().isArray()) - ((Collection) cof).removeAll(Arrays.asList(ArrayConverter.fromAmbiguous(cof2))); + ((Collection) cof).removeAll(Arrays.asList(Utils.fromAmbiguousArray(cof2))); else ((Collection) cof).remove(cof2); return cof; @@ -370,9 +370,9 @@ public static List[] getTerms(String str, char... oprs) char ch = str.charAt(i); if (ch == '\"') quote++; - else if (ch == '{' || ch == '[') + else if ((ch | ' ') == '{') brackets++; - else if (ch == '}' || ch == ']') + else if ((ch | ' ') == '}') brackets--; if (type == 1 || quote % 2 == 0 && brackets == 0) @@ -420,9 +420,9 @@ public static boolean isExpression(CharSequence str, char... operators) quote++; else if (quote % 2 == 0) { - if (ch == '{' || ch == '[') + if ((ch | ' ') == '{') brackets++; - else if (ch == '}' || ch == ']') + else if ((ch | ' ') == '}') brackets--; else if (brackets == 0) { diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java index 9925c3a..102e19c 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java @@ -73,9 +73,9 @@ public static int indexOfTernaryElse(CharSequence str, int defaultCountOfConfiti char ch = str.charAt(i); if (ch == '\"') quote++; - else if (ch == '{' || ch == '[') + else if ((ch | ' ') == '{') brackets++; - else if (ch == '}' || ch == ']') + else if ((ch | ' ') == '}') brackets--; else if (quote % 2 == 0 && brackets == 0) { @@ -110,9 +110,9 @@ public static int indexOfOne(CharSequence str, int from, char oneChar) char ch = str.charAt(from); if (ch == '\"') quote++; - else if (ch == '{' || ch == '[') + else if ((ch | ' ') == '{') brackets++; - else if (ch == '}' || ch == ']') + else if ((ch | ' ') == '}') brackets--; else if (quote % 2 == 0 && brackets == 0 && ch == oneChar && oldCh != oneChar && (from >= len-1 || str.charAt(from+1) != oneChar)) return from; From 5ddb3a4cdcf875354306c8b70a8ce93a3bf7206b Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 5 Dec 2023 18:32:20 +0100 Subject: [PATCH 09/48] some micro optimalizations i < len-1 -> i > 0 --- .../serialx/converters/ProtocolConverter.java | 9 +++++---- .../ugp/serialx/protocols/AutoProtocol.java | 1 + .../org/ugp/serialx/juss/JussSerializer.java | 6 +++--- .../juss/converters/ArrayConverter.java | 19 ++++++++++--------- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java index bb04719..e671dfd 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java @@ -205,10 +205,7 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Serializ args = args.clone(); for (int i = 0, sizeEndl = 10000; i < objArgs.length; i++) { - if (args.length > 2) - args[2] = index + 1; - sb.append(myHomeRegistry.toString(objArgs[i], args)); - if (i < objArgs.length-1) + if (i > 0) if (sb.length() > sizeEndl) { sb.append('\n'); @@ -218,6 +215,10 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Serializ } else sb.append(' '); + + if (args.length > 2) + args[2] = index + 1; + sb.append(myHomeRegistry.toString(objArgs[i], args)); } args[4] = oldObjectClass; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java index cb717f7..3180c27 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java @@ -4,6 +4,7 @@ import java.beans.PropertyDescriptor; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import org.ugp.serialx.Scope; diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index fa667f3..d1136a4 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -323,15 +323,15 @@ else if (args[1] instanceof Integer) for (i = 0; i < valuesLen; i++) //Values { + if (i > 0) + source.append('\n'); + Object obj = objs.get(i); CharSequence serialized = reg.toString(obj, args); appandVal(source, serialized, obj, tabs, i >= valuesLen-1); if (generateComments && (!(obj instanceof Scope) || ((Scope) obj).isEmpty())) GenerateComment(source, reg, obj); - - if (i < valuesLen-1) - source.append('\n'); } if (source instanceof Flushable) diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java index 7ba3db7..e7f6f45 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java @@ -103,23 +103,24 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object.. StringBuilder sb = new StringBuilder(); for (int i = 0, length = elms.length, sizeEndl = 10000; i < length; i++) { - CharSequence str = myHomeRegistry.toString(elms[i], args); - char ch = str.charAt(0); - if ((ch | ' ') == '{') - sb.append("("+str+")"); - else - sb.append(str); - - if (i < length-1) + if (i > 0) if (sb.length() > sizeEndl) { - sb.append('\n'); + sb.append('\n'); for (int j = 0; j < tabs+1; j++) sb.append('\t'); sizeEndl += 10000; } else sb.append(' '); + + CharSequence str = myHomeRegistry.toString(elms[i], args); + char ch = str.charAt(0); + if ((ch | ' ') == '{') + sb.append('(').append(str).append(')'); + else + sb.append(str); + } return index > 0 ? sb.insert(0, '(').append(')') : sb; } From f01159af84dcad3e2beec4a37b3864b5c053030f Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 5 Dec 2023 19:06:16 +0100 Subject: [PATCH 10/48] same as previous --- .../src/main/java/org/ugp/serialx/juss/JussSerializer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index d1136a4..7a4b2f0 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -316,7 +316,7 @@ else if (args[1] instanceof Integer) if (generateComments && (!(var.getValue() instanceof Scope) || ((Scope) var.getValue()).isEmpty())) GenerateComment(source, reg, var); - if (i++ < varLen-1 || valuesLen > 0) + if (++i < varLen || valuesLen > 0) source.append('\n'); } } @@ -325,10 +325,10 @@ else if (args[1] instanceof Integer) { if (i > 0) source.append('\n'); - + Object obj = objs.get(i); CharSequence serialized = reg.toString(obj, args); - + appandVal(source, serialized, obj, tabs, i >= valuesLen-1); if (generateComments && (!(obj instanceof Scope) || ((Scope) obj).isEmpty())) GenerateComment(source, reg, obj); From 5a31fd674e9bb281b2a608fa6deeb74094567fcf Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Wed, 27 Dec 2023 23:54:16 +0100 Subject: [PATCH 11/48] no javafx, and stop importing it... --- .../src/main/java/org/ugp/serialx/json/JsonSerializer.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java index ef140db..bf12831 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java @@ -35,8 +35,6 @@ import org.ugp.serialx.protocols.SerializationProtocol; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; -import javafx.beans.binding.When; - /** * This is implementation of {@link JussSerializer} for serializing in Json! * It should generate and work with .json files! From f4d8b06a4f95a31b00813a9613aa0155ef855229 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Thu, 28 Dec 2023 11:45:03 +0100 Subject: [PATCH 12/48] ... --- .../src/main/java/org/ugp/serialx/protocols/AutoProtocol.java | 1 - 1 file changed, 1 deletion(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java index 3180c27..cb717f7 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java @@ -4,7 +4,6 @@ import java.beans.PropertyDescriptor; import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import org.ugp.serialx.Scope; From 8ceb5de46dac577b9f5039dfb3f4c0364faa2354 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sun, 31 Dec 2023 23:31:41 +0100 Subject: [PATCH 13/48] fixing bug with ArrayConverter affecting other objects, better default logErr, finishing and testing refactor of ObjectConverter, adding tests to GeneralExample --- .../java/org/ugp/serialx/LogProvider.java | 12 +- .../src/main/java/org/ugp/serialx/Utils.java | 2 +- .../ugp/serialx/converters/DataParser.java | 4 +- .../serialx/converters/ProtocolConverter.java | 38 +- .../ugp/serialx/protocols/MapProtocol.java | 2 +- .../ugp/serialx/protocols/ScopeProtocol.java | 2 +- .../protocols/SerializationProtocol.java | 8 +- .../UniversalObjectInstantiationProtocol.java | 4 +- .../converters/DebugParserRegistry.java | 4 +- .../org/ugp/serialx/juss/JussSerializer.java | 2 +- .../juss/converters/ArrayConverter.java | 3 + .../juss/converters/ObjectConverter.java | 9 +- .../juss/converters/ObjectConverterOld.java | 530 ------------------ 13 files changed, 69 insertions(+), 551 deletions(-) delete mode 100644 SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverterOld.java diff --git a/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java b/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java index 5ab4f08..f9eadae 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java @@ -40,7 +40,17 @@ public void logErr(Object obj, Throwable ex) throw new RuntimeException(obj.toString()); throw new RuntimeException(ex); } - System.err.println(obj); + + try + { + StackTraceElement caller = Thread.currentThread().getStackTrace()[2]; + String callerName = caller.getClassName(); + System.err.println(callerName.substring(callerName.lastIndexOf('.')+1) + "#" + caller.getMethodName() + ": " + obj); + } + catch (Exception e) + { + System.err.println(obj); + } } /** diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index 11e1025..f4052a3 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -426,7 +426,7 @@ else if (objs[i] instanceof Class) } for (int i = 0; i < classes.length; i++) - classes[i] = objs[i].getClass(); + classes[i] = objs[i] == null ? Object.class : objs[i].getClass(); return classes; } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index b53fb83..78b52ef 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -260,7 +260,7 @@ public CharSequence toString(Object obj, Object... args) } } - LogProvider.instance.logErr(DataConverter.class.getSimpleName() + ": Unable to convert \"" + obj == null ? "null" : obj.getClass().getName() + "\" to string because none of registered converters were aplicable for this object!", null); + 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); return null; } @@ -316,7 +316,7 @@ public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ign if (returnAsStringIfNotFound) return str; - LogProvider.instance.logErr(DataParser.class.getSimpleName() + ": Unable to parse \"" + str + "\" because none of registred parsers were suitable!", null); + LogProvider.instance.logErr("Unable to parse \"" + str + "\" because none of registred parsers were suitable!", null); return null; } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java index e671dfd..7dd56f0 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java @@ -23,7 +23,6 @@ /** * This converter is capable of converting any Object using {@link SerializationProtocol} as well as invoking static functions! - * This is also responsible for {@link Scope}! * Its case sensitive! *
*
@@ -48,14 +47,15 @@ 10 -
+ Note: Be aware that invocation of static members such as functions and fields (:: operator) is disabled by default for the sake of security...
+
This parser requires additional parser arg at index 0 of type {@link GenericScope} or {@link Serializer} that will be used for further parsing and operating (default new {@link JussSerializer}).
This parser requires additional parser arg at index 3 of type {@link ProtocolRegistry} or {@link SerializationProtocol} itself that will be used for parsing protocol expressions (default {@link SerializationProtocol#REGISTRY}).
* This parser will insert one additional argument into array of additional parser args at index 4, in case of serialization index 5, that will be of type {@link Class} and it will contains information about class of object that is being unserialized or serialized using protocol!
* * @author PETO * - * @since 1.3.0 + * @since 1.3.0 (separated from ObjectConverter since 1.3.7) */ public class ProtocolConverter implements DataConverter { @@ -71,6 +71,8 @@ public class ProtocolConverter implements DataConverter */ protected boolean useBase64IfCan = false; + protected boolean allowStaticMemberInvocation = false; + @Override public Object parse(ParserRegistry myHomeRegistry, String str, Object... compilerArgs) { @@ -99,11 +101,11 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... compile */ protected Object parse(ParserRegistry myHomeRegistry, Class objClass, String str, Object... compilerArgs) { - if (objClass == IsSelectorScope.class) + if (objClass == IsSelectorScope.class) //Handle css-like selector scope to variable assignment { StringBuilder sb = new StringBuilder(str); sb.setCharAt(str.indexOf(' '), '='); - return myHomeRegistry.parse(sb.toString(), compilerArgs); + return myHomeRegistry.parse(sb.toString(), compilerArgs); //Should work only when ObjectConverter and VariableConverter are present... } if (compilerArgs.length < 5) @@ -116,6 +118,12 @@ protected Object parse(ParserRegistry myHomeRegistry, Class objClass, String if (!isOneOf(args[0].charAt(0), '{', '[') && (nameIndex = args[0].indexOf("::")) > -1) //Is static member invocation { String memberName = args[0].substring(nameIndex + 2); + if (!isAllowStaticMemberInvocation()) + { + LogProvider.instance.logErr("Invocation of static member \"" + memberName + "\" from class \"" + objClass.getName() + "\" was denied because this feature is disabled by default for security reasons!", null); + return null; + } + if (args.length > 1) return InvokeStaticFunc(objClass, oldObjectClass, memberName, parseAll(myHomeRegistry, args, 1, true, compilerArgs), compilerArgs); @@ -274,6 +282,26 @@ public void setUseBase64IfCan(boolean useBase64IfCan) this.useBase64IfCan = useBase64IfCan; } + /** + * @return True if invocation of static members (:: operator) is allowed (false by default)! + * + * @since 1.3.7 + */ + public boolean isAllowStaticMemberInvocation() + { + return allowStaticMemberInvocation; + } + + /** + * @param allowStaticMemberInvocation | Enable/disable the invocation of static members (:: operator) (false by default)! + * + * @since 1.3.7 + */ + public void setAllowStaticMemberInvocation(boolean allowStaticMemberInvocation) + { + this.allowStaticMemberInvocation = allowStaticMemberInvocation; + } + /** * @param obj | Object to get protocol for! * @param mode | Protocol mode! diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java index 54fab5a..eacd7ee 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/MapProtocol.java @@ -37,7 +37,7 @@ public Map unserialize(Class> obje { boolean isFromScope = args.length == 1 && args[0] instanceof GenericScope; if (args.length % 2 != 0 && !isFromScope) - LogProvider.instance.logErr(getClass().getSimpleName() + ": Some variables have no values, this is not good!", null); + LogProvider.instance.logErr("Some variables have no values, this is not good!", null); if (objectClass.isInterface()) objectClass = (Class>) HashMap.class; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java index d1c8a69..aae4ce0 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java @@ -23,7 +23,7 @@ public Object[] serialize(GenericScope object) throws Exception { if (object.getClass() != Scope.class) return new Object[] {object.castTo(Scope.class)}; - throw new UnsupportedOperationException(getClass().getSimpleName() + ": You are trying to serialize GenericScope or Scope via protocol! This is not good and should not even be possible! Scopes are meant to be serialized via converters!"); + throw new UnsupportedOperationException("You are trying to serialize GenericScope or Scope via protocol! This is not good and should not even be possible! Scopes are meant to be serialized via converters!"); } @Override diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java index 7aab546..13248f3 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java @@ -30,7 +30,7 @@ public abstract class SerializationProtocol * * @since 1.3.0 */ - public static final ProtocolRegistry REGISTRY = new ProtocolRegistry(new UniversalObjectInstantiationProtocol<>(Object.class), new ListProtocol(), new MapProtocol(), new StringProtocol(), new ScopeProtocol(), new SelfSerializableProtocol(), new EnumProtocol()); + public static final ProtocolRegistry REGISTRY = new ProtocolRegistry(/*This might be unsafe: new UniversalObjectInstantiationProtocol<>(Object.class),*/ new ListProtocol(), new MapProtocol(), new StringProtocol(), new ScopeProtocol(), new SelfSerializableProtocol(), new EnumProtocol()); /** * This mode is for protocols that are used for serialization only! @@ -191,7 +191,7 @@ public static Object[] serializeObj(ProtocolRegistry registry, O object) thr SerializationProtocol prot = registry.GetProtocolFor(object, MODE_SERIALIZE); if (prot == null) { - LogProvider.instance.logErr(SerializationProtocol.class.getSimpleName() + ": Unable to serialize \"" + object + "\" because there is no registered and active protocol for serializing " + object.getClass() + "!", null); + LogProvider.instance.logErr("Unable to serialize \"" + object + "\" because there is no registered and active protocol for serializing " + object.getClass() + "!", null); return null; } return prot.serialize(object); @@ -231,7 +231,7 @@ public static O unserializeObj(ProtocolRegistry registry, Class SerializationProtocol prot = (SerializationProtocol) registry.GetProtocolFor(objectClass, MODE_DESERIALIZE); if (prot == null) { - LogProvider.instance.logErr(SerializationProtocol.class.getSimpleName() + ": Unable to unserialize " + Arrays.toString(args) + " because there is no registered and active protocol for unserializing \"" + objectClass + "\"!", null); + LogProvider.instance.logErr("Unable to unserialize " + Arrays.toString(args) + " because there is no registered and active protocol for unserializing \"" + objectClass + "\"!", null); return null; } return (O) prot.unserialize(objectClass, args); @@ -294,7 +294,7 @@ public ProtocolRegistry clone() public void add(int index, SerializationProtocol element) { if (GetProtocolFor(element.applicableFor()) != null && element.applicableFor() != Object.class) - LogProvider.instance.logErr(getClass().getSimpleName() + ": Protocol applicable for \"" + element.applicableFor().getName() + "\" is already registred!", null); + LogProvider.instance.logErr("Protocol applicable for \"" + element.applicableFor().getName() + "\" is already registred!", null); addDuplicatively(index, element); } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java index b941f2b..045401e 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java @@ -33,7 +33,7 @@ public UniversalObjectInstantiationProtocol(Class applicableFor) @Override public Object[] serialize(T object) { - throw new UnsupportedOperationException(getClass().getSimpleName() + ": This protocol is only for reading! It cant serialize " + object); + throw new UnsupportedOperationException("This protocol is only for reading! It cant serialize " + object); } @SuppressWarnings("unchecked") @@ -54,7 +54,7 @@ public T unserialize(Class objectClass, Object... args) throws Exce catch (IllegalArgumentException e) {} } - LogProvider.instance.logErr(getClass().getSimpleName() + ": Unable to call create new instance of \"" + objectClass + "\" because inserted arguments " + Arrays.asList(args) + " cannot be applied on any public constructor in required class!", null); + LogProvider.instance.logErr("Unable to create new instance of \"" + objectClass + "\" because inserted arguments " + Arrays.asList(args) + " cannot be applied on any public constructor in required class!", null); return null; } diff --git a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java index 2ad0472..bc300ca 100644 --- a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java +++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java @@ -94,7 +94,7 @@ public CharSequence toString(Object obj, Object... args) { } } - LogProvider.instance.logErr(DataConverter.class.getSimpleName() + ": Unable to convert \"" + obj == null ? "null" : obj.getClass().getName() + "\" to string because none of registered converters were aplicable for this object!", null); + 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); return null; } @@ -149,7 +149,7 @@ public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ign if (returnAsStringIfNotFound) return str; - LogProvider.instance.logErr(DataParser.class.getSimpleName() + ": Unable to parse \"" + str + "\" because none of registred parsers were suitable!", null); + LogProvider.instance.logErr("Unable to parse \"" + str + "\" because none of registred parsers were suitable!", null); return null; } diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index 7a4b2f0..71b414d 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -63,7 +63,7 @@ public class JussSerializer extends Serializer implements ImportsProvider * * @since 1.3.2 */ - public static final ParserRegistry JUSS_PARSERS = new ParserRegistry(new OperationGroups(), new VariableConverter(), new StringConverter(), new ObjectConverter(), new ArrayConverter(), new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter()); + public static final ParserRegistry JUSS_PARSERS = new ParserRegistry(new ImportConverter(), new OperationGroups(), new VariableConverter(), new StringConverter(), new ObjectConverter(), new ArrayConverter(), new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter()); /** * {@link ParserRegistry} with all parsers required to parse JUSS with additional operators. diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java index e7f6f45..0849c5f 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java @@ -97,7 +97,10 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object.. tabs = (int) args[1]; if (args.length > 2) + { + args = args.clone(); //Necessary for preventing this from affecting other objects and arrays... args[2] = index + 1; + } Object[] elms = fromAmbiguousArray(obj); StringBuilder sb = new StringBuilder(); diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java index 57c222f..00c7c42 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java @@ -42,12 +42,17 @@ ArrayList 2 4 6 new ArrayList<>(Arrays.asList(2, 4, 6)) + + { ... } + new Scope( ... ) + java.lang.Math::max 10 5 10 -
+ Note: Be aware that invocation of static members such as functions and fields (:: operator) is disabled by default for the sake of security...
+
This parser requires additional parser arg at index 0 of type {@link GenericScope} or {@link Serializer} that will be used for further parsing and operating (default new {@link JussSerializer}).
This parser requires additional parser arg at index 3 of type {@link ProtocolRegistry} or {@link SerializationProtocol} itself that will be used for parsing protocol expressions (default {@link SerializationProtocol#REGISTRY}).
* This parser will insert one additional argument into array of additional parser args at index 4, in case of serialization index 5, that will be of type {@link Class} and it will contains information about class of object that is being unserialized or serialized using protocol!
@@ -107,6 +112,8 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... compile } //TODO: Prevent neccesity of scope parent inheritance. + compilerArgs = compilerArgs.clone(); + compilerArgs[0] = false; //No extra formating... return str.isEmpty() ? scope : ((Serializer) scope/*.inheritParent()*/).LoadFrom(new StringReader(str), compilerArgs); } } diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverterOld.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverterOld.java deleted file mode 100644 index f4d2d3a..0000000 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverterOld.java +++ /dev/null @@ -1,530 +0,0 @@ -package org.ugp.serialx.juss.converters; - -import static org.ugp.serialx.Utils.Instantiate; -import static org.ugp.serialx.Utils.InvokeStaticFunc; -import static org.ugp.serialx.Utils.indexOfNotInObj; -import static org.ugp.serialx.Utils.isOneOf; -import static org.ugp.serialx.Utils.splitValues; - -import java.io.IOException; -import java.io.Serializable; -import java.io.StringReader; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Base64; - -import org.ugp.serialx.GenericScope; -import org.ugp.serialx.LogProvider; -import org.ugp.serialx.Registry; -import org.ugp.serialx.Scope; -import org.ugp.serialx.Serializer; -import org.ugp.serialx.converters.DataConverter; -import org.ugp.serialx.converters.DataParser; -import org.ugp.serialx.converters.DataParser.ParserRegistry; -import org.ugp.serialx.converters.SerializableBase64Converter; -import org.ugp.serialx.converters.imports.ImportsProvider; -import org.ugp.serialx.juss.JussSerializer; -import org.ugp.serialx.protocols.SerializationProtocol; -import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; - -/** - * This converter is capable of converting any Object using {@link SerializationProtocol} as well as invoking static functions! - * This is also responsible for {@link Scope}! - * Its case sensitive! - *
- *
- * Table of sample string <--> object conversions: - * - - - - - - - - - - - - - -
StringObject
ArrayList 2 4 6new ArrayList<>(Arrays.asList(2, 4, 6))
java.lang.Math::max 10 510
-
- This parser requires additional parser arg at index 0 of type {@link GenericScope} or {@link Serializer} that will be used for further parsing and operating (default new {@link JussSerializer}).
- This parser requires additional parser arg at index 3 of type {@link ProtocolRegistry} or {@link SerializationProtocol} itself that will be used for parsing protocol expressions (default {@link SerializationProtocol#REGISTRY}).
- * This parser will insert one additional argument into array of additional parser args at index 4, in case of serialization index 5, that will be of type {@link Class} and it will contains information about class of object that is being unserialized or serialized using protocol!
- * - * @author PETO - * - * @since 1.3.0 - */ -public class ObjectConverterOld implements DataConverter -{ - /** - * Set this on true to force program to use {@link Base64} serialization on {@link Serializable} objects. - * Doing this might result into some form of encryption but its less flexible and tends to be slower than SerialX {@link SerializationProtocol} system! - * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. - * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
- * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
- * Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! - * - * @since 1.0.0 (moved to {@link SerializableBase64Converter} since 1.3.0 and since 1.3.5 into {@link ObjectConverterOld}) - */ - protected boolean useBase64IfCan = false; - - @SuppressWarnings("unchecked") - @Override - public Object parse(ParserRegistry myHomeRegistry, String str, Object... compilerArgs) - { - Class objectClass = null, oldObjectClass; - boolean hasOp, hasCls = false; - char ch; - - if (str.length() > 0 && ((hasOp = (ch = str.charAt(0)) == '{' || ch == '[') && (hasCls = (ch = str.charAt(str.length()-1)) == '}' || ch == ']') /*|| containsNotInObj(str, ' ')*/ || (objectClass = getProtocolExprClass(str, compilerArgs)) != null)) - { - if (objectClass != null) //TODO: Preferably separate this to ProtocolConverter - { - if (objectClass == IsSelectorScope.class) - { - StringBuilder sb = new StringBuilder(str); - sb.setCharAt(str.indexOf(' '), '='); - return myHomeRegistry.parse(sb.toString(), compilerArgs); - } - else - { - if (compilerArgs.length < 5) - compilerArgs = Arrays.copyOf(compilerArgs, 5); - oldObjectClass = (Class) compilerArgs[4]; - compilerArgs[4] = objectClass; - } - - String[] args = splitValues(str = str.trim(), ' '); - if (!isOneOf(args[0].charAt(0), '{', '[') && args[0].contains("::")) - { - String[] clsAttr = args[0].split("::"); - if (clsAttr.length > 1) - { - if (args.length > 1) - try - { - Object rtrn = InvokeStaticFunc(objectClass, clsAttr[1], parseAll(myHomeRegistry, args, 1, true, compilerArgs)); - compilerArgs[4] = oldObjectClass; - return rtrn; - } - catch (InvocationTargetException e) - { - LogProvider.instance.logErr("Exception while calling method \"" + clsAttr[1] + "\":", e); - e.printStackTrace(); - } - else - try - { - compilerArgs[4] = oldObjectClass; - return clsAttr[1].equals("class") ? objectClass : clsAttr[1].equals("new") ? Instantiate(objectClass) : objectClass.getField(clsAttr[1]).get(null); - } - catch (NoSuchFieldException e) - { - try - { - Object rtrn = InvokeStaticFunc(objectClass, clsAttr[1], parseAll(myHomeRegistry, args, 1, true, compilerArgs)); - compilerArgs[4] = oldObjectClass; - return rtrn; - } - catch (InvocationTargetException e2) - { - LogProvider.instance.logErr("Exception while calling method \"" + clsAttr[1] + "\":", e2); - e.printStackTrace(); - } - } - catch (Exception e) - { - LogProvider.instance.logErr("Unable to obtain value of field \"" + clsAttr[1] + "\" in class \"" + objectClass.getSimpleName() + "\" because:", e); - e.printStackTrace(); - } - /*catch (ClassNotFoundException e) - { - LogProvider.instance.logErr("Unable to invoke \"" + args[0].split("::")[1] + "\" because class \"" + args[0].split("::")[0] + "\" was not found!"); - } */ - } - } - else - { - try - { - if ((ch = str.charAt(str.length()-1)) == ';' || ch == ',') - throw new ClassNotFoundException(); - - Object[] objArgs = parseAll(myHomeRegistry, args, 1, true, compilerArgs); - if (objArgs.length == 1 && objArgs[0] instanceof Scope && Scope.class.isAssignableFrom(objectClass)) - return objArgs[0]; - compilerArgs[4] = oldObjectClass; - return SerializationProtocol.unserializeObj(compilerArgs.length > 3 && compilerArgs[3] instanceof ProtocolRegistry ? (ProtocolRegistry) compilerArgs[3] : SerializationProtocol.REGISTRY, objectClass, objArgs); - - /*Object obj; - if (objArgs.length == 1 && objArgs[0] instanceof Scope) - { - Scope scope = (Scope) objArgs[0]; - if ((obj = p.unserialize(objectClass, scope.toValArray())) != null) - return obj; - return p.unserialize(objectClass, scope); - } - else - { - if ((obj = p.unserialize(objectClass, objArgs)) != null) - return obj; - return p.unserialize(objectClass, new Scope(objArgs)); - }*/ - } - catch (Exception e) - { - LogProvider.instance.logErr("Exception while unserializing instance of \"" + objectClass.getName() + "\":", e); - e.printStackTrace(); - } - } - compilerArgs[4] = oldObjectClass; - } - else - { - Serializer scope; - try - { - if (compilerArgs.length > 0 && compilerArgs[0] instanceof Serializer) - { - if (compilerArgs.length > 4 && compilerArgs[4] instanceof Class && Serializer.class.isAssignableFrom((Class) compilerArgs[4])) - scope = ((Serializer) compilerArgs[0]).emptyClone((Class) compilerArgs[4], (GenericScope) compilerArgs[0]); - else - scope = ((Serializer) compilerArgs[0]).emptyClone(); - } - else - scope = getPreferredSerializer(); - } - catch (Exception e) - { - scope = getPreferredSerializer(); - } - - if (indexOfNotInObj(str, '=', ':', ';', ',') > -1) - { - compilerArgs = compilerArgs.clone(); - compilerArgs[0] = false; - //TODO: Prevent neccesity of scope parent inheritance. - return ((Serializer) scope.inheritParent()).LoadFrom(new StringReader(str), compilerArgs); - } - - if (hasOp && hasCls) - { - str = str.substring(1, str.length()-1).trim(); - if (str.isEmpty()) - return scope; - - int index; - if ((index = indexOfNotInObj(str, '=', ';', ',')) > -1 && (index >= str.length()-1 || str.charAt(index+1) != ':') || (objectClass = getProtocolExprClass(str, compilerArgs)) == null || objectClass == IsSelectorScope.class) - { - compilerArgs = compilerArgs.clone(); - compilerArgs[0] = false; - return ((Serializer) scope.inheritParent()).LoadFrom(new StringReader(str), compilerArgs); - } - - if (objectClass != null && indexOfNotInObj(str, "::") > -1) - return myHomeRegistry.parse(str, compilerArgs); - return parse(myHomeRegistry, str, compilerArgs); - } - else if (str.split(" ").length > 1) - { - LogProvider.instance.logErr("Unable to unserialize \"" + str + "\"! Possible reason of this is absence of comma or semicolon, try to insert them into empty spaces!", null); - return null; - } - } - LogProvider.instance.logErr("Unable to unserialize \"" + str + "\" because there is no such class or source string is corrupted!", null); - return null; - } - return CONTINUE; - } - - @Override - public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) - { - return toString(myHomeRegistry, arg, null, args); - } - - /** - * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! - * @param obj | Object to convert into string! - * @param preferedProtocol | Protocol to use preferably. - * @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)! - * - * @return Object converted to string. Easiest way to do this is obj.toString() but you most likely want some more sofisticated formating. - * 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! - * - * @since 1.3.5 - */ - @SuppressWarnings("unchecked") - public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, SerializationProtocol preferedProtocol, Object... args) - { - if (arg == null) - return CONTINUE; - - if (useBase64IfCan && arg instanceof Serializable) - return CONTINUE; - - if (arg instanceof Scope) - { - Serializer serializer; - try - { - if (arg instanceof Serializer) - serializer = (Serializer) arg; - else if (args.length > 0 && args[0] instanceof Serializer) - (serializer = ((Serializer) args[0]).emptyClone()).addAll((GenericScope) arg); - else - serializer = getPreferredSerializer(); - } - catch (Exception e) - { - serializer = getPreferredSerializer(); - } - - if (serializer instanceof JussSerializer) - ((JussSerializer) serializer).setGenerateComments(args.length > 5 && args[5] instanceof Boolean && (boolean) args[5]); - - try - { - if (args.length < 4) - args = Arrays.copyOf(args, 4); - else - args = args.clone(); - args[2] = 0; - args[3] = serializer.getProtocols(); - - StringBuilder sb = new StringBuilder(); - GenericScope parent; - if ((parent = serializer.getParent()) == null || serializer.getClass() != parent.getClass()) - sb.append(ImportsProvider.getAliasFor(serializer, getClass()) + " "); - return serializer.SerializeAsSubscope(sb, args); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - else //TODO: Preferably separate this to ProtocolConverter - { - if (preferedProtocol != null || (preferedProtocol = (SerializationProtocol) getProtocolFor(arg, SerializationProtocol.MODE_SERIALIZE, args)) != null) - { - Object[] objArgs; - Class oldObjectClass = null; - try - { - int tabs = 0, index = 0; - if (args.length > 1 && args[1] instanceof Integer) - tabs = (int) args[1]; - - if (args.length > 2 && args[2] instanceof Integer) - index = (int) args[2]; - - if (args.length < 5) - args = Arrays.copyOf(args, 5); - oldObjectClass = (Class) args[4]; - args[4] = arg.getClass();; - - objArgs = preferedProtocol.serialize(arg); - StringBuilder sb = new StringBuilder(ImportsProvider.getAliasFor(args.length > 0 ? args[0] : null, arg.getClass()) + (objArgs.length <= 0 ? "" : " ")); - - args = args.clone(); - for (int i = 0, sizeEndl = 10000; i < objArgs.length; i++) - { - if (args.length > 2) - args[2] = index + 1; - sb.append(myHomeRegistry.toString(objArgs[i], args)); - if (i < objArgs.length-1) - if (sb.length() > sizeEndl) - { - sb.append('\n'); - for (int j = 0; j < tabs+1; j++) - sb.append('\t'); - sizeEndl += 10000; - } - else - sb.append(' '); - } - - args[4] = oldObjectClass; - return index > 0 && objArgs.length > 0 ? sb.insert(0, '{').append('}') : sb; - } - catch (Exception e) - { - LogProvider.instance.logErr("Exception while serializing instance of \"" + arg.getClass().getName() + "\":", e); - e.printStackTrace(); - } - args[4] = oldObjectClass; - } - } - return CONTINUE; - } - - @Override - public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) - { - if (obj instanceof Scope && ((Scope) obj).isEmpty()) - return "Empty scope!"; - else if (obj instanceof CharSequence && indexOfNotInObj((CharSequence) obj, '\n', '\r') != -1) - return "Multiline char sequence!"; - return new StringBuilder("Object of ").append(obj.getClass().getName()).append(": \"").append(obj.toString()).append("\" serialized using ").append(getProtocolFor(obj, SerializationProtocol.MODE_ALL, argsUsedConvert).toString()).append("!"); - } - - /** - * @return Serializer that is supposed to be used for serializing sub-scopes if there is no other option. - * - * @since 1.3.5 - */ - public Serializer getPreferredSerializer() - { - return new JussSerializer(); - } - - /** - * @return True if program is forced to use {@link Base64} serialization on {@link Serializable} objects. - * This might result into some form of encryption but its less flexible and tends to be slower than SerialX {@link SerializationProtocol} system! - * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. - * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
- * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
- * Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! - * - * @since 1.3.5 - */ - public boolean isUseBase64IfCan() - { - return useBase64IfCan; - } - - /** - * @param useBase64IfCan | Set this on true to force program to use {@link Base64} serialization on {@link Serializable} objects. - * Doing this might result into some form of encryption but its less flexible and tends to be slower than SerialX {@link SerializationProtocol} system! - * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. - * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
- * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization!
- * Note: This will only work when this converter is registered in {@link ParserRegistry} together with {@link SerializableBase64Converter}! - * - * @since 1.3.5 - */ - public void setUseBase64IfCan(boolean useBase64IfCan) - { - this.useBase64IfCan = useBase64IfCan; - } - - /** - * @param obj | Object to get protocol for! - * @param mode | Protocol mode! - * @param args | Parser args to get protocol from! - * - * @return Protocol obtained from args or from {@link SerializationProtocol#REGISTRY} if there is no protocol or {@link ProtocolRegistry} in args (index 3).
- * Note: This is mainly used by {@link ObjectConverterOld}! - * - * @since 1.3.5 - */ - public static SerializationProtocol getProtocolFor(Object obj, byte mode, Object[] args) - { - if (args.length > 3) - { - if (args[3] instanceof ProtocolRegistry) - return ((ProtocolRegistry) args[3]).GetProtocolFor(obj, mode); - else if (args[3] instanceof SerializationProtocol) - return (SerializationProtocol) args[3]; - } - - return SerializationProtocol.REGISTRY.GetProtocolFor(obj, mode); - } - - /** - * @param str | String to check protocol class for! - * - * @return Class of the protocol or null if inserted statement is not protocol expression! - * For example: getProtocolExprClass("java.util.ArrayList 1 2 3 4 5") will return {@link ArrayList} but "Hello world!" will return null! - * - * @since 1.3.0 - */ - public static Class getProtocolExprClass(String str, Object[] compilerArgs) - { - int i = 0, len = str.length(); - for (char ch; i < len; i++) - if ((ch = str.charAt(i)) == ' ' || ch == ':') - break; - try - { - Class cls = ImportsProvider.forName(compilerArgs.length > 0 ? compilerArgs[0] : null, str.substring(0, i), false, ObjectConverterOld.class.getClassLoader()); - if (cls != null) - return cls; - for (char ch; i < len; i++) - { - if ((ch = str.charAt(i)) > 32) - if (ch == '{' || ch == '[') - return IsSelectorScope.class; - else - return null; - } - } - catch (ClassNotFoundException e) - {} - return null; - } - - /** - * @param registry | Registry to use! - * @param strs | Source strings to parse using suitable parser from registry. - * @param from | Start index to begin from! - * @param trim | If true, all strings will be trimed before parsing! - * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! - * - * @return Array of parsed objects, each parsed using {@link DataParser#parseObj(String, Object...)} - * - * @since 1.3.0 - */ - public static Object[] parseAll(ParserRegistry registry, String strs[], int from, boolean trim, Object... args) - { - Object[] objs = new Object[strs.length-from]; - for (int i = 0; from < strs.length; from++, i++) - objs[i] = registry.parse(trim ? strs[from].trim() : strs[from], args); - return objs; - } - - /** - * @return Array with 2 preferred sub-scope wrapping chars that are used during serialization by default. { and } - * - * @since 1.3.5 - */ - public static char[] primarySubscopeWrappers() - { - return new char[] {'{', '}'}; - } - - /** - * @return Array with 2 secondary sub-scope wrapping char. [ and ] - * - * @since 1.3.5 - */ - public static char[] secondarySubscopeWrappers() - { - return new char[] {'[', ']'}; - } - - /** - * Used internally by {@link ObjectConverterOld}!
- * Dummy class with no purpose except to be mark (.class) for shortened scope expression such as: - * - * shortenedSelectorLikeScope {

- * //stuff... - * }; - *
- * - * @author PETO - * - * @since 1.3.0 - */ - public static class IsSelectorScope {}; -} \ No newline at end of file From 402a77d3d1654b6bf55271d650fb0317f595e0ba Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 20 Feb 2024 17:20:06 +0100 Subject: [PATCH 14/48] begining refactor of VarConver... --- .../java/org/ugp/serialx/GenericScope.java | 18 ++++---- .../src/main/java/org/ugp/serialx/Utils.java | 4 +- .../juss/converters/VariableConverter.java | 45 ++++++++++++++++--- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index 3ca29a7..3a59a44 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -286,6 +286,7 @@ public V get(KeyT variableKey, V defaultValue) * @return Value of variable at given path. If no path is given (length is 0) then this {@link GenericScope} will be returned.
* If 1 path argument is given then this behaves similarly to {@link GenericScope#get(Object)}.
* if 2+ path arguments are given then it will search the sub-scopes and return first match value. For example:
+ * In either way, if there is no suitable result then null will be returned!
* Consider this scope tree:
*
 	 * 
@@ -361,10 +362,7 @@ public  V get(KeyT variableKey, Class cls, V defaultValue) th
 	 */
 	public boolean containsVariable(KeyT variableKey) 
 	{
-		for (Map.Entry ent : varEntrySet())
-			if (ent.getKey().equals(variableKey))
-				return true;
-		return false;
+		return variables().containsKey(variableKey);
 	}
 	
 	/**
@@ -792,9 +790,9 @@ public boolean isEmpty()
 	 * 
 	 * @since 1.2.0
 	 */
-	public GenericScope getParent()
+	public > T getParent()
 	{
-		return getParent(1);	
+		return (T) getParent(1);	
 	}
 	
 	/**
@@ -806,15 +804,15 @@ public boolean isEmpty()
 	 * 
 	 * @since 1.3.2
 	 */
-	public GenericScope getParent(int depth)
+	public > T getParent(int depth)
 	{
 		if (depth < 1)
-			return this;
+			return (T) this;
 		
 		GenericScope parentsParent;
 		if (depth == 1 || parent == null || (parentsParent = parent.getParent(--depth)) == null)
-			return parent;
-		return parentsParent;
+			return (T) parent;
+		return (T) parentsParent;
 	}
 	
 	/**
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java
index f4052a3..ef5a592 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java
@@ -855,7 +855,7 @@ public static void post(Serializer serializer, HttpURLConnection conn) throws IO
 	 *
 	 * @since 1.2.2
 	 */
-	public static final class NULL
+	public static final class NULL //TODO: REMOVE!!!!
 	{
 		public static Object toOopNull(Object obj)
 		{
@@ -871,7 +871,7 @@ public boolean equals(Object obj)
 		@Override
 		public String toString() 
 		{
-			return "null";
+			return "NULL";
 		}
 	}
 }
\ No newline at end of file
diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java
index a7374d4..8a20384 100644
--- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java
+++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java
@@ -14,8 +14,10 @@
 import org.ugp.serialx.GenericScope;
 import org.ugp.serialx.LogProvider;
 import org.ugp.serialx.Scope;
+import org.ugp.serialx.Utils;
 import org.ugp.serialx.Utils.NULL;
 import org.ugp.serialx.converters.DataConverter;
+import org.ugp.serialx.converters.DataParser;
 
 /**
  * This converter is capable of converting {@link Map.Entry} and reading variables from {@link Scope} via "$"!
@@ -70,7 +72,7 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args)
 				
 				if (enrty.length > 1 && !objString.isEmpty())
 				{
-					obj = NULL.toOopNull(myHomeRegistry.parse(objString, args));
+					obj = myHomeRegistry.parse(objString, args);
 				}
 
 				for (int i = 0; i < enrty.length-1; i++)
@@ -105,12 +107,38 @@ else if (obj == VOID)
 			}
 			else if (arg.charAt(0) == '$' && !contains(arg, ' ', '+', '-', '*', '/', '%', '>', '<', '=', '&', '|', '^', '?', '='))
 			{
+//				Object obj; 
+//				if ((arg = fastReplace(arg, "$", "")).indexOf('.') > -1)
+//				{
+//					Object[] path = splitValues(fastReplace(fastReplace(arg, "::new", ""), "::class", ""), '.');
+//					GenericScope sc = (GenericScope) scope.getGenericScope(Arrays.copyOfRange(path, 0, path.length-1)); //TODO: Prevent neccesity of scope parent inheritance.
+//					obj = sc == null ? null : sc.variables().get(path[path.length-1]);
+//					/*if (sc == null || !sc.containsVariable(tree[tree.length-1]))
+//						LogProvider.instance.logErr("Variable \"" + tree[tree.length-1] + "\" was not declared in \"" + arg.substring(0, arg.length() - tree[tree.length-1].length() - 1) + "\"! Defaulting to null!");*/
+//				}
+//				else
+//				{
+//					String str = fastReplace(fastReplace(arg, "::new", ""), "::class", "");
+//					/*if (!scope.containsVariable(str))
+//						LogProvider.instance.logErr("Variable \"" + str + "\" was not declared! Defaulting to null!");*/
+//					obj = scope.variables().get(str);
+//				}
+				
 				Object obj; 
 				if ((arg = fastReplace(arg, "$", "")).indexOf('.') > -1)
 				{
-					Object[] tree = splitValues(fastReplace(fastReplace(arg, "::new", ""), "::class", ""), '.');
-					GenericScope sc = (GenericScope) scope.getGenericScope(Arrays.copyOfRange(tree, 0, tree.length-1)); //TODO: Prevent neccesity of scope parent inheritance.
-					obj = sc == null ? null : sc.variables().get(tree[tree.length-1]);
+					Object[] path = splitValues(fastReplace(fastReplace(arg, "::new", ""), "::class", ""), '.');
+					if ((obj = scope.get(path)) == null && !scope.variables().containsKey(path[0]))
+					{
+						for (GenericScope parent = scope.getParent(); parent != null; parent = parent.getParent())
+							if (parent.variables().containsKey(path[0]))
+							{
+								obj = parent.get(path);
+								break;
+							}
+					}
+						
+//					GenericScope sc = (GenericScope) scope.getGenericScope(Arrays.copyOfRange(path, 0, path.length-1)); //TODO: Prevent neccesity of scope parent inheritance.
 					/*if (sc == null || !sc.containsVariable(tree[tree.length-1]))
 						LogProvider.instance.logErr("Variable \"" + tree[tree.length-1] + "\" was not declared in \"" + arg.substring(0, arg.length() - tree[tree.length-1].length() - 1) + "\"! Defaulting to null!");*/
 				}
@@ -119,9 +147,16 @@ else if (arg.charAt(0) == '$' && !contains(arg, ' ', '+', '-', '*', '/', '%', '>
 					String str = fastReplace(fastReplace(arg, "::new", ""), "::class", "");
 					/*if (!scope.containsVariable(str))
 						LogProvider.instance.logErr("Variable \"" + str + "\" was not declared! Defaulting to null!");*/
-					obj = scope.variables().get(str);
+					if ((obj = scope.variables().getOrDefault(str, VOID)) == VOID)
+					{
+						for (GenericScope parent = scope.getParent(); parent != null; parent = parent.getParent())
+							if ((obj = parent.variables().getOrDefault(str, VOID)) != VOID)
+								break;
+					}
 				}
 
+				if (obj == null || obj == VOID) // Was not found...
+					return null;
 				return arg.endsWith("::class") ? obj.getClass() : arg.endsWith("::new") ? Clone(obj) : obj;
 			}
 		}

From c80d378551229bc280d17d7083c440e8d189c86c Mon Sep 17 00:00:00 2001
From: Programmer001 
Date: Sat, 2 Mar 2024 19:59:26 +0100
Subject: [PATCH 15/48] Refactoring VariableConverter, splitting it to
 VariableParser and it. Some formatings

---
 .../java/org/ugp/serialx/GenericScope.java    |   7 +-
 .../src/main/java/org/ugp/serialx/Scope.java  |  22 ++--
 .../src/main/java/org/ugp/serialx/Utils.java  |   2 +
 .../ugp/serialx/converters/DataParser.java    |   2 +-
 .../serialx/converters/VariableParser.java    | 103 ++++++++++++++++++
 .../org/ugp/serialx/juss/JussSerializer.java  |   4 +-
 .../juss/converters/VariableConverter.java    |  81 +++-----------
 7 files changed, 137 insertions(+), 84 deletions(-)
 create mode 100644 SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java

diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java
index 3a59a44..8f243dd 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java
@@ -267,7 +267,7 @@ public  V get(KeyT variableKey)
 	 * @param variableKey | Variables name.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return Value of variable with name or defaultValue if there is no such a one!
+	 * @return Value of variable with name or defaultValue if there is no such a one or given key contains null!
 	 * 
 	 * @since 1.2.5
 	 */
@@ -337,7 +337,7 @@ public  V get(KeyT... pathToValue)
 	 * @param cls | Default value to return.
 	 * @param defaultValue | Class that you want the obtained object to be converted into! Exact conversion algorithm can differ based on its implementations.
 	 * 
-	 * @return Value of variable with name given converted to object of cls or defaultValue if there is no such a one!
+	 * @return Value of variable with name given converted to object of cls or defaultValue if there is no such a one or given key contains null!
 	 * 
 	 * @throws Exception | If converting to object of cls failed from some reason! This can differ from implementation to implementation! By default it uses {@link GenericScope#toObject(cls)}
 	 * 
@@ -792,7 +792,7 @@ public boolean isEmpty()
 	 */
 	public > T getParent()
 	{
-		return (T) getParent(1);	
+		return getParent(1);	
 	}
 	
 	/**
@@ -804,6 +804,7 @@ public boolean isEmpty()
 	 * 
 	 * @since 1.3.2
 	 */
+	@SuppressWarnings("unchecked")
 	public > T getParent(int depth)
 	{
 		if (depth < 1)
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java
index c0defa6..757dc98 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java
@@ -159,7 +159,7 @@ public byte getByte(String variableName)
 	 * @param variableName | Variables name.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return Byte value of variable with name or defaultValue if there is no such a one!
+	 * @return Byte value of variable with name or defaultValue if there is no such a one or given key contains null!
 	 * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible!
 	 * 
 	 * @since 1.2.5
@@ -186,7 +186,7 @@ public short getShort(String variableName)
 	 * @param variableName | Variables name.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return Byte value of variable with name or defaultValue if there is no such a one!
+	 * @return Byte value of variable with name or defaultValue if there is no such a one or given key contains null!
 	 * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible!
 	 * 
 	 * @since 1.2.5
@@ -213,7 +213,7 @@ public int getInt(String variableName)
 	 * @param variableName | Variables name.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return Int value of variable with name or defaultValue if there is no such a one!
+	 * @return Int value of variable with name or defaultValue if there is no such a one or given key contains null!
 	 * Int will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible!
 	 * 
 	 * @since 1.2.5
@@ -240,7 +240,7 @@ public int getLong(String variableName)
 	 * @param variableName | Variables name.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return Long value of variable with name or defaultValue if there is no such a one!
+	 * @return Long value of variable with name or defaultValue if there is no such a one or given key contains null!
 	 * Long will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible!
 	 * 
 	 * @since 1.2.5
@@ -267,7 +267,7 @@ public float getFloat(String variableName)
 	 * @param variableName | Variables name.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return Float value of variable with name or defaultValue if there is no such a one!
+	 * @return Float value of variable with name or defaultValue if there is no such a one or given key contains null!
 	 * Float will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible!
 	 * 
 	 * @since 1.2.5
@@ -294,7 +294,7 @@ public double getDouble(String variableName)
 	 * @param variableName | Variables name.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return Double value of variable with name or defaultValue if there is no such a one!
+	 * @return Double value of variable with name or defaultValue if there is no such a one or given key contains null!
 	 * Double will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible!
 	 * 
 	 * @since 1.2.5
@@ -328,7 +328,7 @@ public String getString(String variableName)
 	 * @param variableName | Variables name.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return String value of variable with name or defaultValue if there is no such a one!
+	 * @return String value of variable with name or defaultValue if there is no such a one or given key contains null!
 	 * String will be also parsed from any object using {@link Object#toString()}!
 	 * 
 	 * @since 1.2.5
@@ -355,7 +355,7 @@ public char getChar(String variableName)
 	 * @param variableName | Variables name.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return Char value of variable with name or defaultValue if there is no such a one!
+	 * @return Char value of variable with name or defaultValue if there is no such a one or given key contains null!
 	 * Char will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible!
 	 * 
 	 * @since 1.2.5
@@ -389,7 +389,7 @@ public boolean getBool(String variableName)
 	 * @param variableName | Variables name.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return Boolean value of variable with name or defaultValue if there is no such a one!
+	 * @return Boolean value of variable with name or defaultValue if there is no such a one or given key contains null!
 	 * Boolean will be also parsed from {@link Number}, or {@link CharSequence} if possible!
 	 * 
 	 * @since 1.2.5
@@ -715,7 +715,7 @@ public  T toObjectOf(String variableWithscope, Class objClass) throws Exce
 	 * @param objClass | Object of class to create.
 	 * @param defaultValue | Default value to return.
 	 * 
-	 * @return Value of variable with name or defaultValue if there is no such a one! If there is no Scope stored by variableWithScope this function behaves same as {@link Scope#get(String, Object)}!
+	 * @return Value of variable with name or defaultValue if there is no such a one or given key contains null! If there is no Scope stored by variableWithScope this function behaves same as {@link Scope#get(String, Object)}!
 	 * If variableWithScope contains {@link GenericScope} like it supposed to, then values of scope are parsed to {@link SerializationProtocol} of objClass.
 	 * 
 	 * @see Serializer#PROTOCOL_REGISTRY
@@ -736,7 +736,7 @@ public  T toObjectOf(String variableWithscope, Class objClass, T defaultVa
 	 * @param defaultValue | Default value to return.
 	 * @param protocolsToUse | Registry of protocols to use.
 	 * 
-	 * @return Value of variable with name or defaultValue if there is no such a one! If there is no Scope stored by variableWithScope this function behaves same as {@link Scope#get(String, Object)}!
+	 * @return Value of variable with name or defaultValue if there is no such a one or given key contains null! If there is no Scope stored by variableWithScope this function behaves same as {@link Scope#get(String, Object)}!
 	 * If variableWithScope contains {@link GenericScope} like it supposed to, then values of scope are parsed to {@link SerializationProtocol} of objClass.
 	 * 
 	 * @see Serializer#PROTOCOL_REGISTRY
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java
index ef5a592..830ba29 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java
@@ -854,6 +854,8 @@ public static void post(Serializer serializer, HttpURLConnection conn) throws IO
 	 * @author PETO
 	 *
 	 * @since 1.2.2
+	 * 
+	 * @deprecated (in 1.3.7) NO LONGER NEEDED, DO NOT USE THIS! You were never supposed to...
 	 */
 	public static final class NULL //TODO: REMOVE!!!!
 	{
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java
index 78b52ef..7498674 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java
@@ -41,7 +41,7 @@ public interface DataParser
 	 * 
 	 * @since 1.3.0
 	 */
-	public static final ParserRegistry REGISTRY = new ParserRegistry(/* new OperationGroups(), new VariableConverter(),*/ new StringConverter(), /*new ObjectConverter(),*/ /*TODO: remove new ArrayConverter(),*/ new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter());
+	public static final ParserRegistry REGISTRY = new ParserRegistry(new VariableParser(), new StringConverter(), new ProtocolConverter(), new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter());
 	
 	/**
 	 * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)!
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java
new file mode 100644
index 0000000..2e40c57
--- /dev/null
+++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java
@@ -0,0 +1,103 @@
+package org.ugp.serialx.converters;
+
+import static org.ugp.serialx.Utils.Clone;
+import static org.ugp.serialx.Utils.contains;
+import static org.ugp.serialx.Utils.splitValues;
+
+import org.ugp.serialx.GenericScope;
+import org.ugp.serialx.Registry;
+import org.ugp.serialx.Scope;
+import org.ugp.serialx.Serializer;
+
+/**
+ * This parser is capable of reading variables from {@link GenericScope} by using "$"!
+ * {@link VariableConverter#parse(String, Object...)} required one additional Scope argument in args... at index 0!
+ * Its case sensitive!
+ * Exact outputs of this converter are based on inserted scope! + * + * @author PETO + * + * @since 1.3.7 + */ +public class VariableParser implements DataParser +{ + @SuppressWarnings("unchecked") + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + if (args.length > 0 && str.length() > 0 && args[0] instanceof GenericScope) + { + return parse(myHomeRegistry, str, (GenericScope) args[0], args); + } + return CONTINUE; + } + + /** + * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @param str | Source string (preferably with some variables to read)! + * @param scope | Source scope to read from, can't be null! + * @param args | Some additional args. This can be anything and it demands on implementation of DataParser. + * + * @return Value of variable read from scope is str was suitable. Special return types are {@link DataParser#VOID} and {@link DataParser#CONTINUE}. Continue will ignore this parser and jump to another one in registry. + * + * @since 1.3.7 + */ + @SuppressWarnings("unchecked") + protected Object parse(ParserRegistry myHomeRegistry, String str, GenericScope scope, Object... args) + { + if (str.charAt(0) == '$' && !contains(str, ' ', '+', '-', '*', '/', '%', '>', '<', '=', '&', '|', '^', '?', '=')) + { + + boolean clsModif = str.endsWith("::class"), newModif = false; // Handle modifiers... + if (clsModif) + str = str.substring(0, str.length()-7); + else if (newModif = str.endsWith("::new")) + str = str.substring(0, str.length()-5); + + Object obj = null; + if ((str = str.substring(1)).indexOf('.') > -1) + { + Object[] path = splitValues(str, '.'); + int iLast = path.length-1; + + backlook: do + { + Object sc = scope.variables().getOrDefault(path[0], VOID); + if (sc instanceof GenericScope) // The first one has to be scope! + { + for (int i = 1; i < iLast; i++) // Subscope/forward lookup... + if (!((sc = ((GenericScope) sc).get(path[i])) instanceof GenericScope)) + { + // LogProvider.instance.logErr("Value of path \"" + arg + "\" cannot be dereferenced because \"" + path[i] + "\" is not a scope but " + sc + "!", null); + break backlook; + } + + obj = ((GenericScope) sc).variables().get(path[iLast]); + break; + } + + if (sc != VOID) // = variable was defined in parent but it is not a scope, it means we want to break cos we can't deref that = treat the path as invalid (undefined)... + { + // LogProvider.instance.logErr("Value of path \"" + arg + "\" cannot be dereferenced because \"" + path[0] + "\" is not a scope but " + sc + "!", null); + break; + } + } + while ((scope = scope.getParent()) != null); + } + else + { + do + { + if ((obj = scope.variables().getOrDefault(str, VOID)) != VOID) + break; + } + while ((scope = scope.getParent()) != null); + } + + if (obj == null || obj == VOID) // When was not found... + return null; + return clsModif ? obj.getClass() : newModif ? Clone(obj, scope instanceof Serializer ? ((Serializer) scope).getParsers() : DataParser.REGISTRY, new Object[] {}, new Scope()) : obj; + } + return CONTINUE; + } +} diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index 71b414d..0871155 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -701,13 +701,13 @@ public T cloneOf(String variableName) * @param variable | Variable to clone! * @param defaultValue | Default value to return. * - * @return Clone of value stored by variable with inserted name or defaultValue if there is no such a one! + * @return Clone of value stored by variable with inserted name or defaultValue if there is no such a one or given key contains null! *

* Note: Cloning is done by {@link Serializer#Clone(Object, Registry, Object[], Object...))}! * * @since 1.3.2 */ - public T cloneOf(String variableName , T defaultValue) + public T cloneOf(String variableName, T defaultValue) { T obj = get(variableName , defaultValue); if (obj == defaultValue) diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index 8a20384..e09c3b3 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -1,6 +1,5 @@ package org.ugp.serialx.juss.converters; -import static org.ugp.serialx.Utils.Clone; import static org.ugp.serialx.Utils.contains; import static org.ugp.serialx.Utils.fastReplace; import static org.ugp.serialx.Utils.multilpy; @@ -13,23 +12,20 @@ import org.ugp.serialx.GenericScope; import org.ugp.serialx.LogProvider; -import org.ugp.serialx.Scope; -import org.ugp.serialx.Utils; -import org.ugp.serialx.Utils.NULL; import org.ugp.serialx.converters.DataConverter; -import org.ugp.serialx.converters.DataParser; +import org.ugp.serialx.converters.VariableParser; /** - * This converter is capable of converting {@link Map.Entry} and reading variables from {@link Scope} via "$"! - * {@link VariableConverter#parse(String, Object...)} required one additional Scope argument in args... argument! - * Its case insensitive!
+ * This converter is capable of converting {@link Map.Entry} and reading variables from {@link GenericScope} by using "$"! + * {@link VariableConverter#parse(String, Object...)} required one additional Scope argument in args... at index 0! + * Its case sensitive!
* Exact outputs of this converter are based on inserted scope! * * @author PETO * * @since 1.3.0 */ -public class VariableConverter implements DataConverter +public class VariableConverter extends VariableParser implements DataConverter { protected boolean jsonStyle; @@ -57,7 +53,7 @@ public VariableConverter(boolean jsonStyle) @SuppressWarnings("unchecked") @Override - public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) + public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) { if (args.length > 0 && arg.length() > 0 && args[0] instanceof GenericScope) { @@ -69,7 +65,7 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) Object obj = null; String objString = enrty[enrty.length-1]; - + if (enrty.length > 1 && !objString.isEmpty()) { obj = myHomeRegistry.parse(objString, args); @@ -93,7 +89,7 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) sc.put(genericVar ? myHomeRegistry.parse(tree[tree.length-1], true, null, args) : tree[tree.length-1], obj); } else - LogProvider.instance.logErr("Variable \"" + tree[tree.length-2] +"\" was not declared as scope in its scope so variable \"" + tree[tree.length-1] +"\" cant be set to \"" + obj + "\"!", null); + LogProvider.instance.logErr("Variable \"" + tree[tree.length-2] + "\" was not declared as scope in its scope so variable \"" + tree[tree.length-1] +"\" cant be set to \"" + obj + "\"!", null); } else if (obj == VOID) scope.variables().remove(enrty[i]); @@ -101,64 +97,13 @@ else if (obj == VOID) scope.put(genericVar ? myHomeRegistry.parse(enrty[i], true, null, args) : enrty[i], obj); } } + if (arg.charAt(0) == '$') return obj; return VOID; } - else if (arg.charAt(0) == '$' && !contains(arg, ' ', '+', '-', '*', '/', '%', '>', '<', '=', '&', '|', '^', '?', '=')) - { -// Object obj; -// if ((arg = fastReplace(arg, "$", "")).indexOf('.') > -1) -// { -// Object[] path = splitValues(fastReplace(fastReplace(arg, "::new", ""), "::class", ""), '.'); -// GenericScope sc = (GenericScope) scope.getGenericScope(Arrays.copyOfRange(path, 0, path.length-1)); //TODO: Prevent neccesity of scope parent inheritance. -// obj = sc == null ? null : sc.variables().get(path[path.length-1]); -// /*if (sc == null || !sc.containsVariable(tree[tree.length-1])) -// LogProvider.instance.logErr("Variable \"" + tree[tree.length-1] + "\" was not declared in \"" + arg.substring(0, arg.length() - tree[tree.length-1].length() - 1) + "\"! Defaulting to null!");*/ -// } -// else -// { -// String str = fastReplace(fastReplace(arg, "::new", ""), "::class", ""); -// /*if (!scope.containsVariable(str)) -// LogProvider.instance.logErr("Variable \"" + str + "\" was not declared! Defaulting to null!");*/ -// obj = scope.variables().get(str); -// } - - Object obj; - if ((arg = fastReplace(arg, "$", "")).indexOf('.') > -1) - { - Object[] path = splitValues(fastReplace(fastReplace(arg, "::new", ""), "::class", ""), '.'); - if ((obj = scope.get(path)) == null && !scope.variables().containsKey(path[0])) - { - for (GenericScope parent = scope.getParent(); parent != null; parent = parent.getParent()) - if (parent.variables().containsKey(path[0])) - { - obj = parent.get(path); - break; - } - } - -// GenericScope sc = (GenericScope) scope.getGenericScope(Arrays.copyOfRange(path, 0, path.length-1)); //TODO: Prevent neccesity of scope parent inheritance. - /*if (sc == null || !sc.containsVariable(tree[tree.length-1])) - LogProvider.instance.logErr("Variable \"" + tree[tree.length-1] + "\" was not declared in \"" + arg.substring(0, arg.length() - tree[tree.length-1].length() - 1) + "\"! Defaulting to null!");*/ - } - else - { - String str = fastReplace(fastReplace(arg, "::new", ""), "::class", ""); - /*if (!scope.containsVariable(str)) - LogProvider.instance.logErr("Variable \"" + str + "\" was not declared! Defaulting to null!");*/ - if ((obj = scope.variables().getOrDefault(str, VOID)) == VOID) - { - for (GenericScope parent = scope.getParent(); parent != null; parent = parent.getParent()) - if ((obj = parent.variables().getOrDefault(str, VOID)) != VOID) - break; - } - } - - if (obj == null || obj == VOID) // Was not found... - return null; - return arg.endsWith("::class") ? obj.getClass() : arg.endsWith("::new") ? Clone(obj) : obj; - } + + return parse(myHomeRegistry, arg, scope, args); //Reading vars from scope... } return CONTINUE; } @@ -176,7 +121,9 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object.. boolean jsonStyle = isJsonStyle(), genericVar = false; Object key = (genericVar = !((key = var.getKey()) instanceof String)) ? myHomeRegistry.toString(key, args) : key, val = var.getValue(); - return new StringBuilder().append(jsonStyle && !genericVar ? "\""+key+"\"" : key).append(val instanceof Scope && !((Scope) val).isEmpty() ? (jsonStyle ? " : " : " =\n" + multilpy('\t', tabs)) : (jsonStyle ? " : " : " = ")).append(myHomeRegistry.toString(val, args)); + return new StringBuilder().append(jsonStyle && !genericVar ? "\""+key+"\"" : key) + .append(val instanceof GenericScope && !((GenericScope) val).isEmpty() ? (jsonStyle ? " : " : " =\n" + multilpy('\t', tabs)) : (jsonStyle ? " : " : " = ")) + .append(myHomeRegistry.toString(val, args)); } return CONTINUE; } From 269d20fb9a1f0c32b9bcbefceb0f0c870d5c74bc Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 19 Mar 2024 07:52:26 +0100 Subject: [PATCH 16/48] refactoring variable converter, adding access member op --- .../java/org/ugp/serialx/GenericScope.java | 4 +- .../src/main/java/org/ugp/serialx/Scope.java | 2 +- .../src/main/java/org/ugp/serialx/Utils.java | 11 ++- .../serialx/converters/ProtocolConverter.java | 3 +- .../serialx/converters/VariableParser.java | 51 ++++++---- .../juss/converters/VariableConverter.java | 97 ++++++++++++------- 6 files changed, 105 insertions(+), 63 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index 8f243dd..778c47d 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -267,7 +267,7 @@ public V get(KeyT variableKey) * @param variableKey | Variables name. * @param defaultValue | Default value to return. * - * @return Value of variable with name or defaultValue if there is no such a one or given key contains null! + * @return Value of variable with name or defaultValue if there is no such a one (or given key contains null)! * * @since 1.2.5 */ @@ -337,7 +337,7 @@ public V get(KeyT... pathToValue) * @param cls | Default value to return. * @param defaultValue | Class that you want the obtained object to be converted into! Exact conversion algorithm can differ based on its implementations. * - * @return Value of variable with name given converted to object of cls or defaultValue if there is no such a one or given key contains null! + * @return Value of variable with name given converted to object of cls or defaultValue if there is no such a one (or given key contains null)! * * @throws Exception | If converting to object of cls failed from some reason! This can differ from implementation to implementation! By default it uses {@link GenericScope#toObject(cls)} * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java index 757dc98..eba21de 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java @@ -514,7 +514,7 @@ else if (obj instanceof CharSequence) */ public String getString(int valueIndex) { - return String.valueOf(get(valueIndex)); + return String.valueOf((Object) get(valueIndex)); } /** diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index 830ba29..e59b8ff 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -218,7 +218,7 @@ public static Object InvokeFunc(Object obj, Class objCls, String name, Class< */ public static T Clone(T obj) { - return Clone(obj, DataParser.REGISTRY, new Object[] {}, new Scope()); + return Clone(obj, DataParser.REGISTRY, new Object[0], new Scope()); } /** @@ -458,8 +458,8 @@ public static StringBuilder multilpy(char ch, int times) */ public static StringBuilder multilpy(CharSequence str, int times) { - StringBuilder sb = new StringBuilder(str); - while (times-- > 1) + StringBuilder sb = new StringBuilder(); + while (times-- > 0) sb.append(str); return sb; } @@ -503,7 +503,7 @@ public static String[] splitValues(String s, int limit, boolean splitAfterSingle * * @since 1.3.5 */ - public static String[] splitValues(String s, int limit, boolean oneOrMore, char[] splitBreaks, char... splitter) + public static String[] splitValues(String s, int limit, boolean oneOrMore, char[] splitBreaks, char... splitter) //TODO: This bs is terribly broken! Idk what I was doing back then but its not doing what I would assume at all... { if (splitter.length <= 0 || limit == 1) return new String[] {s}; @@ -727,9 +727,12 @@ public static boolean isOneOf(int ch, char... chars) public static boolean contains(CharSequence str, char... oneOf) { if (oneOf.length == 1) + { for (int i = 0, len = str.length(); i < len; i++) if (str.charAt(i) == oneOf[0]) return true; + return false; + } for (int i = 0, len = str.length(); i < len; i++) if (isOneOf(str.charAt(i), oneOf)) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java index 7dd56f0..c41079c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java @@ -2,7 +2,6 @@ import static org.ugp.serialx.Utils.Instantiate; import static org.ugp.serialx.Utils.indexOfNotInObj; -import static org.ugp.serialx.Utils.isOneOf; import static org.ugp.serialx.Utils.splitValues; import java.io.Serializable; @@ -115,7 +114,7 @@ protected Object parse(ParserRegistry myHomeRegistry, Class objClass, String String[] args = splitValues(str, ' '); int nameIndex; - if (!isOneOf(args[0].charAt(0), '{', '[') && (nameIndex = args[0].indexOf("::")) > -1) //Is static member invocation + if ((args[0].charAt(0) | ' ') != '{' && (nameIndex = args[0].indexOf("::")) > -1) //Is static member invocation { String memberName = args[0].substring(nameIndex + 2); if (!isAllowStaticMemberInvocation()) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java index 2e40c57..947e52e 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java @@ -11,7 +11,8 @@ /** * This parser is capable of reading variables from {@link GenericScope} by using "$"! - * {@link VariableConverter#parse(String, Object...)} required one additional Scope argument in args... at index 0! + * {@link VariableConverter#parse(String, Object...)} required one additional Scope argument in args... at index 0!
+ * It also manages access member operator also known as separator ".". * Its case sensitive!
* Exact outputs of this converter are based on inserted scope! * @@ -31,10 +32,27 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) } return CONTINUE; } + + /** + * @param source | Source object to get value of the member from (may or may not be null). Source should not be modified! + * @param member | Name/key of the member to get. + * + * @return The value of member from given source. You can think about this as ekvivalent to source.member in Java. If member with provided name/key is not present in the source or its value is not possible to get, {@link VOID} has to be returned! If source can't be accessed/dereferenced, null has to be returned!
+ * Note: This method is meant to be overridden in order to add support for accessing multiple sources because by default it supports only {@link GenericScope} + * + * @since 1.3.7 + */ + @SuppressWarnings("unchecked") + public Object getMemberOperator(Object source, Object member) + { + if (source instanceof GenericScope) + return ((GenericScope) source).variables().getOrDefault(member, VOID); + return null; + } /** * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! - * @param str | Source string (preferably with some variables to read)! + * @param str | Source string, should not be null or empty (preferably with some variables to read)! * @param scope | Source scope to read from, can't be null! * @param args | Some additional args. This can be anything and it demands on implementation of DataParser. * @@ -42,12 +60,10 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) * * @since 1.3.7 */ - @SuppressWarnings("unchecked") - protected Object parse(ParserRegistry myHomeRegistry, String str, GenericScope scope, Object... args) + protected Object parse(ParserRegistry myHomeRegistry, String str, GenericScope scope, Object... args) { - if (str.charAt(0) == '$' && !contains(str, ' ', '+', '-', '*', '/', '%', '>', '<', '=', '&', '|', '^', '?', '=')) + if (str.charAt(0) == '$' && !contains(str = str.substring(1), ' ', '+', '-', '*', '/', '%', '>', '<', '=', '&', '|', '^', '?', '=')) { - boolean clsModif = str.endsWith("::class"), newModif = false; // Handle modifiers... if (clsModif) str = str.substring(0, str.length()-7); @@ -55,30 +71,24 @@ else if (newModif = str.endsWith("::new")) str = str.substring(0, str.length()-5); Object obj = null; - if ((str = str.substring(1)).indexOf('.') > -1) + if (str.indexOf('.') > -1) { - Object[] path = splitValues(str, '.'); + String[] path = splitValues(str, '.'); int iLast = path.length-1; backlook: do { - Object sc = scope.variables().getOrDefault(path[0], VOID); - if (sc instanceof GenericScope) // The first one has to be scope! + Object sc; + if ((sc = getMemberOperator(scope, path[0])) != VOID) // Attempt to get only when exists... { - for (int i = 1; i < iLast; i++) // Subscope/forward lookup... - if (!((sc = ((GenericScope) sc).get(path[i])) instanceof GenericScope)) + for (int i = 1; i < iLast; i++) // Subscope/forward lookup (inner path only)... + if ((sc = getMemberOperator(sc, path[i])) == null || sc == VOID) { // LogProvider.instance.logErr("Value of path \"" + arg + "\" cannot be dereferenced because \"" + path[i] + "\" is not a scope but " + sc + "!", null); break backlook; } - obj = ((GenericScope) sc).variables().get(path[iLast]); - break; - } - - if (sc != VOID) // = variable was defined in parent but it is not a scope, it means we want to break cos we can't deref that = treat the path as invalid (undefined)... - { - // LogProvider.instance.logErr("Value of path \"" + arg + "\" cannot be dereferenced because \"" + path[0] + "\" is not a scope but " + sc + "!", null); + obj = getMemberOperator(sc, path[iLast]); break; } } @@ -96,8 +106,9 @@ else if (newModif = str.endsWith("::new")) if (obj == null || obj == VOID) // When was not found... return null; - return clsModif ? obj.getClass() : newModif ? Clone(obj, scope instanceof Serializer ? ((Serializer) scope).getParsers() : DataParser.REGISTRY, new Object[] {}, new Scope()) : obj; + return clsModif ? obj.getClass() : newModif ? Clone(obj, scope instanceof Serializer ? ((Serializer) scope).getParsers() : DataParser.REGISTRY, new Object[0], new Scope()) : obj; } + return CONTINUE; } } diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index e09c3b3..e5e8412 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -1,12 +1,10 @@ package org.ugp.serialx.juss.converters; import static org.ugp.serialx.Utils.contains; -import static org.ugp.serialx.Utils.fastReplace; import static org.ugp.serialx.Utils.multilpy; import static org.ugp.serialx.Utils.splitValues; import java.util.AbstractMap; -import java.util.Arrays; import java.util.Map; import java.util.Map.Entry; @@ -17,13 +15,16 @@ /** * This converter is capable of converting {@link Map.Entry} and reading variables from {@link GenericScope} by using "$"! - * {@link VariableConverter#parse(String, Object...)} required one additional Scope argument in args... at index 0! + * {@link VariableConverter#parse(String, Object...)} required one additional Scope argument in args... at index 0!
+ * It manages assign operator = as well as access member operator also known as separator ".".
* Its case sensitive!
* Exact outputs of this converter are based on inserted scope! * * @author PETO * * @since 1.3.0 + * + * @see VariableParser */ public class VariableConverter extends VariableParser implements DataConverter { @@ -57,64 +58,68 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) { if (args.length > 0 && arg.length() > 0 && args[0] instanceof GenericScope) { - GenericScope scope = (GenericScope) args[0]; - boolean genericVar = args.length > 4 && args[4] == GenericScope.class; + GenericScope scope = (GenericScope) args[0]; if (isVarAssignment(arg)) { - String[] enrty = splitValues(arg, 0, false, new char[] {'?'}, '=', ':'); - - Object obj = null; - String objString = enrty[enrty.length-1]; + boolean getValueModif = arg.charAt(0) == '$', genericVar = args.length > 4 && args[4] == GenericScope.class; + if (getValueModif) + arg = arg.substring(1); + + String vars[] = splitValues(arg, 0, false, new char[] {'?'}, '=', ':'), valStr; - if (enrty.length > 1 && !objString.isEmpty()) + Object val = null; + int iVal = vars.length-1; + if (vars.length > 1 && !(valStr = vars[iVal]).isEmpty()) { - obj = myHomeRegistry.parse(objString, args); + val = myHomeRegistry.parse(valStr, args); } - for (int i = 0; i < enrty.length-1; i++) + eachVar: for (int i = 0; i < iVal; i++) // Support for assigning multiple vars to the same value... { - if (!genericVar && contains(enrty[i] = enrty[i].trim(), ' ')) - LogProvider.instance.logErr("Variable name \"" + enrty[i] + "\" is invalid, blank characters are not allowed!", null); - else + String var = vars[i]; + if (!genericVar && contains(var, ' ')) + LogProvider.instance.logErr("Variable name \"" + var + "\" is invalid, blank characters are not allowed!", null); + else if (var.indexOf('.') > -1) { - if ((enrty[i] = fastReplace(enrty[i], "$", "")).indexOf('.') > -1) + String[] path = splitValues(var, '.'); + int iLast = path.length-1, j = 0; + + backlook: do { - String[] tree = splitValues(enrty[i], '.'); - GenericScope sc = (GenericScope) scope.getGenericScope((Object[]) Arrays.copyOfRange(tree, 0, tree.length-1)); - if (sc != null) + Object sc; + if ((sc = getMemberOperator(scope, path[0])) != VOID) // Attempt to get only when exists... { - if (obj == VOID) - sc.variables().remove(enrty[i]); - else - sc.put(genericVar ? myHomeRegistry.parse(tree[tree.length-1], true, null, args) : tree[tree.length-1], obj); + for (j = 1; j < iLast; j++) // Subscope/forward lookup (inner path only)... + if ((sc = getMemberOperator(sc, path[j])) == null || sc == VOID) + break backlook; + + setMemberOperator(myHomeRegistry, sc, path[iLast], val, genericVar, args); + continue eachVar; } - else - LogProvider.instance.logErr("Variable \"" + tree[tree.length-2] + "\" was not declared as scope in its scope so variable \"" + tree[tree.length-1] +"\" cant be set to \"" + obj + "\"!", null); } - else if (obj == VOID) - scope.variables().remove(enrty[i]); - else - scope.put(genericVar ? myHomeRegistry.parse(enrty[i], true, null, args) : enrty[i], obj); + while ((scope = scope.getParent()) != null); + + LogProvider.instance.logErr("Path \"" + var + "\" cannot be set to \"" + val + "\" because \"" + path[j] + "\" is not a accessible or does not exist!", null); } + else + setMemberOperator(myHomeRegistry, scope, var, val, genericVar, args); } - if (arg.charAt(0) == '$') - return obj; - return VOID; + return getValueModif ? val : VOID; } return parse(myHomeRegistry, arg, scope, args); //Reading vars from scope... } + return CONTINUE; } - @SuppressWarnings("unchecked") @Override public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) { if (obj instanceof Entry) { - Entry var = (Entry) obj; + Entry var = (Entry) obj; int tabs = 0; if (args.length > 1 && args[1] instanceof Integer) tabs = (int) args[1]; @@ -136,6 +141,30 @@ public CharSequence getDescription(ParserRegistry myHomeRegistry, Object objToDe return new StringBuilder(myHomeRegistry.getConverterFor(ent.getValue(), argsUsedConvert).getDescription(myHomeRegistry, ent.getValue(), argsUsedConvert)).append(" Stored by \"").append(ent.getKey()).append("\" variable!"); } + /** + * @param myHomeRegistry | {@link ParserRegistry} provided by caller, may or may not be used... + * @param source | Source object to set the value member. + * @param member | Name/key of the member to set. + * @param val | Value to set the member to. + * @param genericVar | If true, member is expected be generic (not only string) and further parsing is required, may or may not be used... + * @param args | Some additional args to be used in case of parsing that are provided by called, may or may not be used... + * + * @return By default it returns the previous value of the member. If member with provided name/key is not present in the source or its value is not possible to set, {@link VOID} should be returned! + * + * @since 1.3.7 + */ + @SuppressWarnings("unchecked") + public Object setMemberOperator(ParserRegistry myHomeRegistry, Object source, String member, Object val, boolean genericVar, Object... args) + { + if (source instanceof GenericScope) + { + if (val == VOID) + return ((GenericScope) source).remove(member); + return ((GenericScope) source).put(genericVar ? myHomeRegistry.parse(member, true, null, args) : member, val); + } + return VOID; + } + /** * @return True if variables will be serialized using json style ("key" : value)! * From 11351a37ac285ad735bc3c57a108c2456cadf9d4 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sun, 31 Mar 2024 00:11:01 +0100 Subject: [PATCH 17/48] Fixing splitValues, small fix JussSerializer#from, finishing refactor of VarParser and Converter + scope inheritance removed! --- .../main/java/org/ugp/serialx/Serializer.java | 28 ++++---- .../src/main/java/org/ugp/serialx/Utils.java | 64 ++++++++++++++----- .../serialx/converters/VariableParser.java | 11 ++-- .../org/ugp/serialx/juss/JussSerializer.java | 4 -- .../juss/converters/ObjectConverter.java | 3 +- .../juss/converters/VariableConverter.java | 30 +++++---- 6 files changed, 82 insertions(+), 58 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 9b5476b..9cc2103 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -28,13 +28,8 @@ import java.util.Map; import java.util.function.Function; -import org.ugp.serialx.converters.BooleanConverter; -import org.ugp.serialx.converters.CharacterConverter; import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.converters.DataParser.ParserRegistry; -import org.ugp.serialx.converters.NullConverter; -import org.ugp.serialx.converters.NumberConverter; -import org.ugp.serialx.converters.SerializableBase64Converter; import org.ugp.serialx.converters.StringConverter; import org.ugp.serialx.protocols.SerializationProtocol; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; @@ -56,7 +51,7 @@ public abstract class Serializer extends Scope * * @since 1.3.2 */ - public static final ParserRegistry COMMON_PARSERS = new ParserRegistry(new StringConverter(), /* TODO: new ProtocolConverter() */ new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter()); + public static final ParserRegistry COMMON_PARSERS = DataParser.REGISTRY.clone(); protected ParserRegistry parsers; protected ProtocolRegistry protocols; @@ -1064,8 +1059,9 @@ Obtained serializer content (return) * - * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often) or when something went wrong during deserialization! + * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often) or when something went very wrong during deserialization! * @throws IntrospectionException when there were no PropertyDescriptor found for obj class! + * @throws RuntimeException in case of something went wrong during deserialization process and {@link LogProvider#isReThrowException()} is set to true! * * @since 1.3.5 */ @@ -1073,20 +1069,18 @@ public static Serializer from(Serializer newInstance, Object fromObj, String... { if (fromObj instanceof CharSequence) { - if (indexOfNotInObj((CharSequence) fromObj, "http") == 0) - try - { - return newInstance.LoadFrom(new URL(fromObj.toString()).openStream()); - } - catch (IOException e) - {} - try { - return newInstance.LoadFrom(new File(fromObj.toString())); + String fromStr; + if (indexOfNotInObj(fromStr = fromObj.toString(), "http") == 0) + return newInstance.LoadFrom(new URL(fromStr).openStream()); + return newInstance.LoadFrom(new File(fromStr)); } catch (Exception e) - {} + { + if (e instanceof RuntimeException) + throw e; + } return newInstance.LoadFrom((CharSequence) fromObj); } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index e59b8ff..899f72c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -468,42 +468,65 @@ public static StringBuilder multilpy(CharSequence str, int times) * @param s | String to split and check some syntax. * @param splitter | Chars where string will be split! * - * @return String splitted after splitters. If there is more than one splitter in row, it will be taken as one whole! + * @return String splitted after splitters. More than one splitter in row will be take as 1. Each resulting token will be {@link String#trim() trim}med! * * @since 1.0.0 */ public static String[] splitValues(String s, char... splitter) { - return splitValues(s, 0, true, splitter); + return splitValues(s, 0, 2, splitter); } /** * @param s | String to split and check some syntax. * @param limit | If 0 or less = no limit, 1 = no splitting, more than 1 = count of results! - * @param oneOrMore | If true, string will be splitted after one or more splitters in row, if false splitting will occur only after single splitter (this is similar to "+" in regex)! + * @param splittingStrategy | If 0, splitting will occur after each splitter! + * If 1, string will be splitted after only one splitter, more than one splitters in row will be ignored! + * If 2, splitting will occur after any number of splitters, n number of splitters in row will be treated as 1! * @param splitter | Chars where string will be split! * - * @return String splitted after splitters according to arguments. If there is more than one splitter in row, it will be taken as one whole! + * @return String splitted after splitters according to arguments. Each resulting token will be {@link String#trim() trim}med! * * @since 1.3.0 */ - public static String[] splitValues(String s, int limit, boolean splitAfterSingleCharOnly, char... splitter) + public static String[] splitValues(String s, int limit, int splittingStrategy, char... splitter) { - return splitValues(s, limit, splitAfterSingleCharOnly, new char[0], splitter); + return splitValues(s, 0, limit, splittingStrategy, new char[0], splitter); } /** * @param s | String to split and check some syntax. * @param limit | If 0 or less = no limit, 1 = no splitting, more than 1 = count of results! - * @param oneOrMore | If true, string will be splitted after one or more splitters in row, if false splitting will occur only after single splitter (this is similar to "+" in regex)! + * @param splittingStrategy | If 0, splitting will occur after each splitter! + * If 1, string will be splitted after only one splitter, more than one splitters in row will be ignored! + * If 2, splitting will occur after any number of splitters, n number of splitters in row will be treated as 1! * @param splitBreaks | When some of these characters is encountered, splitting is terminated for the rest of the string! * @param splitter | Chars where string will be split! * - * @return String splitted after splitters according to arguments. If there is more than one splitter in row, it will be taken as one whole! + * @return String splitted after splitters according to arguments. Each resulting token will be {@link String#trim() trim}med! * * @since 1.3.5 */ - public static String[] splitValues(String s, int limit, boolean oneOrMore, char[] splitBreaks, char... splitter) //TODO: This bs is terribly broken! Idk what I was doing back then but its not doing what I would assume at all... + public static String[] splitValues(String s, int limit, int splittingStrategy, char[] splitBreaks, char... splitter) + { + return splitValues(s, 0, limit, splittingStrategy, splitBreaks, splitter); + } + + /** + * @param s | String to split and check some syntax. + * @param i | Index of character to start at. Note that everything before this index will be ignored by other options... + * @param limit | If 0 or less = no limit, 1 = no splitting, more than 1 = count of results! + * @param splittingStrategy | If 0, splitting will occur after each splitter! + * If 1, string will be splitted after only one splitter, more than one splitters in row will be ignored! + * If 2, splitting will occur after any number of splitters, n number of splitters in row will be treated as 1! + * @param splitBreaks | When some of these characters is encountered, splitting is terminated for the rest of the string! + * @param splitter | Chars where string will be split! + * + * @return String splitted after splitters according to arguments. Each resulting token will be {@link String#trim() trim}med! + * + * @since 1.3.7 + */ + public static String[] splitValues(String s, int i, int limit, int splittingStrategy, char[] splitBreaks, char... splitter) { if (splitter.length <= 0 || limit == 1) return new String[] {s}; @@ -512,9 +535,9 @@ public static String[] splitValues(String s, int limit, boolean oneOrMore, char[ // return splitValues(" "+s, limit, oneOrMore, splitBreaks, splitter); List result = new ArrayList<>(); - - int brackets = 0, quote = 0, lastIndex = 0; - for (int i = 0, count = 1, len = s.length(), oldCh = splitter[0]; i < len && (limit <= 0 || count < limit); i++) + + int brackets = 0, quote = 0, lastIndex = 0, len = s.length(); + for (int count = 1, oldCh = 0; i < len && (limit <= 0 || count < limit); i++) { char ch = s.charAt(i); if (ch == '"') @@ -528,10 +551,17 @@ public static String[] splitValues(String s, int limit, boolean oneOrMore, char[ break; } - if (brackets == 0 && oldCh != ch && isOneOf(ch, splitter) && (oneOrMore || (i >= len-1 || !isOneOf(s.charAt(i+1), splitter)))) + if (brackets == 0 && isOneOf(ch, splitter) && + (splittingStrategy != 1 || ch != oldCh && (i >= len-1 || !isOneOf(s.charAt(i+1), splitter)))) { - result.add(s.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i).trim()); - count++; + String tok = s.substring(lastIndex, i).trim(); + if (splittingStrategy < 2 || result.isEmpty() || !tok.isEmpty()) + { + result.add(tok); + lastIndex = i + 1; + + count++; + } } else if ((ch | ' ') == '{') brackets++; @@ -545,14 +575,14 @@ else if ((ch | ' ') == '}') } oldCh = ch; } - + if (brackets > 0) throw new IllegalArgumentException("Unclosed brackets in: " + s); else if (quote % 2 != 0) throw new IllegalArgumentException("Unclosed or missing quotes in: " + s); else { - result.add(s.substring(lastIndex == 0 ? 0 : lastIndex + 1, s.length()).trim()); + result.add(s.substring(lastIndex, len).trim()); } return result.toArray(new String[0]); diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java index 947e52e..ba99062 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java @@ -10,9 +10,9 @@ import org.ugp.serialx.Serializer; /** - * This parser is capable of reading variables from {@link GenericScope} by using "$"! - * {@link VariableConverter#parse(String, Object...)} required one additional Scope argument in args... at index 0!
- * It also manages access member operator also known as separator ".". + * This parser is capable of reading variables from {@link GenericScope} by using $!
+ * {@link VariableParser#parse(String, Object...)} requires one additional Scope argument in args... at index 0!
+ * It also manages access member operator also known as separator ".".
* Its case sensitive!
* Exact outputs of this converter are based on inserted scope! * @@ -71,9 +71,10 @@ else if (newModif = str.endsWith("::new")) str = str.substring(0, str.length()-5); Object obj = null; - if (str.indexOf('.') > -1) + int op0Index; + if ((op0Index = str.indexOf('.')) > -1) { - String[] path = splitValues(str, '.'); + String[] path = splitValues(str, op0Index, 0, 0, new char[0], '.'); int iLast = path.length-1; backlook: do diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index 0871155..ccb1a71 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -497,10 +497,6 @@ else if (ch == '}' || ch == ']') if (parent == null) getImports().removeImportsOf(this); -// else -// for (Map.Entry ent : parent.varEntrySet()) -// if (variables().get(ent.getKey()) == ent.getValue()) -// variables().remove(ent.getKey());//TODO: Prevent neccesity of scope parent inheritance. return (S) this; } diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java index 00c7c42..086ac55 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java @@ -111,10 +111,9 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... compile scope = getPreferredSerializer(); } - //TODO: Prevent neccesity of scope parent inheritance. compilerArgs = compilerArgs.clone(); compilerArgs[0] = false; //No extra formating... - return str.isEmpty() ? scope : ((Serializer) scope/*.inheritParent()*/).LoadFrom(new StringReader(str), compilerArgs); + return str.isEmpty() ? scope : scope.LoadFrom(new StringReader(str), compilerArgs); } } return CONTINUE; diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index e5e8412..c3f57f5 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -14,8 +14,8 @@ import org.ugp.serialx.converters.VariableParser; /** - * This converter is capable of converting {@link Map.Entry} and reading variables from {@link GenericScope} by using "$"! - * {@link VariableConverter#parse(String, Object...)} required one additional Scope argument in args... at index 0!
+ * This converter is capable of converting {@link Map.Entry} and reading variables from {@link GenericScope} by using $!
+ * {@link VariableConverter#parse(String, Object...)} requires one additional Scope argument in args... at index 0!
* It manages assign operator = as well as access member operator also known as separator ".".
* Its case sensitive!
* Exact outputs of this converter are based on inserted scope! @@ -59,13 +59,17 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) if (args.length > 0 && arg.length() > 0 && args[0] instanceof GenericScope) { GenericScope scope = (GenericScope) args[0]; - if (isVarAssignment(arg)) + int op0Index; + if ((op0Index = isVarAssignment(arg)) > -1) { boolean getValueModif = arg.charAt(0) == '$', genericVar = args.length > 4 && args[4] == GenericScope.class; if (getValueModif) + { arg = arg.substring(1); + op0Index--; + } - String vars[] = splitValues(arg, 0, false, new char[] {'?'}, '=', ':'), valStr; + String vars[] = splitValues(arg, op0Index, 0, 1, new char[] {'?'}, '=', ':'), valStr; Object val = null; int iVal = vars.length-1; @@ -74,14 +78,14 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) val = myHomeRegistry.parse(valStr, args); } - eachVar: for (int i = 0; i < iVal; i++) // Support for assigning multiple vars to the same value... + eachVar: for (int i = 0; i < iVal; i++) // Support for assigning multiple vars to the same value... Yea this is not the prettiest code but it does the job and mainly it does it fast so shut up! { String var = vars[i]; - if (!genericVar && contains(var, ' ')) + if (!genericVar && contains(var, ' ')) LogProvider.instance.logErr("Variable name \"" + var + "\" is invalid, blank characters are not allowed!", null); - else if (var.indexOf('.') > -1) + else if ((op0Index = var.indexOf('.')) > -1) { - String[] path = splitValues(var, '.'); + String[] path = splitValues(var, op0Index, 0, 0, new char[0], '.'); int iLast = path.length-1, j = 0; backlook: do @@ -188,11 +192,11 @@ public void setJsonStyle(boolean jsonStyle) /** * @param s | CharSequence to search! * - * @return true if inserted expression is variable assignment expression such as variable = 4 otherwise false! + * @return Index of first assignment operator ('=' or ':') if inserted expression is variable assignment expression such as variable = 4, otherwise -1! * * @since 1.3.0 */ - public static boolean isVarAssignment(CharSequence s) + public static int isVarAssignment(CharSequence s) { for (int i = 0, brackets = 0, quote = 0, len = s.length(), oldCh = -1, chNext; i < len; i++) { @@ -203,9 +207,9 @@ public static boolean isVarAssignment(CharSequence s) if (quote % 2 == 0) { if (ch == '?') - return false; + return -1; else if (brackets == 0 && (ch == '=' || ch == ':') && !(oldCh == '=' || oldCh == ':' || oldCh == '!' || oldCh == '>'|| oldCh == '<') && (i >= len-1 || !((chNext = s.charAt(i+1)) == '=' || chNext == ':' || chNext == '!' || chNext == '>'|| chNext == '<'))) - return true; + return i; else if ((ch | ' ') == '{') brackets++; else if ((ch | ' ') == '}') @@ -214,7 +218,7 @@ else if ((ch | ' ') == '}') } oldCh = ch; } - return false; + return -1; } // public static V getValueOf(GenericScope scope, K... pathToScope) From 22478c466004b7bd52ecb6b85c974ba154f92f8e Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 2 Apr 2024 17:02:02 +0200 Subject: [PATCH 18/48] removing oop NULL like the colossal mistake it was... --- .../src/main/java/org/ugp/serialx/GenericScope.java | 10 +++------- .../src/main/java/org/ugp/serialx/Serializer.java | 6 +++--- SerialX-core/src/main/java/org/ugp/serialx/Utils.java | 2 +- .../java/org/ugp/serialx/converters/NullConverter.java | 4 +--- .../main/java/org/ugp/serialx/juss/JussSerializer.java | 3 +-- .../operators/ConditionalAssignmentOperators.java | 3 +-- 6 files changed, 10 insertions(+), 18 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index 778c47d..7cec162 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -16,7 +16,6 @@ import java.util.function.Function; import java.util.function.Predicate; -import org.ugp.serialx.Utils.NULL; import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.protocols.SerializationProtocol; import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry; @@ -277,7 +276,7 @@ public V get(KeyT variableKey, V defaultValue) V obj = (V) variables().get(variableKey); if (obj == null) return defaultValue; - return obj instanceof NULL ? null : obj; + return obj; } /** @@ -388,8 +387,7 @@ public boolean containsIndependentValue(ValT value) @SuppressWarnings("unchecked") public V get(int valueIndex) { - V obj = (V) values().get(valueIndex < 0 ? valuesCount() + valueIndex : valueIndex); - return obj instanceof NULL ? null : obj; + return (V) values().get(valueIndex < 0 ? valuesCount() + valueIndex : valueIndex); } /** @@ -600,7 +598,6 @@ public GenericScope transform(Function trans, boolean incl try { Object obj = ent.getValue(); - obj = obj instanceof NULL ? null : obj; if (obj instanceof GenericScope && includeSubScopes) { GenericScope sc = ((GenericScope) obj).transform(trans, includeSubScopes); @@ -655,8 +652,7 @@ public List map(Function trans, boolean includeSubScopes) List fltVals = new ArrayList<>(); for (Object obj : this) try - { - obj = obj instanceof NULL ? null : obj; + { if (obj instanceof GenericScope && includeSubScopes) { GenericScope sc = ((GenericScope) obj).transform(trans, includeSubScopes); diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 9cc2103..f677009 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -653,7 +653,7 @@ else if (multLineCom <= -1 && ch == '"') if (semicolon > index) { lineReader.close(); - return (T) NULL.toOopNull(DataParser.parseObj(DataParser.REGISTRY, sb.toString(), this)); + return (T) DataParser.parseObj(DataParser.REGISTRY, sb.toString(), this); } if (multLineCom > -1 || com > -1) //Is comment @@ -722,7 +722,7 @@ else if (ch == '}' || ch == ']') else if (quote % 2 != 0) throw new IllegalArgumentException("Unclosed or missing quotes!"); else if (!(line = sb.toString()).isEmpty()) - return (T) NULL.toOopNull(DataParser.parseObj(DataParser.REGISTRY, line, this)); + return (T) DataParser.parseObj(DataParser.REGISTRY, line, this); LogProvider.instance.logErr("Value with index " + index + " is out of bounds!"); return null; } @@ -808,7 +808,7 @@ else if (multLineCom <= -1 && ch == '"') int start = sb.indexOf("=", findIndex-fromIndexOrig); if (start <= -1) start = sb.indexOf(":", findIndex-fromIndexOrig); - return (T) NULL.toOopNull(DataParser.parseObj(DataParser.REGISTRY, sb.substring(start+1), this)); + return (T) DataParser.parseObj(DataParser.REGISTRY, sb.substring(start+1), this); } if (multLineCom > -1 || com > -1) //Is comment diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index 899f72c..b22206d 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -261,7 +261,7 @@ else if (obj.getClass() == String.class) { ParserRegistry parsers = parsersToUse instanceof ParserRegistry ? (ParserRegistry) parsersToUse : new ParserRegistry(parsersToUse); - Object cln = NULL.toOopNull(parsers.parse(parsers.toString(obj, converterArgs).toString(), parserArgs)); + Object cln = parsers.parse(parsers.toString(obj, converterArgs).toString(), parserArgs); if (cln != null && cln != VOID) return (T) cln; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java index 1d772b3..ae3c7af 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java @@ -1,7 +1,5 @@ package org.ugp.serialx.converters; -import org.ugp.serialx.Utils.NULL; - /** * This converter is capable of converting "nothing" otherwise known as null and {@link DataParser#VOID}. * Its case insensitive! @@ -48,7 +46,7 @@ public Object parse(ParserRegistry registry, String str, Object... args) @Override public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) { - if (obj == null || obj instanceof NULL) + if (obj == null) return "null"; return CONTINUE; } diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index ccb1a71..ea95a34 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -29,7 +29,6 @@ import org.ugp.serialx.Registry; import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; -import org.ugp.serialx.Utils.NULL; import org.ugp.serialx.converters.BooleanConverter; import org.ugp.serialx.converters.CharacterConverter; import org.ugp.serialx.converters.DataConverter; @@ -676,7 +675,7 @@ else if (brackets > 0) */ protected Object parseObject(ParserRegistry registry, String str, Object... parserArgs) { - return NULL.toOopNull(registry.parse(str, parserArgs)); + return registry.parse(str, parserArgs); } /** diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java index 102e19c..57fc84c 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java @@ -3,7 +3,6 @@ import static org.ugp.serialx.Utils.indexOfNotInObj; import org.ugp.serialx.LogProvider; -import org.ugp.serialx.Utils.NULL; import org.ugp.serialx.converters.DataParser; /** @@ -45,7 +44,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) if ((index = str.indexOf("??")) > -1) { Object obj = myHomeRegistry.parse(str.substring(0, index).trim(), args); - if (obj != null && !(obj instanceof NULL)) + if (obj != null) return obj; String next = str.substring(index+2); From fa2b34ff5dda895060d16f07e31a998cfecfc158 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 2 Apr 2024 19:38:50 +0200 Subject: [PATCH 19/48] ... --- pom.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 00e37a7..de6c8cc 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,7 @@ org.apache.maven.plugins maven-compiler-plugin + 3.10.1 ${java.version} @@ -63,7 +64,7 @@ eclipse - + org.codehaus.plexus plexus-compiler-eclipse @@ -72,7 +73,7 @@ org.eclipse.jdt ecj - 3.25.0 + 3.33.0 From 3fd9d39c1643777105c033ab2a1d0c8d8e410a58 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 2 Apr 2024 23:23:32 +0200 Subject: [PATCH 20/48] ... --- SerialX-core/src/main/java/org/ugp/serialx/Utils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index b22206d..51c40eb 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -890,7 +890,7 @@ public static void post(Serializer serializer, HttpURLConnection conn) throws IO * * @deprecated (in 1.3.7) NO LONGER NEEDED, DO NOT USE THIS! You were never supposed to... */ - public static final class NULL //TODO: REMOVE!!!! + public static final class NULL //TODO: REMOVE IN NEXT V!!!! { public static Object toOopNull(Object obj) { From 2faf39ada9a10e9d2113368bdf82bddf2824db1c Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Mon, 8 Apr 2024 08:10:55 +0200 Subject: [PATCH 21/48] important optimiz... --- .../src/main/java/org/ugp/serialx/Utils.java | 20 +++ .../serialx/converters/BooleanConverter.java | 25 +-- .../converters/CharacterConverter.java | 13 +- .../ugp/serialx/converters/NullConverter.java | 15 +- .../serialx/converters/NumberConverter.java | 145 +++++++++++++----- .../serialx/converters/StringConverter.java | 19 ++- 6 files changed, 167 insertions(+), 70 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index 51c40eb..75326ee 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -770,6 +770,26 @@ public static boolean contains(CharSequence str, char... oneOf) return false; } + /** + * @param str | Source string to compare. + * @param lowerCaseOther | Other lower-case string to compare with. This must be lower-case in order for this to work! + * @param from | The beginning index, where to start with comprising (inclusive, most likely 0). + * @param to | The ending marking index, index where to end the comparing (exclusive, most likely str.length()) + * + * @return True if str is equal to lowerCaseOther given that str case is ignored and lowerCaseOther is lower-case, otherwise false. Similar to {@link String#equalsIgnoreCase(String)} but more optimal!
+ * Note that this function was designed for non-blank ASCII strings and may not work properly for others...
+ * Also sufficient length of both strings is not checked so adjust from and to accordingly. + * + * @since 1.3.7 + */ + public static boolean equalsLowerCase(CharSequence str, CharSequence lowerCaseOther, int from, int to) + { + for (; from < to; from++) + if ((str.charAt(from) | ' ') != lowerCaseOther.charAt(from)) + return false; + return true; + } + /** * @param str | String to display! * @param pos | Position to display! diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java index 871a2c4..bc5e442 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java @@ -1,5 +1,8 @@ package org.ugp.serialx.converters; +import static java.lang.Boolean.*; +import static org.ugp.serialx.Utils.equalsLowerCase; + /** * This converter is capable of converting {@link String}. * Its case insensitive! @@ -19,19 +22,19 @@ true - new Boolean(true) + Boolean.TRUE t - new Boolean(true) + Boolean.TRUE false - new Boolean(false) + Boolean.FALSE f - new Boolean(false) + Boolean.FALSE @@ -54,12 +57,16 @@ public BooleanConverter(boolean shorten) } @Override - public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { - if (arg.equalsIgnoreCase("T") || arg.equalsIgnoreCase("true")) - return new Boolean(true); - if (arg.equalsIgnoreCase("F") || arg.equalsIgnoreCase("false")) - return new Boolean(false); + int len, ch0; + if ((len = str.length()) > 0) + { + if ((ch0 = str.charAt(0) | ' ') == 't' && (len == 1 || len == 4 && equalsLowerCase(str, "true", 1, 4))) + return TRUE; + if (ch0 == 'f' && (len == 1 || len == 5 && equalsLowerCase(str, "false", 1, 5))) + return FALSE; + } return CONTINUE; } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java index 3db9a41..d8c276e 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java @@ -1,7 +1,5 @@ package org.ugp.serialx.converters; -import static org.ugp.serialx.Utils.fastReplace; - /** * This converter is capable of converting {@link Character}. * Its case sensitive! @@ -38,16 +36,17 @@ public class CharacterConverter implements DataConverter @Override public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { - if (str.length() > 1 && str.charAt(0) == '\'' && str.charAt(str.length()-1) == '\'') + int len; + if ((len = str.length()) > 1 && str.charAt(0) == '\'' && str.charAt(--len) == '\'') try { - if (str.equals("''")) // TODO: str.length() == 2 + mby cache len - return new Character(' '); - return new Character((char) Integer.parseInt(str = fastReplace(str, "'", ""))); + if (len == 1) // str == "''" + return ' '; + return (char) Integer.parseInt(str.substring(1, len)); } catch (Exception e) { - return new Character(str.charAt(0)); + return str.charAt(0); } return CONTINUE; } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java index ae3c7af..6cc784e 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NullConverter.java @@ -1,5 +1,7 @@ package org.ugp.serialx.converters; +import static org.ugp.serialx.Utils.equalsLowerCase; + /** * This converter is capable of converting "nothing" otherwise known as null and {@link DataParser#VOID}. * Its case insensitive! @@ -19,7 +21,7 @@ null - null (object) + null void @@ -36,10 +38,13 @@ public class NullConverter implements DataConverter @Override public Object parse(ParserRegistry registry, String str, Object... args) { - if (str.equalsIgnoreCase("null")) - return null; - if (str.equalsIgnoreCase("void")) - return VOID; + if (str.length() == 4) + { + if (equalsLowerCase(str, "null", 0, 4)) + return null; + if (equalsLowerCase(str, "void", 0, 4)) + return VOID; + } return CONTINUE; } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java index 68b0d6c..e45762c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -7,8 +7,6 @@ import java.text.DecimalFormatSymbols; import java.util.Locale; -import org.ugp.serialx.LogProvider; - /** * 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! * Its case insensitive! @@ -66,6 +64,8 @@ new Integer(255) new Integer(15) + * + * @see NumberConverter#numberOf(CharSequence, char, int, int) * * @author PETO * @@ -89,47 +89,15 @@ public class NumberConverter implements DataConverter @Override public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) { - if (arg.length() > 0) + int len; + if ((len = arg.length()) > 0) { - char ch = arg.charAt(0); - if (ch == '+' || ch == '-' || ch == '.' || (ch >= '0' && ch <= '9')) + char ch0 = arg.charAt(0); + if (ch0 == '+' || ch0 == '-' || ch0 == '.' || (ch0 >= '0' && ch0 <= '9')) { - arg = normFormatNum(arg.toLowerCase()); - ch = arg.charAt(arg.length()-1); //ch = last char - - if (ch == '.') - return CONTINUE; - if (contains(arg, '.') || (!arg.startsWith("0x") && ch == 'f' || ch == 'd')) - { - if (ch == 'f') - return new Float(fastReplace(arg, "f", "")); - return new Double(fastReplace(arg, "d", "")); - } - - try - { - // TODO: Use decode method instead of this mess if possible... - if (ch == 'l') - return new Long(Long.parseLong(fastReplace(fastReplace(fastReplace(arg, "l", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); - if (ch == 's') - return new Short(Short.parseShort(fastReplace(fastReplace(fastReplace(arg, "s", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); - if (ch == 'y') - return new Byte(Byte.parseByte(fastReplace(fastReplace(arg, "y", ""), "0b", ""), arg.startsWith("0b") ? 2 : 10)); - return new Integer(Integer.parseInt(fastReplace(fastReplace(arg, "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); - } - catch (NumberFormatException e) - { - if (arg.matches("[0-9.]+")) - try - { - return new Long(Long.parseLong(fastReplace(fastReplace(fastReplace(arg, "l", ""), "0b", ""), "0x", ""), arg.startsWith("0b") ? 2 : arg.startsWith("0x") ? 16 : 10)); - } - catch (NumberFormatException e2) - { - LogProvider.instance.logErr("Number " + arg + " is too big for its datatype! Try to change its datatype to double (suffix D)!", e2); - return null; - } - } + Number num; + if ((num = numberOf(arg, ch0, --len, 10, 0)) != null) + return num; } } return CONTINUE; @@ -174,6 +142,101 @@ public String format(Number num) return num.toString(); } + /** + * @param str | Source char sequence with number to parse. + * @param ch0 | Should be str.charAt(0). This is to ensure that string is not null or empty and also for possible optimizations. + * @param end | Index of where to end with parsing. If whole string is meant to be parsed, then str.length()-1, should not be greater than that! + * @param base | Base of the parsed number. Theoretically can be anything but usually should be 2, 8, 10 or 16... Note that base will be overridden by suffixes #. for 16, 0x for 16, 0b for 2 or 0 for 8 (only if not followed by .). + * @param type | Preferred datatype of of the number represented by suffixes 'S' for {@link Short}, 'Y' for {@link Byte}, 'L' for {@link Long}, 'D' for {@link Double}, 'F' for {@link Float}. Other stands for {@link Integer}.
+ * Note that floating point numberer will be treated as {@link Double} if no suffix is present by default. Also numbers in E-notation format with negative exponents can be converted to {@link Double}. Further more, integers will be auto-converted to {@link Long} if overflow should occur!
+ * Important thing to know is that this argument will be overridden by suffix from str if present! + * + * @return + * + * @since 1.3.7 + */ + public static Number numberOf(CharSequence str, char ch0, int end, int base, int type) //TODO + { + int start = 0; + + if (ch0 == '#') //Determine base + { + base = 16; + start++; + } + else if (ch0 == '0' && end > 0) + { + int ch1 = str.charAt(1) | ' '; + if (ch1 == 'b') + { + base = 2; + start++; + } + else if (ch1 == 'x') + { + base = 16; + start++; + } + else if (ch1 != '.') + base = 8; + + start++; + } + + double result = 0, baseCof = 1, exponent = 1; + int chEnd = str.charAt(end--) | ' '; //Determine data type + if (base == 10 ? chEnd >= 'd' : chEnd >= 'l') + type = chEnd; + else if (chEnd == '.') + type = 'd'; + else + { + result = chEnd > '9' ? chEnd - 'a' + 10 : chEnd - '0'; + baseCof = base; + } + + for (int ch; end >= start; end--) //Parsing + { + if ((ch = str.charAt(end)) == '-') // Neg + result = -result; + else if (ch == '.') //Decimal + { + result /= baseCof; + baseCof = 1; + if (type == 0) + type = 'd'; + } + else if ((ch |= ' ') == 'e' && base == 10) //Handle E-notation + { + if ((exponent = Math.pow(base, result)) < 1 && type == 0) + type = 'd'; + result = 0; + baseCof = 1; + } + else if (ch == ' ') //Not valid + return null; + else if (ch != 127 && ch != '+') + { + result += (ch > '9' ? ch - 'a' + 10 : ch - '0') * baseCof; + baseCof *= base; + } + } + + result *= exponent; + + if (type == 'd') + return result; + if (type == 'f') + return (float) result; + if (type == 'l' || result > 0x7fffffff || result < 0x80000000) + return (long) result; + if (type == 's') + return (short) result; + if (type == 'y') + return (byte) result; + return (int) result; + } + /** * @param num | Number string to format! * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java index 33984bb..d7ae1d7 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java @@ -43,6 +43,17 @@ public class StringConverter implements DataConverter */ public static boolean serializeStringNormally = true; + @Override + public String parse(ParserRegistry myHomeRegistry, String str, Object... args) + { + int len; + if ((len = str.length()) > 1 && str.charAt(0) == '\"' && str.charAt(--len) == '\"' && indexOfNotInObj(str, ' ') == -1) + { + return str.substring(1, len); + } + return CONTINUE; + } + @Override public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) { @@ -67,14 +78,6 @@ else if (serializeStringNormally) return CONTINUE; } - @Override - public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) - { - if (str.length() > 1 && str.charAt(0) == '\"' && str.charAt(str.length()-1) == '\"' && indexOfNotInObj(str, ' ') == -1) - return str.substring(1, str.length() - 1); - return CONTINUE; - } - @Override public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) { From 0552ca3095232e3e98333d2ed9a03bbc958a9cbd Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Thu, 11 Apr 2024 10:40:31 +0200 Subject: [PATCH 22/48] NumConv docs --- .../serialx/converters/NumberConverter.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java index e45762c..f49eafe 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -63,9 +63,29 @@ new Integer(255) 0b1111 new Integer(15) + + 0112 + new Integer(74) + + + 0112 + new Integer(74) + + + 10e2 + new Integer(10e2) + + + 10e2 + new Integer(10e2) + + + .1e2 + new Double(0.1e2) + * - * @see NumberConverter#numberOf(CharSequence, char, int, int) + * @see NumberConverter#numberOf(CharSequence, char, int, int, int) * * @author PETO * @@ -151,7 +171,8 @@ public String format(Number num) * Note that floating point numberer will be treated as {@link Double} if no suffix is present by default. Also numbers in E-notation format with negative exponents can be converted to {@link Double}. Further more, integers will be auto-converted to {@link Long} if overflow should occur!
* Important thing to know is that this argument will be overridden by suffix from str if present! * - * @return + * @return {@link Number} parsed from str with rules specified above. This function was designed to act as more optimized merger of {@link Byte#valueOf(String, int)}, {@link Short#valueOf(String, int)}, {@link Integer#valueOf(String, int)}, {@link Long#valueOf(String, int)} and {@link Float#valueOf(String)}, {@link Double#valueOf(String)} all encapsulated in 1 universal function.
+ * Note: This function will not check for incorrect number formats in order to save performance. Only incorrect format is when inserted string contains space, in this case it will return null! * * @since 1.3.7 */ From ea69c1ac86e27159fb278eaeaaf077088d6a0c28 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 16 Apr 2024 16:42:35 +0200 Subject: [PATCH 23/48] add ability to cache for StringConv --- .../serialx/converters/NumberConverter.java | 2 +- .../serialx/converters/StringConverter.java | 39 ++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java index f49eafe..df92bd9 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -176,7 +176,7 @@ public String format(Number num) * * @since 1.3.7 */ - public static Number numberOf(CharSequence str, char ch0, int end, int base, int type) //TODO + public static Number numberOf(CharSequence str, char ch0, int end, int base, int type) { int start = 0; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java index d7ae1d7..5b2c35c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java @@ -3,6 +3,8 @@ import static org.ugp.serialx.Utils.contains; import static org.ugp.serialx.Utils.indexOfNotInObj; +import java.util.Map; + import org.ugp.serialx.Registry; /** @@ -41,14 +43,24 @@ public class StringConverter implements DataConverter * * @since 1.2.0 (moved to {@link StringConverter} since 1.3.0) */ - public static boolean serializeStringNormally = true; + public static boolean serializeStringNormally = true; //TODO + + protected Map parsingCache; @Override public String parse(ParserRegistry myHomeRegistry, String str, Object... args) { + String result; int len; if ((len = str.length()) > 1 && str.charAt(0) == '\"' && str.charAt(--len) == '\"' && indexOfNotInObj(str, ' ') == -1) { + if (parsingCache != null) + { + if ((result = parsingCache.get(str)) != null) + return result; + parsingCache.put(str, result = str.substring(1, len)); + return result; + } return str.substring(1, len); } return CONTINUE; @@ -90,6 +102,31 @@ public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Ob return ""; } + /** + * @param cache | Instance of {@link Map}, preferably {@link HashMap}, that will be used as cache for parsed strings where keys will be strings with " and values will be string without them. This cache will then be prioritized over creating a new instance of string during parsing, similarly to Java's string pool. Doing this can save you some memory with minimal performance overhead!
+ * Setting this to null will disable the parsing result caching by this {@link StringConverter} as it is by default.
+ * Recommended: Enable this when parsing a lot of strings that are the same, otherwise this will not have a big impact.
+ * Rule of thumb, is that this cache should be modified only by this converter however adding some pre-cached entries is possible but should be performed with caution! + * + * @since 1.3.7 + */ + public void setParsingCache(Map cache) + { + parsingCache = cache; + } + + /** + * @return Instance of {@link Map}, preferably {@link HashMap}, that will be used as cache for parsed strings where keys will be strings with " and values will be string without them. This cache will then be prioritized over creating a new instance of string during parsing, similarly to Java's string pool.
+ * Null will be returned if caching is disabled, which is by default...
+ * Note: Rule of thumb, is that this cache should be modified only by this converter however adding some pre-cached entries is possible but should be performed with caution! + * + * @since 1.3.7 + */ + public Map getParsingCache() + { + return parsingCache; + } + /** * @param obj | Object to stringify directly. * From ef49dcdbd1a8a6670d359f693d9688290be4fa30 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Fri, 26 Apr 2024 15:11:32 +0200 Subject: [PATCH 24/48] moving some juss specifc prots to juss module and fixing some small mistakes --- .../main/java/org/ugp/serialx/juss}/protocols/AutoProtocol.java | 0 .../java/org/ugp/serialx/juss}/protocols/SelfSerializable.java | 0 .../org/ugp/serialx/juss}/protocols/SelfSerializableProtocol.java | 0 .../juss}/protocols/UniversalObjectInstantiationProtocol.java | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename {SerialX-core/src/main/java/org/ugp/serialx => SerialX-juss/src/main/java/org/ugp/serialx/juss}/protocols/AutoProtocol.java (100%) rename {SerialX-core/src/main/java/org/ugp/serialx => SerialX-juss/src/main/java/org/ugp/serialx/juss}/protocols/SelfSerializable.java (100%) rename {SerialX-core/src/main/java/org/ugp/serialx => SerialX-juss/src/main/java/org/ugp/serialx/juss}/protocols/SelfSerializableProtocol.java (100%) rename {SerialX-core/src/main/java/org/ugp/serialx => SerialX-juss/src/main/java/org/ugp/serialx/juss}/protocols/UniversalObjectInstantiationProtocol.java (100%) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java similarity index 100% rename from SerialX-core/src/main/java/org/ugp/serialx/protocols/AutoProtocol.java rename to SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializable.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializable.java similarity index 100% rename from SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializable.java rename to SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializable.java diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializableProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java similarity index 100% rename from SerialX-core/src/main/java/org/ugp/serialx/protocols/SelfSerializableProtocol.java rename to SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java similarity index 100% rename from SerialX-core/src/main/java/org/ugp/serialx/protocols/UniversalObjectInstantiationProtocol.java rename to SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java From 69af2e6ace0000e738ab8442135d225119ff4086 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Fri, 26 Apr 2024 15:12:24 +0200 Subject: [PATCH 25/48] ... --- .../src/main/java/org/ugp/serialx/Serializer.java | 2 +- .../org/ugp/serialx/converters/DataParser.java | 2 +- .../org/ugp/serialx/protocols/EnumProtocol.java | 4 +--- .../serialx/protocols/SerializationProtocol.java | 2 +- .../ugp/serialx/juss/protocols/AutoProtocol.java | 8 +++++--- .../serialx/juss/protocols/SelfSerializable.java | 6 ++---- .../juss/protocols/SelfSerializableProtocol.java | 15 +++++++++++---- .../UniversalObjectInstantiationProtocol.java | 8 +++++--- 8 files changed, 27 insertions(+), 20 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index f677009..5ceb1dc 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -36,7 +36,7 @@ /** * {@link org.ugp.serialx.Serializer} is powerful utility class that allows you to serialize any object in Java using custom data format compiled by recursive descent parser consisting of {@link DataParser}s. - * This class itself is responsible for utility, formating and managing input-output (IO) of content obtained from parsers and protocols as well as their management of their usage! + * This class itself is responsible for formating and managing input-output (IO) of content obtained from parsers and protocols as well as their management of their usage! * It is instance of {@link Scope} so we can say that this is scope that can serialize itself using system of already mentioned {@link DataParser} and {@link SerializationProtocol}! * * @author PETO diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index 7498674..436cc19 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -7,7 +7,7 @@ import org.ugp.serialx.Scope; /** - * This class supposed to be used to parse strings back to java objects using {@link DataParser#parse(String, Object...)}! + * This interface is supposed to be used to parse strings back to java objects using {@link DataParser#parse(String, Object...)}! * Instance of DataParser should be registered into {@link DataParser#REGISTRY} or other external registry in order to work, also only one instance of each DataParser should be used and accessed via this registry!
* Static method {@link DataParser#parseObj} is used to walk this registry and parse inserted string in process, in other words we can say that this interface contains recursive descent parse that uses its own implementations! * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/EnumProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/EnumProtocol.java index f0bba4d..1bf6709 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/EnumProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/EnumProtocol.java @@ -1,9 +1,7 @@ package org.ugp.serialx.protocols; -import java.util.Collection; - /** - * EnumProtocol is universal protocol to serialize any enumerator ({@link Collection} instance). + * EnumProtocol is universal protocol to serialize any enumerator ({@link Enum} instance). * * @author PETO * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java index 13248f3..2b8d50a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java @@ -30,7 +30,7 @@ public abstract class SerializationProtocol * * @since 1.3.0 */ - public static final ProtocolRegistry REGISTRY = new ProtocolRegistry(/*This might be unsafe: new UniversalObjectInstantiationProtocol<>(Object.class),*/ new ListProtocol(), new MapProtocol(), new StringProtocol(), new ScopeProtocol(), new SelfSerializableProtocol(), new EnumProtocol()); + public static final ProtocolRegistry REGISTRY = new ProtocolRegistry(/*This might be unsafe: new UniversalObjectInstantiationProtocol<>(Object.class), new SelfSerializableProtocol(SelfSerializable.class),*/ new ListProtocol(), new MapProtocol(), new StringProtocol(), new ScopeProtocol(), new EnumProtocol()); /** * This mode is for protocols that are used for serialization only! diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java index cb717f7..fc0fd00 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java @@ -1,4 +1,6 @@ -package org.ugp.serialx.protocols; +package org.ugp.serialx.juss.protocols; + +import static org.ugp.serialx.Utils.Instantiate; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; @@ -8,7 +10,7 @@ import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; -import org.ugp.serialx.Utils; +import org.ugp.serialx.protocols.SerializationProtocol; /** * This is automatic protocol that will automatically serialize every or selected field in object that has valid and public getter and setter! @@ -128,7 +130,7 @@ public AutoProtocol(Class applicableFor, boolean useScope, List objectClass) throws Exception { - return Utils.Instantiate(objectClass); + return Instantiate(objectClass); } @Override diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializable.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializable.java index 3c35d90..1619025 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializable.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializable.java @@ -1,9 +1,7 @@ -package org.ugp.serialx.protocols; - -import java.io.Serializable; +package org.ugp.serialx.juss.protocols; /** - * This is based on pretty similar concept as regular {@link Serializable} is! However this interface is meant to create its instance programmatically via constructor! + * This is based on pretty similar concept as regular {@link java.io.Serializable} is! However this interface is meant to create its instance programmatically via constructor! * So condition of using this is that array of objects returned by {@link SelfSerializable#serialize()} must be applicable for some public constructor of certain class implementing this! * Specific instances of this interface will be created by calling that public constructor! This is done reflectively by {@link SelfSerializableProtocol}! * diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java index d4eac0d..efa1aaa 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java @@ -1,4 +1,4 @@ -package org.ugp.serialx.protocols; +package org.ugp.serialx.juss.protocols; /** * SelfSerializableProtocol is universal protocol to serialize any {@link SelfSerializable} instance. The condition of use is implementation of {@link SelfSerializable} interface and public constructor that can be called with content returned by specific {@link SelfSerializable#serialize()}! @@ -11,13 +11,19 @@ */ public class SelfSerializableProtocol extends UniversalObjectInstantiationProtocol { - public SelfSerializableProtocol() + /** + * @param applicableFor | Class implementing {@link SelfSerializable} that can be serialized using this protocol.
+ * Note: Passing {@link SelfSerializable#getClass()} will make this protocol universal and work for any {@link SelfSerializable} instance, this can be considered unsafe in some cases... + * + * @since 1.3.7 + */ + public SelfSerializableProtocol(Class applicableFor) { - super(SelfSerializable.class); + super(applicableFor); } @Override - public Object[] serialize(SelfSerializable object) + public Object[] serialize(SelfSerializable object) { return object.serialize(); } @@ -28,3 +34,4 @@ public byte getMode() return MODE_ALL; } } + \ No newline at end of file diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java index 045401e..a773ea9 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java @@ -1,10 +1,11 @@ -package org.ugp.serialx.protocols; +package org.ugp.serialx.juss.protocols; import java.lang.reflect.Constructor; import java.util.Arrays; import org.ugp.serialx.LogProvider; import org.ugp.serialx.Utils; +import org.ugp.serialx.protocols.SerializationProtocol; /** * Universal protocol for deserializing any object using its constructor. Args array of {@link UniversalObjectInstantiationProtocol#unserialize(Class, Object...)} must have elements applicable as arguments for some constructor of required objects class! @@ -18,14 +19,15 @@ */ public class UniversalObjectInstantiationProtocol extends SerializationProtocol { - protected final Class applicableFor; + protected final Class applicableFor; /** * @param applicableFor | Class that can be serialized using this protocol. + * Note: Passing {@link Object#getClass()} will make this protocol universal and work for any {@link Object} instance, this can be considered unsafe in some cases... * * @since 1.3.7 */ - public UniversalObjectInstantiationProtocol(Class applicableFor) + public UniversalObjectInstantiationProtocol(Class applicableFor) { this.applicableFor = applicableFor; } From fc2b9d1fda39b8c080af4e8cd77a2465338fdb1e Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 30 Apr 2024 14:35:54 +0200 Subject: [PATCH 26/48] removing deprecateds --- .../main/java/org/ugp/serialx/Serializer.java | 275 ------------------ .../ugp/serialx/converters/DataConverter.java | 37 --- .../ugp/serialx/converters/DataParser.java | 76 ----- .../SerializableBase64Converter.java | 14 - .../serialx/juss/protocols/AutoProtocol.java | 26 +- .../operators/ArithmeticOperators.java | 13 - 6 files changed, 2 insertions(+), 439 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 5ceb1dc..1b3c9a0 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -578,281 +578,6 @@ public A SerializeAsSubscope(A source, char[] wrappingBra source = (A) SerializeTo(source.append('\n'), args).append('\n').append(multilpy('\t', tabs)); return (A) source.append(wrappingBrackets[1]); } - - /* - * @param file | File with specific format content. - * @param index | Index of value to get from lowest Scope. - * - * @return Value with index in lowest Scope. Similar to Serializer.LoadFrom(file).get(index) however this function is specifically designed to load only that 1 value witch saves alto of performance! - * But target value can't be using any variables declared outside and also can't be variable invocation itself! Also there might be some problems with commented code! Also there can't be no variables in file! - * - * @since 1.2.5 - * - @Deprecated - public T LoadFrom(File file, int index) - { - try - { - return LoadFrom(new FileReader(file), index); - } - catch (FileNotFoundException e) - { - e.printStackTrace(); - } - return null; - } - - /** - * @param str | Any {@link CharSequence} with specific format content. - * @param index | Index of value to get from lowest Scope. - * - * @return Value with index in lowest Scope. Similar to Serializer.LoadFrom(str).get(index) however this function is specifically designed to load only that 1 value witch saves alto of performance! - * But target value can't be using any variables declared outside and also can't be variable invocation itself! Also there might be some problems with commented code! - * - * @since 1.2.5 - * - @Deprecated - public T LoadFrom(CharSequence str, int index) - { - return LoadFrom(new StringReader(str.toString()), index); - } - - /** - * @param reader | Any {@link Reader} with specific format content. - * @param index | Index of value to get from lowest Scope. - * - * @return Value with index in lowest Scope. Similar to Serializer.LoadFrom(reader).get(index) however this function is specifically designed to load only that 1 value witch saves alto of performance! - * But target value can't be using any variables declared outside and also can't be variable invocation itself! - * - * @since 1.2.5 - * - @Deprecated - @SuppressWarnings("unchecked") - public T LoadFrom(Reader reader, int index) - { - StringBuilder sb = new StringBuilder(); - int semicolon = 0, brackets = 0, quote = 0, vars = 0, multLineCom = -1; - - String line; - try - { - BufferedReader lineReader = new BufferedReader(reader); - while ((line = lineReader.readLine()) != null) - { - if (!contains(line = line.trim(), '=', ':') || !(brackets == 0 && quote % 2 == 0)) - for (int i = 0, com = -1, len = line.length(); i < len; i++) - { - char ch = line.charAt(i); - - if (ch == '/' && i < len-1 && line.charAt(i+1) == '/') - com++; - else if (multLineCom <= -1 && ch == '"') - quote++; - - boolean notInObj = brackets == 0 && quote % 2 == 0; - if (semicolon > index) - { - lineReader.close(); - return (T) DataParser.parseObj(DataParser.REGISTRY, sb.toString(), this); - } - - if (multLineCom > -1 || com > -1) //Is comment - { - if (multLineCom > 0 && ch == '*' && i < len-1 && line.charAt(++i) == '/') - multLineCom = -1; - } - else if (ch == '/' && i < len-1) - { - char chNext = line.charAt(i+1); - if (chNext == '*') - i += multLineCom = 1; - else - sb.append(ch); - } - /*else if (notInObj && ch == '=') - { - vars++; - }* - else if (notInObj && isOneOf(ch, ';', ',')) - { - if (vars > 0) - { - vars = 0; - } - else - semicolon++; - } - else - { - if (ch | ' ') == '{' || ch == '[') - brackets++; - else if (ch == '}' || ch == ']') - { - if (brackets > 0) - brackets--; - else - { - lineReader.close(); - throw new IllegalArgumentException("Missing closing bracket in: " + line); - } - } - - if (vars == 0 && semicolon == index) - sb.append(ch); - } - } - else - { - char lastCh = line.charAt(line.length()-1); - if (isOneOf(lastCh, '{', '[')) - brackets++; - if (isOneOf(lastCh, ';', ',')) - vars++; - } - - } - } - catch (IOException e) - { - e.printStackTrace(); - } - - if (brackets > 0) - throw new IllegalArgumentException("Unclosed brackets!"); - else if (quote % 2 != 0) - throw new IllegalArgumentException("Unclosed or missing quotes!"); - else if (!(line = sb.toString()).isEmpty()) - return (T) DataParser.parseObj(DataParser.REGISTRY, line, this); - LogProvider.instance.logErr("Value with index " + index + " is out of bounds!"); - return null; - } - - /** - * @param file | File with specific format content. - * @param varName | Name of variable to load! - * - * @return Value of variable with varName in lowest Scope. Similar to Serializer.LoadFrom(file).get(varName) however this function is specifically designed to load only that 1 variable witch saves alto of performance! - * But target variable can't be using any variables declared outside! Also there might be some problems with commented code! - * - * @since 1.2.5 - * - @Deprecated - public T LoadFrom(File file, String varName) - { - try - { - return LoadFrom(new FileReader(file), varName); - } - catch (FileNotFoundException e) - { - e.printStackTrace(); - } - return null; - } - - /** - * @param str | Any {@link CharSequence} with specific format content. - * @param varName | Name of variable to load! - * - * @return Value of variable with varName in lowest Scope. Similar to Serializer.LoadFrom(str).get(varName) however this function is specifically designed to load only that 1 variable witch saves alto of performance! - * But target variable can't be using any variables declared outside! Also there might be some problems with commented code! - * - * @since 1.2.5 - * - @Deprecated - public T LoadFrom(CharSequence str, String varName) - { - return LoadFrom(new StringReader(str.toString()), varName); - } - - /** - * @param reader | Any {@link Reader} with specific format content. - * @param varName | Name of variable to load! - * - * @return Value of variable with varName in lowest Scope. Similar to Serializer.LoadFrom(reader).get(varName) however this function is specifically designed to load only that 1 variable witch saves alto of performance! - * But target variable can't be using any variables declared outside! Also there might be some problems with commented code! - * - * @since 1.2.5 - * - @Deprecated - @SuppressWarnings("unchecked") - public T LoadFrom(Reader reader, String varName) - { - StringBuilder sb = new StringBuilder(); - int brackets = 0, quote = 0, multLineCom = -1, fromIndex = 0, fromIndexOrig = 0, findIndex = -1; - - String line; - try - { - BufferedReader lineReader = new BufferedReader(reader); - while ((line = lineReader.readLine()) != null) - { - if (findIndex <= -1 && multLineCom <= -1 && line.length() > varName.length() && !(line.charAt(0) == '/' && isOneOf(line.charAt(1), '/', '*')) && (findIndex = line.indexOf(varName)) > -1) - { - fromIndexOrig = fromIndex = findIndex; - findIndex+=sb.length(); - } - - for (int com = -1, len = line.length(); fromIndex < len; fromIndex++) - { - char ch = line.charAt(fromIndex); - - if (ch == '/' && fromIndex < len-1 && line.charAt(fromIndex+1) == '/') - com++; - else if (multLineCom <= -1 && ch == '"') - quote++; - - if (findIndex > -1 && quote % 2 == 0 && brackets == 0 && isOneOf(ch, ';', ',')) - { - lineReader.close(); - int start = sb.indexOf("=", findIndex-fromIndexOrig); - if (start <= -1) - start = sb.indexOf(":", findIndex-fromIndexOrig); - return (T) DataParser.parseObj(DataParser.REGISTRY, sb.substring(start+1), this); - } - - if (multLineCom > -1 || com > -1) //Is comment - { - if (multLineCom > 0 && ch == '*' && fromIndex < len-1 && line.charAt(++fromIndex) == '/') - multLineCom = -1; - } - else if (ch == '/' && fromIndex < len-1) - { - char chNext = line.charAt(fromIndex+1); - if (chNext == '*') - fromIndex = multLineCom = 1; - else - sb.append(ch); - } - else - { - if (ch | ' ') == '{' || ch == '[') - brackets++; - else if (ch == '}' || ch == ']') - { - if (brackets > 0) - brackets--; - else - { - lineReader.close(); - throw new IllegalArgumentException("Missing closing bracket in: " + line); - } - } - - sb.append(ch); - } - } - fromIndex = 0; - } - } - catch (IOException e) - { - e.printStackTrace(); - } - - LogProvider.instance.logErr("Variable " + varName + " was not found!"); - return null; - }*/ /** * @param indexWithStringValue | Index of independent value that should be string. diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java index c6fadf4..2c157f5 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java @@ -54,43 +54,6 @@ public static CharSequence objToString(Object obj, Object... args) return REGISTRY.toString(obj, args); } - /** - * @deprecated Use {@link ParserRegistry#toString(Object, Object...)}! - * - * @param registry | Registry to use! - * @param obj | Object to convert into string! - * @param args | Additional arguments that will be obtained in {@link DataParser#toString(String, Object...)}! - * - * @return Object converted to string using {@link DataConverter} suitable converter picked from registry! - * {@link DataConverter#toString(Object, Object...)} of all registered converters will be called however only suitable ones should return the result, others should return {@link DataParser#CONTINUE}! - * - * @since 1.3.0 - */ - @Deprecated - public static CharSequence objToString(Registry registry, Object obj, Object... args) - { - if (registry instanceof ParserRegistry) - return ((ParserRegistry) registry).toString(obj, args); - return objToString(new ParserRegistry(registry), obj, args); - } - - /** - * @deprecated Use {@link ParserRegistry#getConverterFor(Object, Object...)}! - * - * @param registry | Registry to use! - * @param obj | Object to find converter for! - * @param args | Additional arguments that will be obtained in {@link DataParser#toString(String, Object...)}! - * - * @return Converter suitable for converting required obj to string, selected from registry! - */ - @Deprecated - public static DataConverter getConverterFor(Registry registry, Object obj, Object... args) - { - if (registry instanceof ParserRegistry) - return ((ParserRegistry) registry).getConverterFor(obj, args); - return getConverterFor(new ParserRegistry(registry), obj, args); - } - /** * @return "Object of " + objToDescribe.getClass().getName() + ": \"" + objToDescribe + "\" converted by " + DataParser.class.getName() * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index 436cc19..828e550 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -68,82 +68,6 @@ public static Object parseObj(String str, Object... args) return REGISTRY.parse(str, args); } - /** - * @deprecated Use {@link ParserRegistry#parse(String, Object...)}! - * - * @param registry | Registry to use! - * @param str | Source string to parse using suitable parser from registry. - * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! - * - * @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! You can return {@link DataParser#CONTINUE} to mark parser as not suitable for parsing obtained string. - * If no suitable result was found, null will be returned and you will be notified in console (null does not necessary means invalid output since null can be proper result of parsing)! - * - * @since 1.3.0 - */ - @Deprecated - public static Object parseObj(Registry registry, String str, Object... args) - { - return parseObj(registry, str, false, null, args); - } - - /** - * @deprecated Use {@link ParserRegistry#parse(String, boolean, Class[], Object...)}! - * - * @param registry | Registry to use! - * @param str | Source string to parse using suitable parser from registry. - * @param returnAsStringIfNotFound | If true, inserted string will be returned instead of null and error message! - * @param ignore | {@link DataParser} class to ignore! - * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! - * - * @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! You can return {@link DataParser#CONTINUE} to mark parser as not suitable for parsing obtained string. - * If no suitable result was found, null or inserted string will be returned based on returnAsStringIfNotFound! - * - * @since 1.3.0 - */ - @Deprecated - public static Object parseObj(Registry registry, String str, boolean returnAsStringIfNotFound, Class[] ignore, Object... args) - { - if (registry instanceof ParserRegistry) - return ((ParserRegistry) registry).parse(str, returnAsStringIfNotFound, ignore, args); - return parseObj(new ParserRegistry(registry), str, returnAsStringIfNotFound, ignore, args); - } - - /** - * @deprecated Use {@link DataParser.REGISTRY#getParserFor(String, Object...)}! - * - * @param registry | Registry to search! - * @param str | String to find parser for! - * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! - * - * @return Parser suitable for parsing required string, selected from {@link DataParser#REGISTRY}! - * - * @since 1.3.0 - */ - @Deprecated - public static DataParser getParserFor(String str, Object... args) - { - return getParserFor(REGISTRY, str, args); - } - - /** - * @deprecated Use {@link DataParser#getParserFor(String, Object...)}! - * - * @param registry | Registry to search! - * @param str | String to find parser for! - * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! - * - * @return Parser suitable for parsing required string, selected from inserted registry! - * - * @since 1.3.0 - */ - @Deprecated - public static DataParser getParserFor(Registry registry, String str, Object... args) - { - if (registry instanceof ParserRegistry) - return ((ParserRegistry) registry).getParserFor(str, args); - return getParserFor(new ParserRegistry(registry), str, args); - } - /** * Registry to store {@link DataParser} and {@link DataConverter} and performing parsing (String -> Object) and converting (Object -> String) operations with them! * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/SerializableBase64Converter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/SerializableBase64Converter.java index b2bb26a..4d8dce4 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/SerializableBase64Converter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/SerializableBase64Converter.java @@ -48,20 +48,6 @@ new ArrayList() */ public class SerializableBase64Converter implements DataConverter { - /** - * @deprecated DO NOT USE, IT WILL TAKE NOTE EFFECT! USE {@link ObjectConverter#setUseBase64IfCan(boolean)}! - * - * Set this on true to force program to use SerializationProtocol also on java.io.Serializable objects. - * Doing this also might take less memory space then using classic java.io.Serializable. - * In some cases, java Serialization can be more effective than protocols sometimes not! You should try which gives you the best result, then you can also deactivate certain protocols that are less effective than Java serialization. - * For example for long strings, classic Java serialization is better than protocol, it will take less memory storage space, but performance is almost always far slower!
- * Note: Whole concept of SerialX API is about avoiding classic Java serialization from many reasons so you most likely want this on true! Also protocol will be almost certainly faster classic serialization! - * - * @since 1.0.0 (moved to {@link SerializableBase64Converter} since 1.3.0) - */ - @Deprecated - public static boolean useProtocolIfCan = true; - @Override public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) { diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java index fc0fd00..1f869ed 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java @@ -173,15 +173,13 @@ public T unserialize(Class objectClass, Object... args) throws Exce } /** - * @deprecated DO NOT USE! - * * @param variableName | Name of variable! * - * @return PropertyDescriptor of variable with name or null if this protocols can't use it! + * @return PropertyDescriptor of variable with name or null if this protocols can't serialize variable with given name!
+ * Note: I would recommend to tread this as read only and not set anything that you are not sure of. This will ensure correct functionality... * * @since 1.3.2 */ - @Deprecated public PropertyDescriptor getfieldDescriptorsDescriptor(String variableName) { for (PropertyDescriptor var : fieldDescriptors) @@ -215,24 +213,4 @@ public void setUseScope(boolean useScope) { this.useScope = useScope; } - - /** - * DEPRECATED: DO NOT USE! USE {@link Scope#getPropertyDescriptorsOf(Class, String...)} instead! - * - * @param cls | Class to inspect! - * @param fieldNames | Names of fields to get descriptors for, if this array is empty or null, descriptors for all fields with public getters and setters will be obtained! - * - * @return List of {@link PropertyDescriptor}s of cls representing access methods of required fields! Only descriptors of fields that have valid and public getter and setter will be returned! - * - * @throws IntrospectionException when there are no fields with valid and public getters and setters. - * - * @see PropertyDescriptor - * - * @since 1.3.2 - */ - @Deprecated - public static List getPropertyDescriptorsOf(Class cls, String... fieldNames) throws IntrospectionException - { - return Scope.getPropertyDescriptorsOf(cls, fieldNames); - } } diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java index c05f137..c55cbf1 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -456,19 +456,6 @@ else if (obj instanceof Character) return obj; } - /** - * DEPRECATED: Use {@link String#valueOf(Object)} instead, this function is duplicate functionality rendering it unnecessary. - * - * @return "null" if null and else obj.toString(); - * - * @since 1.3.0 - */ - @Deprecated - public static String toString(Object obj) - { - return obj == null ? "null" : obj.toString(); - } - /** * Used internally by {@link ArithmeticOperators} to wrap result of evaluation! * Mainly used by String results! From 211bae29432cc9dea86e5ad34ce119f014a7418f Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sat, 11 May 2024 23:35:50 +0200 Subject: [PATCH 27/48] testing, fixing, jdocking, finilizing --- .../main/java/org/ugp/serialx/Serializer.java | 2 +- .../src/main/java/org/ugp/serialx/Utils.java | 78 +++++++++---------- .../serialx/converters/NumberConverter.java | 3 + .../serialx/converters/StringConverter.java | 22 +++++- .../ugp/serialx/protocols/ListProtocol.java | 4 +- .../converters/JsonCharacterConverter.java | 39 ++++++++-- .../json/converters/JsonNumberConverter.java | 11 ++- .../juss/converters/OperationGroups.java | 2 +- .../juss/converters/VariableConverter.java | 48 +++++++----- .../operators/ArithmeticOperators.java | 2 +- 10 files changed, 136 insertions(+), 75 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 1b3c9a0..3dcd9e9 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -534,7 +534,7 @@ public Object apply(Object t) if (t instanceof Serializer) { GenericScope srl = ((Scope) t).transform(this); - return new GenericScope<>(srl.variables(), srl.values(), srl.getParent()); + return new Scope(srl.variables(), srl.values(), srl.getParent()); } return t; } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index 75326ee..ef21e16 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -223,14 +223,14 @@ public static T Clone(T obj) /** * @param obj | Object to clone. - * @param + * @param parsersToUse | Parsers that will be used for cloning... * @param converterArgs | Argument for {@link DataConverter#objToString(Registry, Object, Object...)}! * @param parserArgs | Arguments for {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)}! * * @return Cloned object using {@link DataParser}, {@link DataConverter} and {@link SerializationProtocol} or the same object as inserted one if cloning is not possible, for instance when protocol was not found and object is not instance of {@link Cloneable}. * This clone function will always prioritized the Protocol variation, regular cloning is used only when there is no protocol registered or exception occurs.
* Note: If there are protocols to serialize inserted object and all its sub-objects and variables then this clone will be absolute deep copy, meaning that making any changes to this cloned object or to its variables will not affect original one in any way! - * But keep in mind that this clone is absolute hoverer, based on protocols used, it does not need to be an 100% copy! + * But keep in mind that this clone is absolute hoverer, based on protocols used, it does not need to be an 100% copy! Also note that certain objects such as primitive wrappers ({@link Integer}, {@link Float} etc...) will not be necessarily cloned since cloning them is not reasonable... * * @since 1.3.2 */ @@ -238,49 +238,47 @@ public static T Clone(T obj) public static T Clone(T obj, Registry parsersToUse, Object[] converterArgs, Object... parserArgs) { if (obj == null) - return obj; - else if (obj.getClass() == Byte.class) - return (T) new Byte((byte) obj); - else if (obj.getClass() == Short.class) - return (T) new Short((short) obj); - else if (obj.getClass() == Integer.class) - return (T) new Integer((int) obj); - else if (obj.getClass() == Long.class) - return (T) new Long((long) obj); - else if (obj.getClass() == Float.class) - return (T) new Float((float) obj); - else if (obj.getClass() == Double.class) - return (T) new Double((double) obj); - else if (obj.getClass() == Character.class) - return (T) new Character((char) obj); - else if (obj.getClass() == Boolean.class) - return (T) new Boolean((boolean) obj); - else if (obj.getClass() == String.class) + return null; + if (obj.getClass() == Byte.class) + return (T) (Byte) ((byte) obj); // valueOf call... + if (obj.getClass() == Short.class) + return (T) (Short) ((short) obj); + if (obj.getClass() == Integer.class) + return (T) (Integer) ((int) obj); + if (obj.getClass() == Long.class) + return (T) (Long) ((long) obj); + if (obj.getClass() == Float.class) + return (T) (Float) ((float) obj); + if (obj.getClass() == Double.class) + return (T) (Double) ((double) obj); + if (obj.getClass() == Character.class) + return (T) (Character) ((char) obj); + if (obj.getClass() == Boolean.class) + return (T) (Boolean) ((boolean) obj); + if (obj.getClass() == String.class) return (T) new String((String) obj); - else + + ParserRegistry parsers = parsersToUse instanceof ParserRegistry ? (ParserRegistry) parsersToUse : new ParserRegistry(parsersToUse); + + Object cln = parsers.parse(parsers.toString(obj, converterArgs).toString(), parserArgs); + if (cln != null && cln != VOID) + return (T) cln; + + if (obj instanceof Cloneable) { - ParserRegistry parsers = parsersToUse instanceof ParserRegistry ? (ParserRegistry) parsersToUse : new ParserRegistry(parsersToUse); - - Object cln = parsers.parse(parsers.toString(obj, converterArgs).toString(), parserArgs); - if (cln != null && cln != VOID) - return (T) cln; - - if (obj instanceof Cloneable) + try { - try - { - Method method = Object.class.getDeclaredMethod("clone"); - method.setAccessible(true); - return (T) method.invoke(obj); - } - catch (Exception e) - { - throw new RuntimeException(e); - } + Method method = Object.class.getDeclaredMethod("clone"); + method.setAccessible(true); + return (T) method.invoke(obj); + } + catch (Exception e) + { + throw new RuntimeException(e); } - LogProvider.instance.logErr("Unable to clone " + obj.getClass() + ": " + obj, null); - return obj; } + LogProvider.instance.logErr("Unable to clone " + obj.getClass() + ": " + obj, null); + return obj; } /** diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java index df92bd9..4f3fa34 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -259,12 +259,15 @@ else if (ch != 127 && ch != '+') } /** + * @deprecated THIS IS NO LONGER NECESSARY BECAUSE BECAUSE {@link NumberConverter#numberOf(CharSequence, char, int, int, int)} CAN DO THE SAME THING MUCH FASTET! + * * @param num | Number string to format! * * @return Original string with formated sign and deleted '_'! * * @since 1.3.0 */ + @Deprecated public static String normFormatNum(String num) { if (num.length() > 2) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java index 5b2c35c..1314103 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java @@ -43,7 +43,7 @@ public class StringConverter implements DataConverter * * @since 1.2.0 (moved to {@link StringConverter} since 1.3.0) */ - public static boolean serializeStringNormally = true; //TODO + protected boolean serializeStringNormally = true; protected Map parsingCache; @@ -127,6 +127,26 @@ public Map getParsingCache() return parsingCache; } + /** + * @return Will return value of {@link StringConverter#serializeStringNormally}! + * + * @since 1.3.7 (it was static before = not good) + */ + public boolean isSerializeStringNormally() + { + return serializeStringNormally; + } + + /** + * @param serializeStringNormally | Set value of {@link StringConverter#serializeStringNormally}! + * + * @since 1.3.7 (it was static before = not good) + */ + public void setSerializeStringNormally(boolean serializeStringNormally) + { + this.serializeStringNormally = serializeStringNormally; + } + /** * @param obj | Object to stringify directly. * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/ListProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/ListProtocol.java index d2d99a8..f300466 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/ListProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/ListProtocol.java @@ -11,7 +11,7 @@ * * @since 1.0.0 and applicable for {@link Collection} since 1.2.2 */ -public class ListProtocol extends SerializationProtocol> +public class ListProtocol extends SerializationProtocol> { @Override public Object[] serialize(Collection obj) @@ -24,7 +24,7 @@ public Collection unserialize(Class> objectClass, Obj { if (objectClass.isInterface()) return new ArrayList<>(Arrays.asList(args)); - + try { return objectClass.getConstructor(Collection.class).newInstance(Arrays.asList(args)); diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java index 0850e25..d9fc561 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java @@ -2,27 +2,52 @@ import org.ugp.serialx.converters.CharacterConverter; -public class JsonCharacterConverter extends CharacterConverter { - +/** + * {@link CharacterConverter} modified to match JSON more closely. It will serialize char as {@link String} since JSON does not know char... + * + * @author PETO + * + * @since 1.3.7 + */ +public class JsonCharacterConverter extends CharacterConverter +{ protected boolean formatAsString; - public JsonCharacterConverter(boolean formatAsString) { - setFormatAsString(formatAsString); + /** + * @param formatAsString | If true, character will be serialized in a letter form. Otherwise it will be serialized as ASCII value (int). + * + * @since 1.3.7 + */ + public JsonCharacterConverter(boolean formatAsString) + { + setFormatAsString(formatAsString); } @Override public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) { if (obj instanceof Character) - return isFormatAsString() ? obj.toString() : String.valueOf((int) (char) obj); + return isFormatAsString() ? "\""+obj+"\"" : String.valueOf((int) (char) obj); return CONTINUE; } - public boolean isFormatAsString() { + /** + * @return True if character is going to be serialized in a letter form. If false, it will be serialized as ASCII value (int). + * + * @since 1.3.7 + */ + public boolean isFormatAsString() + { return formatAsString; } - public void setFormatAsString(boolean formatAsString) { + /** + * @param formatAsString | If true, character will be serialized in a letter form. Otherwise it will be serialized as ASCII value (int). + * + * @since 1.3.7 + */ + public void setFormatAsString(boolean formatAsString) + { this.formatAsString = formatAsString; } } diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java index 1aaec5b..0f2e76e 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java @@ -2,8 +2,15 @@ import org.ugp.serialx.converters.NumberConverter; -public class JsonNumberConverter extends NumberConverter { - +/** + * {@link NumberConverter} modified to match JSON more closely. It will not use Juss number suffixes since JSON does not support them... + * + * @author PETO + * + * @since 1.3.7 + */ +public class JsonNumberConverter extends NumberConverter +{ @Override public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) { diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java index 005603d..9315151 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java @@ -52,7 +52,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) args[2] = runtimeGroupStack; } String mark = GROUP_MARK_OP + runtimeGroupStack.size() + GROUP_MARK_CLS; - runtimeGroupStack.put(mark, str.substring(opIndex+1, clsIndex)); + runtimeGroupStack.put(mark, str.substring(opIndex+1, clsIndex).trim()); StringBuilder sb = new StringBuilder(str).replace(opIndex, clsIndex+1, mark); return myHomeRegistry.parse(sb.toString(), args); diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index c3f57f5..a18a471 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -81,32 +81,40 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) eachVar: for (int i = 0; i < iVal; i++) // Support for assigning multiple vars to the same value... Yea this is not the prettiest code but it does the job and mainly it does it fast so shut up! { String var = vars[i]; - if (!genericVar && contains(var, ' ')) - LogProvider.instance.logErr("Variable name \"" + var + "\" is invalid, blank characters are not allowed!", null); - else if ((op0Index = var.indexOf('.')) > -1) + if (!genericVar) { - String[] path = splitValues(var, op0Index, 0, 0, new char[0], '.'); - int iLast = path.length-1, j = 0; - - backlook: do + if (contains(var, ' ')) { - Object sc; - if ((sc = getMemberOperator(scope, path[0])) != VOID) // Attempt to get only when exists... + LogProvider.instance.logErr("Variable name \"" + var + "\" is invalid, blank characters are not allowed!", null); + continue; + } + + if ((op0Index = var.indexOf('.')) > -1) + { + String[] path = splitValues(var, op0Index, 0, 0, new char[0], '.'); + int iLast = path.length-1, j = 0; + + backlook: do { - for (j = 1; j < iLast; j++) // Subscope/forward lookup (inner path only)... - if ((sc = getMemberOperator(sc, path[j])) == null || sc == VOID) - break backlook; - - setMemberOperator(myHomeRegistry, sc, path[iLast], val, genericVar, args); - continue eachVar; + Object sc; + if ((sc = getMemberOperator(scope, path[0])) != VOID) // Attempt to get only when exists... + { + for (j = 1; j < iLast; j++) // Subscope/forward lookup (inner path only)... + if ((sc = getMemberOperator(sc, path[j])) == null || sc == VOID) + break backlook; + + setMemberOperator(myHomeRegistry, sc, path[iLast], val, false, args); + continue eachVar; + } } + while ((scope = scope.getParent()) != null); + + LogProvider.instance.logErr("Path \"" + var + "\" cannot be set to \"" + val + "\" because \"" + path[j] + "\" is not a accessible or does not exist!", null); + continue; } - while ((scope = scope.getParent()) != null); - - LogProvider.instance.logErr("Path \"" + var + "\" cannot be set to \"" + val + "\" because \"" + path[j] + "\" is not a accessible or does not exist!", null); } - else - setMemberOperator(myHomeRegistry, scope, var, val, genericVar, args); + + setMemberOperator(myHomeRegistry, scope, var, val, genericVar, args); } return getValueModif ? val : VOID; diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java index c55cbf1..0837750 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -335,7 +335,7 @@ else if (pow <= Float.MAX_VALUE && pow >= Float.MIN_VALUE && (cof instanceof Flo else if (cof instanceof Integer || cof2 instanceof Integer) return (int) pow; } - return null; + return null; } /** From 39fdb1f202eb143fe68a71767fb7e79b17cd6dcd Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Fri, 28 Jun 2024 23:16:12 +0200 Subject: [PATCH 28/48] Adding/improving some docs, fixing some bugs (CharConv...), Improving SerializationDebuger (OUT, it shows exceptions...), Improving LogProvider, Refactoring/improivng operators, Logical, Comparasional, adding numeric and logical negation... ConditionalAsigment. Improving some other things... --- .../java/org/ugp/serialx/LogProvider.java | 4 +- .../src/main/java/org/ugp/serialx/Utils.java | 29 ++-- .../serialx/converters/BooleanConverter.java | 17 ++- .../converters/CharacterConverter.java | 2 +- .../ugp/serialx/converters/DataConverter.java | 2 +- .../ugp/serialx/converters/DataParser.java | 8 +- .../serialx/converters/NumberConverter.java | 2 +- .../{converters => }/DebugParserRegistry.java | 47 ++++--- .../devtools/SerializationDebugger.java | 109 +++++++++------ .../org/ugp/serialx/json/JsonSerializer.java | 2 +- .../org/ugp/serialx/juss/JussSerializer.java | 2 +- .../operators/ArithmeticOperators.java | 46 ++++--- .../operators/ComparisonOperators.java | 53 ++++---- .../ConditionalAssignmentOperators.java | 35 +++-- .../operators/LogicalOperators.java | 127 +++++++----------- .../operators/NegationOperator.java | 24 +++- 16 files changed, 279 insertions(+), 230 deletions(-) rename SerialX-devtools/src/main/java/org/ugp/serialx/devtools/{converters => }/DebugParserRegistry.java (79%) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java b/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java index f9eadae..b68d533 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/LogProvider.java @@ -36,8 +36,8 @@ public void logErr(Object obj, Throwable ex) { if (reThrowException) { - if (ex == null) - throw new RuntimeException(obj.toString()); + if (ex == null || ex.getMessage() == null || ex.getMessage().isEmpty()) + throw new RuntimeException(String.valueOf(obj)); throw new RuntimeException(ex); } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index ef21e16..43dd25c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -590,30 +590,32 @@ else if (quote % 2 != 0) * @param s | CharSequence to search! * @param oneOf | Characters to find! * - * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}', otherwise -1! + * @return Index of first character found that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}', otherwise -1! * * @since 1.3.0 */ public static int indexOfNotInObj(CharSequence s, char... oneOf) { - return indexOfNotInObj(s, true, oneOf); + return indexOfNotInObj(s, 0, s.length(), true, oneOf); } /** * @param s | CharSequence to search! + * @param from | The beginning index, where to start the search (should be 0 in most cases). + * @param to | Ending index of search (exclusive, should be s.length()). * @param firstIndex | If true, first index will be returned, if false last index will be returned. * @param oneOf | Characters to find! * - * @return Index of first found character that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}', otherwise -1! + * @return Index of first character found that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}', otherwise -1! * * @since 1.3.5 */ - public static int indexOfNotInObj(CharSequence s, boolean firstIndex, char... oneOf) + public static int indexOfNotInObj(CharSequence s, int from, int to, boolean firstIndex, char... oneOf) { - int found = -1; - for (int i = 0, brackets = 0, quote = 0, len = s.length(); i < len; i++) + int index = -1; + for (int brackets = 0, quote = 0; from < to; from++) { - char ch = s.charAt(i); + char ch = s.charAt(from); if (ch == '"') quote++; @@ -621,9 +623,9 @@ public static int indexOfNotInObj(CharSequence s, boolean firstIndex, char... on { if (brackets == 0 && /*oneOf.length == 0 ? ch == oneOf[0] :*/ isOneOf(ch, oneOf)) { - found = i; if (firstIndex) - return found; + return from; + index = from; } else if ((ch | ' ') == '{') brackets++; @@ -636,7 +638,7 @@ else if ((ch | ' ') == '}') } } } - return found; + return index; } /** @@ -663,8 +665,11 @@ public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind) */ public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind, boolean firstIndex) { + int len = s.length(), lenToFind = sequenceToFind.length(); + if (len < lenToFind) + return -1; int found = -1; - for (int i = 0, brackets = 0, quote = 0, match = 0, len = s.length(), lenToFind = sequenceToFind.length(); i < len; i++) + for (int i = 0, brackets = 0, quote = 0, match = 0; i < len; i++) { char ch = s.charAt(i); if (ch == '"') @@ -885,7 +890,7 @@ public static void post(Serializer serializer, HttpURLConnection conn) throws IO for (Object param : serializer) { - if (postData.length() != 0) + if (postData.length() != 0) postData.append('&'); postData.append(URLEncoder.encode(serializer.getParsers().toString(param).toString(), "UTF-8")); } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java index bc5e442..ffc07a6 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/BooleanConverter.java @@ -44,13 +44,18 @@ */ public class BooleanConverter implements DataConverter { - public boolean shorten; + protected boolean shorten; public BooleanConverter() { this(true); } + /** + * @param shorten | If true, shortened format (T/F) will be serialized. If false, true/false will be serialized... + * + * @since 1.3.5 + */ public BooleanConverter(boolean shorten) { setShorten(shorten); @@ -84,11 +89,21 @@ public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Ob return new StringBuilder().append("Primitive data type: \"").append(obj).append("\" the ").append(obj.getClass().getSimpleName().toLowerCase()).append(" value!"); } + /** + * @return If true, shortened format (T/F) will be serialized. If false, true/false will be serialized... + * + * @since 1.3.5 + */ public boolean isShorten() { return shorten; } + /** + * @param shorten | If true, shortened format (T/F) will be serialized. If false, true/false will be serialized... + * + * @since 1.3.5 + */ public void setShorten(boolean shorten) { this.shorten = shorten; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java index d8c276e..624a560 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/CharacterConverter.java @@ -46,7 +46,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) } catch (Exception e) { - return str.charAt(0); + return str.charAt(1); } return CONTINUE; } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java index 2c157f5..6c11480 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java @@ -31,7 +31,7 @@ public interface DataConverter extends DataParser * @param objToDescribe | Object to generate description for! * @param argsUsedConvert | Array of arguments that were used for converting described object! * - * @return Description for object (should not contains endlines)! + * @return Description for object (should not contain endlines)! * * @since 1.3.0 */ diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index 828e550..ce57623 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -247,7 +247,9 @@ public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ign /** * @param classOfParserToPrecache | Class of parser to precache! * - * @return Int array of 2 signifying the index of where the parser was inserted in parsing cache and converting cache (index 0 = parsing cache index, index 1 = converting cache index) + * @return Int array of 2 signifying the index of where the parser was inserted in parsing cache and converting cache (index 0 = parsing cache index, index 1 = converting cache index). These 2 values should be the same. + * + * @since 1.3.5 */ public int[] preCache(Class classOfParserToPrecache) { @@ -303,8 +305,8 @@ public void resetCache() /** * You can use this to manually set caching arrays. Doing this might give you a solid performance boost when parsing or converting large amount of objects with this registry! But sometimes, this might cause some unexpected behavior especially when you have multiple parsers that are dependent on each other! * - * @param parsingCache | Array of specific parsing cache to use (it can contains some preached parsers to use preferably). This array is supposed to be as long as this registry! - * @param convertingCache | Array of specific converter cache to use (it can contains some preached converters to use preferably). This array is supposed to be as long as this registry! + * @param parsingCache | Array of specific parsing cache to use (it can contains some preached parsers to use preferably). This array is supposed to be as long as this registry and instances and their indexes (order) in cache should be same as in this registry! + * @param convertingCache | Array of specific converter cache to use (it can contains some preached converters to use preferably). This array is supposed to be as long as this registry and instances and their indexes (order) in cache should be same as in this registry! * * @since 1.3.5 */ diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java index 4f3fa34..10631eb 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -259,7 +259,7 @@ else if (ch != 127 && ch != '+') } /** - * @deprecated THIS IS NO LONGER NECESSARY BECAUSE BECAUSE {@link NumberConverter#numberOf(CharSequence, char, int, int, int)} CAN DO THE SAME THING MUCH FASTET! + * @deprecated THIS IS OBSOLET, SLOW AND NO LONGER NECESSARY BECAUSE {@link NumberConverter#numberOf(CharSequence, char, int, int, int)} CAN DO THE SAME THING MUCH FASTET! * * @param num | Number string to format! * diff --git a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java similarity index 79% rename from SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java rename to SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java index bc300ca..3bead58 100644 --- a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/converters/DebugParserRegistry.java +++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java @@ -1,4 +1,4 @@ -package org.ugp.serialx.devtools.converters; +package org.ugp.serialx.devtools; import java.util.Map; import java.util.TreeMap; @@ -7,7 +7,6 @@ import org.ugp.serialx.converters.DataConverter; import org.ugp.serialx.converters.DataParser; import org.ugp.serialx.converters.DataParser.ParserRegistry; -import org.ugp.serialx.devtools.SerializationDebugger; /** * Special {@link ParserRegistry} that keeps track of its actions! Use only for debugging! @@ -115,13 +114,21 @@ public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ign DataParser parser = parsingCache[i]; if (parser != null) { - double t0 = System.nanoTime(); - obj = parser.parse(this, str, args); - double t = System.nanoTime(); - if (obj != SerializationDebugger.CONTINUE) + try { - iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms (from cache)\n>>\t\"" + str + "\"\t -->\t" + SerializationDebugger.toStringAndCls(obj)); - return obj; + double t0 = System.nanoTime(); + obj = parser.parse(this, str, args); + double t = System.nanoTime(); + if (obj != SerializationDebugger.CONTINUE) + { + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms (from cache)\n>>\t\"" + str + "\"\t -->\t" + SerializationDebugger.toStringAndCls(obj)); + return obj; + } + } + catch (Exception ex) + { + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " (from cache)\n>>\t\"" + str + "\"\tthrew\t" + ex); + return null; } } } @@ -134,15 +141,23 @@ public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ign if (cls == parser.getClass()) continue registryLoop; - double t0 = System.nanoTime(); - obj = parser.parse(this, str, args); - double t = System.nanoTime(); - if (obj != SerializationDebugger.CONTINUE) + try + { + double t0 = System.nanoTime(); + obj = parser.parse(this, str, args); + double t = System.nanoTime(); + if (obj != SerializationDebugger.CONTINUE) + { + if (parsingCache != null && i < parsingCache.length) + parsingCache[i] = parser; + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms\n>>\t\"" + str + "\"\t -->\t" + SerializationDebugger.toStringAndCls(obj)); + return obj; + } + } + catch (Exception ex) { - if (parsingCache != null && i < parsingCache.length) - parsingCache[i] = parser; - iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " " + (t-t0)/1000000 + "ms\n>>\t\"" + str + "\"\t -->\t" + SerializationDebugger.toStringAndCls(obj)); - return obj; + iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + "\n>>\t\"" + str + "\"\tthrew\t" + ex); + return null; } } diff --git a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java index 0476abd..bcbc5c4 100644 --- a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java +++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java @@ -2,6 +2,7 @@ import static org.ugp.serialx.Utils.multilpy; +import java.io.PrintWriter; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -10,13 +11,15 @@ import org.ugp.serialx.Registry; import org.ugp.serialx.Serializer; import org.ugp.serialx.converters.DataConverter; -import org.ugp.serialx.devtools.converters.DebugParserRegistry; +import org.ugp.serialx.converters.DataParser; /** * Use this for debugging during parsing and converting by adding new instance of it into your parser {@link Registry} or in case of {@link Serializer} use !
* During parsing, type __debug or __debug_yourObject into your code!
* During converting/serializing, serialize your object using {@link DebugWrapper} with your object as argument! * + * @see SerializationDebugger#debug(Serializer) + * * @author PETO * * @since 1.3.5 @@ -25,6 +28,14 @@ public class SerializationDebugger implements DataConverter { public static final String DEBUG_MARK = new String("__debug"); + /** + * Output object that will be used for logging... + * If null, it will be set automatically! + * + * @since 1.3.7 + */ + public static PrintWriter out; + @Override public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { @@ -50,17 +61,20 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object.. */ public Object printDebugs(DebugParserRegistry myHomeRegistry, Object objToSerialize, String strToParse, Object... args) { + if (out == null) + out = new PrintWriter(System.err); + String action = objToSerialize == null && strToParse != null ? "Parsing" : "Converting"; - System.err.println("--------------------------------------------- " + action + " Debug ---------------------------------------------"); + out.println("--------------------------------------------- " + action + " Debug ---------------------------------------------"); if (args == null) - System.err.println("------- Available args (args): none (args = null)!"); + out.println("------- Available args (args): none (args = null)!"); else - print("------- Available args (args):", Arrays.asList(args), 0); + print(out, "------- Available args (args):", Arrays.asList(args), 0); if (myHomeRegistry == null) - System.err.println("\n------- Available parsers (myHomeRegistry: null): none!"); + out.println("\n------- Available parsers (myHomeRegistry: null): none!"); else - print("\n------- Available parsers (myHomeRegistry: " + myHomeRegistry.getClass().getName() + "):", myHomeRegistry, 0); + print(out, "\n------- Available parsers (myHomeRegistry: " + myHomeRegistry.getClass().getName() + "):", myHomeRegistry, 0); if (strToParse != null && (strToParse = strToParse.substring(DEBUG_MARK.length())).length() > 0 && (strToParse = strToParse.substring(1)).length() > 0) { @@ -79,14 +93,13 @@ else if (args[99] instanceof Integer && (int) args[99] > 0) objToSerialize = myHomeRegistry.parse(strToParse, args); double t = System.nanoTime(); - if (myHomeRegistry.getParsingCache() == null) - System.err.println("\n------- Paring cache (after process): null (none)"); - else - print("\n------- Paring cache (after process):", Arrays.asList(myHomeRegistry.getParsingCache()), 0); - print("\n------- Registry iterations (" + myHomeRegistry.getRegistryIterationStackTrace().size() + " in total, total time " + (t-t0)/1000000 + "ms):", myHomeRegistry.getRegistryIterationStackTrace(), 0); - System.err.println("\n--------------------------------------------- " + action + " Results ---------------------------------------------"); - System.err.println("String \"" + strToParse + "\" was parsed into:\n\t" + toStringAndCls(objToSerialize)); - System.err.println("\n"); + printCacheInfo(out, myHomeRegistry.getParsingCache(), "parsing", " (after process)"); + print(out, "\n------- Registry iterations (" + myHomeRegistry.getRegistryIterationStackTrace().size() + " in total, total time " + (t-t0)/1000000 + "ms):", myHomeRegistry.getRegistryIterationStackTrace(), 0); + out.println("\n--------------------------------------------- " + action + " Results ---------------------------------------------"); + out.println("String \"" + strToParse + "\" was parsed into:\n\t" + toStringAndCls(objToSerialize)); + out.println("\n"); + + out.flush(); return objToSerialize; } @@ -107,31 +120,41 @@ else if (args[99] instanceof Integer && (int) args[99] > 0) strToParse = myHomeRegistry.toString(objToSerialize, args).toString(); double t = System.nanoTime(); - if (myHomeRegistry.getConverterCache() == null) - System.err.println("\n------- Converting cache (after process): null (none)"); - else - print("\n------- Converting cache (after process):", Arrays.asList(myHomeRegistry.getConverterCache()), 0); - print("\n------- Registry iterations (" + myHomeRegistry.getRegistryIterationStackTrace().size() + " in total, total time " + (t-t0)/1000000 + "ms):", myHomeRegistry.getRegistryIterationStackTrace(), 0); - System.err.println("\n--------------------------------------------- " + action + " Results ---------------------------------------------"); - System.err.println("Object " + toStringAndCls(objToSerialize) + " was converted to string:\n" + (strToParse.contains("\n") ? strToParse : "\t" + strToParse)); - System.err.println("\n"); + printCacheInfo(out, myHomeRegistry.getConverterCache(), "converting", " (after process)"); + print(out, "\n------- Registry iterations (" + myHomeRegistry.getRegistryIterationStackTrace().size() + " in total, total time " + (t-t0)/1000000 + "ms):", myHomeRegistry.getRegistryIterationStackTrace(), 0); + out.println("\n--------------------------------------------- " + action + " Results ---------------------------------------------"); + out.println("Object " + toStringAndCls(objToSerialize) + " was converted to string:\n" + (strToParse.contains("\n") ? strToParse : "\t" + strToParse)); + out.println("\n"); + + out.flush(); return strToParse; } - if (myHomeRegistry.getParsingCache() == null) - System.err.println("\n------- Current parsing cache: null (none)"); - else - print("\n------- Current parsing cache:", Arrays.asList(myHomeRegistry.getParsingCache()), 0); - - if (myHomeRegistry.getConverterCache() == null) - System.err.println("\n------- Current parsing cache: null (none)"); - else - print("\n------- Current parsing cache:", Arrays.asList(myHomeRegistry.getConverterCache()), 0); - System.err.println("\n--------------------------------------------- No Results ---------------------------------------------"); - System.err.println("\n"); + printCacheInfo(out, myHomeRegistry.getParsingCache(), "parsing", ""); + printCacheInfo(out, myHomeRegistry.getConverterCache(), "converting", ""); + + out.println("\n--------------------------------------------- No Results ---------------------------------------------"); + if (myHomeRegistry.getParsingCache() != null && myHomeRegistry.getParsingCache().length > 0 || myHomeRegistry.getConverterCache() != null && myHomeRegistry.getConverterCache().length > 0) + out.println("If this is not the expected outcome you can try not using ParserRegistry caching or try to pre-cache some parsers!"); + out.println("\n"); + + out.flush(); return VOID; } + /** + * Helper method for printing contents of {@link ParserRegistry#getParsingCache()}. + * + * @since 1.3.7 + */ + public static void printCacheInfo(PrintWriter out, DataParser[] cache, String cacheType, String additional) + { + if (cache == null) + out.println("\n------- Current " + cacheType + " cache" + additional + ": null (none)"); + else + print(out, "\n------- Current " + cacheType + " cache" + additional + ":", Arrays.asList(cache), 0); + } + /** * @param serializer | Serializer to debug! * @@ -190,19 +213,19 @@ public static String toStringAndCls(Object obj) * * @since 1.3.5 */ - public static void print(String text, List objs, int tabs) + public static void print(PrintWriter out, String text, List objs, int tabs) { - System.err.println(text); + out.println(text); for (int i = 0, i2 = 0; i < objs.size(); i++) { Object o = objs.get(i); String strTbs = multilpy('\t', tabs).toString(); if (o instanceof List) - print(strTbs + (i2++) + ":\t" + o.getClass().getName() + ":", (List) o, tabs+1); + print(out, strTbs + (i2++) + ":\t" + o.getClass().getName() + ":", (List) o, tabs+1); else if (o instanceof Map) - print(strTbs + (i2++) + ":\t" + o.getClass().getName() + ":", (Map) o, tabs+1); + print(out, strTbs + (i2++) + ":\t" + o.getClass().getName() + ":", (Map) o, tabs+1); else - System.err.println(multilpy('\t', tabs).toString() + (i2++) + ":\t" + String.valueOf(o)); + out.println(multilpy('\t', tabs).toString() + (i2++) + ":\t" + String.valueOf(o)); } } @@ -211,19 +234,19 @@ else if (o instanceof Map) * * @since 1.3.5 */ - public static void print(String text, Map map, int tabs) + public static void print(PrintWriter out, String text, Map map, int tabs) { - System.err.println(text); + out.println(text); for (Entry entry : map.entrySet()) { Object o = entry.getValue(); String strTbs = multilpy('\t', tabs).toString(); if (o instanceof List) - print(strTbs + (entry.getKey()) + ":\t" + o.getClass().getName() + ":", (List) o, tabs+1); + print(out, strTbs + (entry.getKey()) + ":\t" + o.getClass().getName() + ":", (List) o, tabs+1); else if (o instanceof Map) - print(strTbs + (entry.getKey()) + ":\t" + o.getClass().getName() + ":", (Map) o, tabs+1); + print(out, strTbs + (entry.getKey()) + ":\t" + o.getClass().getName() + ":", (Map) o, tabs+1); else - System.err.println(strTbs + entry.getKey() + ":\t" + String.valueOf(o)); + out.println(strTbs + entry.getKey() + ":\t" + String.valueOf(o)); } } diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java index bf12831..09ac8ab 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java @@ -217,7 +217,7 @@ protected Appendable appandVar(Appendable source, CharSequence serializedVar, En protected Appendable appandVal(Appendable source, CharSequence serializedVal, Object value, int tabs, boolean isLast) throws IOException { source.append(multilpy('\t', tabs)).append(serializedVal); - if (isLast || serializedVal != null && indexOfNotInObj(serializedVal, '/') != -1) + if (isLast || serializedVal != null && indexOfNotInObj(serializedVal, "//") != -1) return source; return source.append(','); } diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index ea95a34..57a19f9 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -361,7 +361,7 @@ protected Appendable appandVar(Appendable source, CharSequence serializedVar, En protected Appendable appandVal(Appendable source, CharSequence serializedVal, Object value, int tabs, boolean isLast) throws IOException { source.append(multilpy('\t', tabs)).append(serializedVal); - if (isLast && value instanceof Scope || serializedVal != null && indexOfNotInObj(serializedVal, '/') != -1) + if (isLast && value instanceof Scope || serializedVal != null && indexOfNotInObj(serializedVal, "//") != -1) return source; return source.append(';'); } diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java index 0837750..b91ecc9 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -47,7 +47,7 @@ protected Object eval(ParserRegistry registryForParsers, String expr, Object... List cofs = terms[0]; if (cofs.size() <= 1) return CONTINUE; - List oprs = terms[1]; + List oprs = terms[1]; Object cof1 = null, cof2 = null; String opr = null; @@ -67,11 +67,11 @@ protected Object eval(ParserRegistry registryForParsers, String expr, Object... cof1 = registryForParsers.parse(cof1.toString().trim(), i > 0, new Class[] {getClass()}, argsForParsers); cof1 = cof1 instanceof ResultWrapper ? ((ResultWrapper) cof1).obj : cof1; - cof2 = cofs.remove(index + 1); - if (cof2 instanceof String) - cof2 = registryForParsers.parse(cof2.toString().trim(), i > 0, new Class[] {getClass()}, argsForParsers); - cof2 = cof2 instanceof ResultWrapper ? ((ResultWrapper) cof2).obj : cof2; - + cof2 = cofs.remove(index + 1); + if (cof2 instanceof String) + cof2 = registryForParsers.parse(cof2.toString().trim(), i > 0, new Class[] {getClass()}, argsForParsers); + cof2 = cof2 instanceof ResultWrapper ? ((ResultWrapper) cof2).obj : cof2; + opr = oprs.remove(index).toString(); if (opr.charAt(0) == '+') cofs.set(index, new ResultWrapper(addOperator(cof1, cof2))); @@ -93,7 +93,7 @@ else if (opr.charAt(0) == '%') } catch (IndexOutOfBoundsException ex) { - LogProvider.instance.logErr("Missing coefficient in \"" + expr + "\"!", ex); + LogProvider.instance.logErr("Missing coefficient in \"" + expr + "\"!", null); } catch (ArithmeticException ex) { @@ -123,7 +123,7 @@ public Object subOperator(Object cof, Object cof2) return sub(toNum(cof), toNum(cof2)); } - /** + /** * @return Multiplication of cof and cof2 multiplied by sign (cof * cof2 * sign) supposed to be returned! * * @since 1.3.2 @@ -133,7 +133,7 @@ public Object multOperator(Object cof, Object cof2, int sign) return mult(toNum(cof), toNum(cof2), sign); } - /** + /** * @return Division of cof and cof2 multiplied by sign (cof / cof2 * sign) supposed to be returned! * * @since 1.3.2 @@ -143,8 +143,8 @@ public Object divOperator(Object cof, Object cof2, int sign) return div(toNum(cof), toNum(cof2), sign); } - /** - * @return Modulation of cod and cof2 (cof % cof2) supposed to be returned! + /** + * @return Modulation of cod and cof2 (cof % cof2) supposed to be returned! * * @since 1.3.2 */ @@ -154,7 +154,7 @@ public Object modOperator(Object cof, Object cof2) } /** - * @return Cof powered by cof2 multiplied by sign (Math.pow(cof, cof2 * sign)) supposed to be returned! + * @return Cof powered by cof2 multiplied by sign (Math.pow(cof, cof2 * sign)) supposed to be returned! * * @since 1.3.2 */ @@ -235,7 +235,7 @@ public static Object sub(Object cof, Object cof2) return ((Number) cof).doubleValue() - ((Number) cof2).doubleValue(); } - + if (cof instanceof Collection) { if (cof2 instanceof Collection) @@ -247,6 +247,17 @@ else if (cof2.getClass().isArray()) return cof; } + if (cof instanceof Scope) + { + if (cof2 instanceof Collection) + ((Scope) cof).values().removeAll((Collection) cof2); + else if (cof2.getClass().isArray()) + ((Scope) cof).values().removeAll(Arrays.asList(cof2)); + else + ((Scope) cof).values().remove(cof2); + return cof; + } + return null; } @@ -341,7 +352,6 @@ else if (cof instanceof Integer || cof2 instanceof Integer) /** * * @param str | String to split! - * @param operatos | If true, list of spited operators will be returned otherwise terms split after each operator. * @param oprs | Operators to use as a splitters. * * @return List of terms splitted according to inserted arguments! For example getTerm("5 + 6", true, '+') will return [+], while getTerm("5 + 6", false, '+') will return [5, 6]! @@ -349,7 +359,7 @@ else if (cof instanceof Integer || cof2 instanceof Integer) * @since 1.3.0 */ @SuppressWarnings("unchecked") - public static List[] getTerms(String str, char... oprs) + public static List[] getTerms(CharSequence str, char... oprs) { List[] ret = new ArrayList[] {new ArrayList<>(), new ArrayList<>()}; //cofs, ops @@ -441,7 +451,7 @@ else if (oldCh <= 32 && isCof == 1) } /** - * @return null -> 0, bool ? 1 : 0 + * @return null -> 0, bool ? 1 : 0. Otherwise obj. * * @since 1.3.0 */ @@ -449,9 +459,9 @@ public static Object toNum(Object obj) { if (obj == null) return 0; - else if (obj instanceof Boolean) + if (obj instanceof Boolean) return (boolean) obj ? 1 : 0; - else if (obj instanceof Character) + if (obj instanceof Character) return (int) (char) obj; return obj; } diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java index 7509862..b60d778 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java @@ -13,7 +13,7 @@ import org.ugp.serialx.converters.imports.ImportsProvider; /** - * This parser provides comparison operators to compare 2 objects! For example 6 > 5 or 5 == 5 returns true! + * This parser provides comparison operators, > < >= <= == === != !=== and instanceof, to compare 2 objects! For example 6 > 5, 1 < 5 or 5 == 5 returns true! * * @author PETO * @@ -24,42 +24,43 @@ public class ComparisonOperators implements DataParser @Override public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { - int index = -1; - if (str.length() > 2 && (indexOfNotInObj(str, '>', '<', '!', '=') > -1 || (index = indexOfNotInObj(str, " instanceof ")) > -1)) + int len; + if ((len = str.length()) < 3) + return CONTINUE; + + int index, op; + if ((index = indexOfNotInObj(str, '<', '>', '=')) > -1) { - if (index > -1) + if ((op = str.charAt(index)) != '=') // > < { - try - { - return ImportsProvider.forName(args.length > 0 ? args[0] : null, str.substring(index+12).trim()).isInstance(myHomeRegistry.parse(str.substring(0, index).trim(), args)); - } - catch (Exception e) - { - LogProvider.instance.logErr("Unable to check if object " + str.substring(0, index).trim() + " is instance of class \"" + str.substring(index+12).trim() + "\" because there is no such a class!", e); - return null; - } + boolean orEqual = index+1 < len && str.charAt(index+1) == '='; + return comparisonOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (orEqual ? 2 : 1)).trim(), args), op == '>', orEqual); } - else if ((index = str.indexOf("!=")) > -1) + + if (/*op == '=' &&*/ str.charAt(index+1) == '=') // == { - boolean isTripple = str.charAt(index+2) == '='; - return !equalsOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (isTripple ? 3 : 2)).trim(), args), isTripple); + boolean isTripple = index+2 < len && str.charAt(index+2) == '='; + return equalsOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (isTripple ? 3 : 2)).trim(), args), isTripple); } - else if ((index = str.indexOf("==")) > -1) + if (/*op == '=' &&*/ str.charAt(--index) == '!') // != { - boolean isTripple = str.charAt(index+2) == '='; - return equalsOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (isTripple ? 3 : 2)).trim(), args), isTripple); + boolean isTripple = index+2 < len && str.charAt(index+2) == '='; + return !equalsOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (isTripple ? 3 : 2)).trim(), args), isTripple); } - else if ((index = str.indexOf('<')) > -1) + //System.out.println(str); + } + + if ((index = indexOfNotInObj(str, " instanceof ")) > -1) + { + try { - boolean orEqual = str.charAt(index+1) == '='; - return comparisonOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (orEqual ? 2 : 1)).trim(), args), false, orEqual); + return ImportsProvider.forName(args.length > 0 ? args[0] : null, str.substring(index+12).trim()).isInstance(myHomeRegistry.parse(str.substring(0, index).trim(), args)); } - else if ((index = str.indexOf('>')) > -1) + catch (Exception e) { - boolean orEqual = str.charAt(index+1) == '='; - return comparisonOperator(myHomeRegistry.parse(str.substring(0, index).trim(), args), myHomeRegistry.parse(str.substring(index + (orEqual ? 2 : 1)).trim(), args), true, orEqual); + LogProvider.instance.logErr("Unable to check if object " + str.substring(0, index).trim() + " is instance of class \"" + str.substring(index+12).trim() + "\" because there is no such a class!", e); + return null; } - //System.out.println(str); } //double t = System.nanoTime(); //System.out.println((t-t0)/1000000); diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java index 57fc84c..e3ad5cf 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java @@ -17,22 +17,21 @@ public class ConditionalAssignmentOperators implements DataParser @Override public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { - if (str.length() > 2 && indexOfNotInObj(str, '?') > -1) + int index, ternIfIndex; + if (str.length() > 2 && (index = indexOfNotInObj(str, '?')) > -1) { - int index = indexOfOne(str, 0, '?'); - if (index > -1) + if ((ternIfIndex = indexOfOne(str, index, '?')) > -1) //?: { try { - String last = str.substring(index+1), first = str.substring(0, index); + String last = str.substring((index = ternIfIndex)+1), first = str.substring(0, index); boolean condition = (boolean) LogicalOperators.toBool(myHomeRegistry.parse(first.trim(), args)); if ((index = indexOfTernaryElse(last, 1, '?', ':')) > -1) { first = last.substring(0, index); return condition ? myHomeRegistry.parse(first.trim(), args) : (last = last.substring(index+1).trim()).isEmpty() ? VOID : myHomeRegistry.parse(last, args); } - else - return condition ? myHomeRegistry.parse(last.trim(), args) : VOID; + return condition ? myHomeRegistry.parse(last.trim(), args) : VOID; } catch (ClassCastException ex) { @@ -41,10 +40,10 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) } } - if ((index = str.indexOf("??")) > -1) + if (str.charAt(index+1) == '?') //?? { - Object obj = myHomeRegistry.parse(str.substring(0, index).trim(), args); - if (obj != null) + Object obj ; + if ((obj = myHomeRegistry.parse(str.substring(0, index).trim(), args)) != null) return obj; String next = str.substring(index+2); @@ -57,17 +56,17 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) } /** - * @param str - * @param defaultCountOfConfitions - * @param tenraryTokens + * @param str | Source string to search. + * @param defaultCountOfConfitions | How many condition operators (tenraryTokens[0]) are expected. Should be 1 in most cases. + * @param tenraryTokens | Characters representing parts of ternary operator. Index 0 should be '?' and index 1 should be ':'. * - * @return + * @return Return index of else branch in ternary operator expression or -1 if there is no else branch! * * @since 1.3.5 */ public static int indexOfTernaryElse(CharSequence str, int defaultCountOfConfitions, char... ternaryOperators) { - for (int i = 0, len = str.length(), oldCh = -1, tokenCount = 0, quote = 0, brackets = 0; i < len; i++) + for (int i = 0, len = str.length(), oldCh = -1, tokenCount = 0, quote = 0, brackets = 0; i < len; i++) { char ch = str.charAt(i); if (ch == '\"') @@ -94,11 +93,11 @@ else if (quote % 2 == 0 && brackets == 0) } /** - * @param str - * @param from - * @param oneChar + * @param str | String to search. + * @param from | Beginning index. Should be 0 in most cases. + * @param oneChar | Single character that you want to find. * - * @return + * @return Index of oneChar if there is only one in a row! * * @since 1.3.5 */ diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java index 9bd7cb6..5e60f17 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java @@ -1,11 +1,9 @@ package org.ugp.serialx.converters.operators; +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; import static org.ugp.serialx.Utils.indexOfNotInObj; -import static org.ugp.serialx.converters.operators.ArithmeticOperators.getTerms; -import java.util.List; - -import org.ugp.serialx.LogProvider; import org.ugp.serialx.converters.DataParser; /** @@ -20,80 +18,47 @@ public class LogicalOperators implements DataParser @Override public Object parse(ParserRegistry myHomeRegistry, String s, Object... args) { - if (s.length() > 2 && indexOfNotInObj(s, '&', '|', '^') > -1) + int len; + if ((len = s.length()) < 3) + return CONTINUE; + + Object result = CONTINUE; + int i = 0, index; + do { - List[] terms = getTerms(s, '&', '|', '^'); - List cofs = terms[0]; - if (cofs.size() <= 1) - return CONTINUE; - - List oprs = terms[1]; + if ((index = indexOfNotInObj(s, i, len, true, '&', '|', '^')) == -1) + return result; - Object cof1 = null, cof2 = null, opr = null; - try - { - for (int i = 0, index = 0, size = oprs.size(); i < size; index = 0, i++) - { - opr = oprs.remove(index); - if (opr.equals("&&")) - { - cof1 = cofs.get(index); - if (cof1 instanceof String) - cof1 = myHomeRegistry.parse(cof1.toString().trim(), i > 0, new Class[] {getClass()}, args); - if (cof1.equals(false)) - { - cofs.remove(index + 1); - cofs.set(index, false); - } - else - { - cof2 = cofs.remove(index + 1); - if (cof2 instanceof String) - cof2 = myHomeRegistry.parse(cof2.toString().trim(), i > 0, new Class[] {getClass()}, args); - cofs.set(index, andOperator(cof1, cof2)); - } - } - else if (opr.equals("||")) - { - cof1 = cofs.get(index); - if (cof1 instanceof String) - cof1 = myHomeRegistry.parse(cof1.toString().trim(), i > 0, new Class[] {getClass()}, args); - if (cof1.equals(true)) - { - return true; - } - else - { - cof2 = cofs.remove(index + 1); - if (cof2 instanceof String) - cof2 = myHomeRegistry.parse(cof2.toString().trim(), i > 0, new Class[] {getClass()}, args); - cofs.set(index, orOperator(cof1, cof2)); - } - } - else if (opr.equals("^")) - { - cof1 = cofs.get(index); - if (cof1 instanceof String) - cof1 = myHomeRegistry.parse(cof1.toString().trim(), i > 0, new Class[] {getClass()}, args); - - cof2 = cofs.remove(index + 1); - if (cof2 instanceof String) - cof2 = myHomeRegistry.parse(cof2.toString().trim(), i > 0, new Class[] {getClass()}, args); - cofs.set(index, xorOperator(cof1, cof2)); - } - } - } - catch (ClassCastException ex) + int op; + if ((op = s.charAt(i = index)) != '^' && (++i >= len || s.charAt(i) != op)) // Ensure && and || and refuse & and | + continue; + + if (result == CONTINUE) // Beginning + result = myHomeRegistry.parse(s.substring(0, index).trim(), args); + + int nextOpIndex; + if ((nextOpIndex = indexOfNotInObj(s, ++i, len, true, '&', '|', '^')) == -1) + nextOpIndex = len; + + if (op == '&') { - LogProvider.instance.logErr("Logical operator " + opr + " is undefined between " + cof1.getClass().getName() + " and " + cof2.getClass().getName() + "!", ex); + if (!FALSE.equals(result)) + result = andOperator(result, myHomeRegistry.parse(s.substring(i, nextOpIndex).trim(), args)); } - catch (IndexOutOfBoundsException e) + else if (op == '|') { - LogProvider.instance.logErr("Missing coefficient in \"" + s + "\"!", e); + if (TRUE.equals(result)) + return TRUE; + result = orOperator(result, myHomeRegistry.parse(s.substring(i, nextOpIndex).trim(), args)); } - return cofs.get(0); + else + result = xorOperator(result, myHomeRegistry.parse(s.substring(i, nextOpIndex).trim(), args)); + + i = nextOpIndex; } - return CONTINUE; + while (i < len); + + return result; } /** @@ -127,7 +92,7 @@ public Object xorOperator(Object obj1, Object obj2) } /** - * @return null -> false or if number > 0 + * @return null -> false or if number > 0. Otherwise obj. * * @since 1.3.0 */ @@ -135,18 +100,18 @@ public static Object toBool(Object obj) { if (obj == null) return false; - else if (obj instanceof Number) - return ((Number) obj).doubleValue() > 0; - else if (obj instanceof Character) - return (char) obj > 0; - /*else if (obj instanceof Map) + if (obj instanceof Number) + return ((Number) obj).doubleValue() != 0; + if (obj instanceof Character) + return (char) obj != 0; + /*if (obj instanceof Map) return !((Map) obj).isEmpty(); - else if (obj instanceof Collection) + if (obj instanceof Collection) return !((Collection) obj).isEmpty(); - else if (obj instanceof Scope) + if (obj instanceof Scope) return !((Scope) obj).isEmpty(); - else if (obj.getClass().isArray()) + if (obj.getClass().isArray()) return Array.getLength(obj) > 0;*/ return obj; } -} +} \ No newline at end of file diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java index d59f941..f644357 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java @@ -4,7 +4,8 @@ import org.ugp.serialx.converters.DataParser; /** - * This parser provides ability to negate stuff! For example !true returns false! + * This parser provides ability to negate stuff! For example !true returns false!
+ * This include classic numeric negation - and logical negation ! operators. * * @author PETO * @@ -16,11 +17,11 @@ public class NegationOperator implements DataParser public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { int ch, len = str.length(); - if (len > 0 && ((ch = str.charAt(0)) == '-' || ch == '!')) + if (len > 0 && ((ch = str.charAt(0)) == '!' || ch == '-')) { int negCount = 1; for (int i = negCount; i < len; i++) - if ((ch = str.charAt(i)) == '-' || ch == '!') + if ((ch = str.charAt(i)) == '!' || ch == '-') negCount++; else break; @@ -28,7 +29,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) Object obj = myHomeRegistry.parse(str.substring(negCount), args); if (negCount % 2 == 0) return obj; - Object neg = notOperator(obj); + Object neg = ch == '!' ? logicalNotOperator(obj) : notOperator(obj); if (obj == neg && !(obj instanceof Number && ((Number) obj).intValue() == 0)) LogProvider.instance.logErr("Unable to nagete \"" + obj + "\" because object of \"" + obj.getClass().getName() + "\" cant be negated!", null); return neg; @@ -38,7 +39,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) /** - * @param obj | Object to negate! + * @param obj | Object to negate! Numeric in nature or an object! * * @return Negated object supposed to be returned or same object as argument if object can't be negated! Only numbers and booleans can be negated! * @@ -49,6 +50,19 @@ public Object notOperator(Object obj) return negate(obj); } + /** + * @param obj | Object to negate! Should be boolean! + * + * @return Negated object supposed to be returned or same object as argument if object can't be negated! Should, but do not strictly has to be boolean!
+ * Node: By default it has same behavior as {@link NegationOperator#notOperator(Object)} but it can be overridden! + * + * @since 1.3.7 + */ + public Object logicalNotOperator(Object obj) + { + return negate(obj); + } + /** * @param obj | Object to negate! * From 7cce36be443eb13eec9e2406ba711a8a98bc0bc6 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 2 Jul 2024 14:47:59 +0200 Subject: [PATCH 29/48] refactoring AritmeticOperators, GenericScope is now Collection! --- .../java/org/ugp/serialx/GenericScope.java | 115 +++++++++++--- .../src/main/java/org/ugp/serialx/Scope.java | 4 +- .../main/java/org/ugp/serialx/Serializer.java | 2 +- .../ugp/serialx/converters/DataParser.java | 12 +- .../ugp/serialx/protocols/ScopeProtocol.java | 2 +- .../protocols/SerializationProtocol.java | 3 +- .../serialx/devtools/DebugParserRegistry.java | 12 +- .../juss/converters/VariableConverter.java | 2 +- .../operators/ArithmeticOperators.java | 144 +++++++++++------- 9 files changed, 200 insertions(+), 96 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index 7cec162..359e51d 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -22,7 +22,7 @@ /** - * This is some kind of hybrid between {@link List} and {@link Map} which allow you to have both variables and independent values managed by one Object.
+ * This collection is some sort of hybrid between {@link List} and {@link Map} which allow you to have both variables and independent values managed by one Object.
* Note: Variables are managed and accessed classically via {@link Map} methods such as put(KeyT key, Object) and array of independent values is accessed by via {@link List} methods such as add(Object) and get(int)
* Also this is java representation of JUSS GenericScope group such as: *
@@ -35,12 +35,12 @@
  * 
  * @author PETO
  * 
- * @since 1.2.0
+ * @since 1.3.5
  * 
  * @param  generic type of variables key.
  * @param  generic type of variables value and independent value.
  */
-public class GenericScope implements Iterable, Cloneable, Serializable
+public class GenericScope implements Collection, Cloneable, Serializable
 {
 	private static final long serialVersionUID = 5717775602991055386L;
 	
@@ -108,7 +108,7 @@ else if (obj instanceof Collection)
 		else if (obj instanceof Map)
 			return valuesCount() <= 0 && variables().equals(obj);
 		else if (obj != null && obj.getClass().isArray())
-			return variablesCount() <= 0 && Objects.deepEquals(toValArray(), Utils.fromAmbiguousArray(obj));
+			return variablesCount() <= 0 && Objects.deepEquals(toArray(), Utils.fromAmbiguousArray(obj));
 		return super.equals(obj);
 	}
 	
@@ -365,12 +365,28 @@ public boolean containsVariable(KeyT variableKey)
 	}
 	
 	/**
-	 * @param value | Objecthe value.
+	 * @param value | Object the independent value.
+	 * 
+	 * @return True if independent value was found in this scope.
+	 * 
+	 * @since 1.3.7
+	 */
+	@Override
+	public boolean contains(Object value) 
+	{
+		return values().contains(value);
+	}
+	
+	/**
+	 * @deprecated USE {@link GenericScope#contains(Object)} instead!
+	 * 
+	 * @param value | Object the value.
 	 * 
 	 * @return True if independent value was found in this scope.
 	 * 
 	 * @since 1.2.0
 	 */
+	@Deprecated
 	public boolean containsIndependentValue(ValT value) 
 	{
 		return values().contains(value);
@@ -417,6 +433,7 @@ public  V get(int valueIndex, Class cls) throws Exception
 	 * 
 	 * @since 1.2.0
 	 */
+	@Override
 	public boolean add(ValT value)
 	{
 		boolean result = values().add(value);
@@ -432,11 +449,12 @@ public boolean add(ValT value)
 	 * 
 	 * @since 1.2.0
 	 */
-	public boolean addAll(Collection values)
+	@Override
+	public boolean addAll(Collection values)
 	{
 		if (values.isEmpty())
 			return false;
-		return values().addAll(values);
+		return values().addAll((Collection) values);
 	}
 	
 	/**
@@ -451,6 +469,45 @@ public boolean addAll(@SuppressWarnings("unchecked") ValT... values)
 		return addAll(Arrays.asList(values));
 	}
 	
+	/**
+	 * @param values | Independent values to check.
+	 * 
+	 * @return True all provided values are contained in this scope as independent values!
+	 * 
+	 * @since 1.3.7
+	 */
+	@Override
+	public boolean containsAll(Collection values) 
+	{
+		return values().containsAll(values);
+	}
+
+	/**
+	 * @param values | Independent values to check.
+	 * 
+	 * @return {@link Collection#removeAll(Collection)} for the independent values,,,
+	 * 
+	 * @since 1.3.7
+	 */
+	@Override
+	public boolean removeAll(Collection values)
+	{
+		return values().removeAll(values);
+	}
+
+	/**
+	 * @param values | Independent values to check.
+	 * 
+	 * @return {@link Collection#retainAll(Collection)} for the independent values,,,
+	 * 
+	 * @since 1.3.7
+	 */
+	@Override
+	public boolean retainAll(Collection values)
+	{
+		return values().retainAll(values);
+	}
+	
 	/**
 	 * @param scopeValueIndex | Index of sub-scopes value.
 	 * 
@@ -521,7 +578,7 @@ public  T toObject(Class objClass, ProtocolRegistry protocolsToUse) throws
 		SerializationProtocol pro = protocolsToUse == null ? null : protocolsToUse.GetProtocolFor(objClass, SerializationProtocol.MODE_DESERIALIZE);
 		if (pro != null)
 		{
-			T obj = pro.unserialize(objClass, this.variablesCount() > 0 ? new Object[] {this} : this.toValArray());
+			T obj = pro.unserialize(objClass, this.variablesCount() > 0 ? new Object[] {this} : this.toArray());
 			if (obj != null)
 				return obj;
 		}
@@ -680,14 +737,27 @@ public ValT remove(int valueIndex)
 		return values().remove(valueIndex < 0 ? valuesCount() + valueIndex : valueIndex);
 	}
 	
+	/**
+	 * @param independentValue | Independent value to remove!
+	 * 
+	 * @return Value of variable that was removed!
+	 * 
+	 * @since 1.3.7
+	 */
+	@Override
+	public boolean remove(Object independentValue)
+	{
+		return values().remove(independentValue);
+	}
+	
 	/**
 	 * @param variableKey | Name of variable to remove!
 	 * 
 	 * @return Value of variable that was removed!
 	 * 
-	 * @since 1.3.2
+	 * @since 1.3.7
 	 */
-	public ValT remove(KeyT variableKey)
+	public ValT removeVariable(KeyT variableKey)
 	{
 		return variables().remove(variableKey);
 	}
@@ -699,6 +769,7 @@ public ValT remove(KeyT variableKey)
 	 * 
 	 * @since 1.3.5
 	 */
+	@Override
 	public void clear()
 	{
 		variables().clear();
@@ -712,7 +783,7 @@ public void clear()
 	 */
 	@SuppressWarnings("unchecked")
 	public GenericScope inheritParent()
-	{ 
+	{
 		GenericScope parent = getParent();
 		if (parent != null)
 			variables().putAll((Map) parent.variables());
@@ -765,8 +836,11 @@ public int variablesCount()
 	
 	/**
 	 * @return Total number of variables and independent values of this scope! (vvaluesCount() + variablesCount())
+	 * 
+	 * @since 1.3.7 (before 1.3.7 known as totalSize)
 	 */
-	public int totalSize()
+	@Override
+	public int size()
 	{
 		return valuesCount() + variablesCount();
 	}
@@ -776,9 +850,10 @@ public int totalSize()
 	 * 
 	 * @since 1.2.0
 	 */
+	@Override
 	public boolean isEmpty()
 	{
-		return totalSize() <= 0;
+		return size() <= 0;
 	}
 	
 	/**
@@ -838,22 +913,24 @@ public List toValList()
 	 * @return Primitive array with independent values of this {@link GenericScope}. These values have nothing to do with values of variables, they are independent!
 	 * Modifying this list will not affect this {@link GenericScope} object!
 	 * 
-	 * @since 1.2.0
+	 * @since 1.3.7 (before 1.3.7 known as toValArray)
 	 */
-	public Object[] toValArray()
+	@Override
+	public Object[] toArray() 
 	{
 		return values().toArray();
 	}
-	
+
 	/**
 	 * @param vals | Array to store independent values into!
 	 * 
 	 * @return Primitive array with independent values of this {@link GenericScope}. These values have nothing to do with values of variables, they are independent!
 	 * Modifying this list will not affect this {@link GenericScope} object!
 	 * 
-	 * @since 1.3.5
+	 * @since 1.3.7 (before 1.3.7 known as toValArray)
 	 */
-	public  V[] toValArray(V[] vals)
+	@Override
+	public  T[] toArray(T[] vals) 
 	{
 		return values().toArray(vals);
 	}
@@ -874,7 +951,7 @@ public List toUnifiedList()
 	}
 	
 	/**
-	 * @return Values of this scope. These are not the values of keys these are values that have no key. You can access them via {@link GenericScope#get(int)}!
+	 * @return Independent values of this scope. These are not the values of keys these are values that have no key. You can access them via {@link GenericScope#get(int)}!
 	 * Note: Editing this List will affect this scope!
 	 * 
 	 * @since 1.2.0
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java
index eba21de..ca80662 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java
@@ -22,7 +22,7 @@
 
 	
 /**
- * This is some kind of hybrid between {@link List} and {@link Map} which allow you to have both variables and independent values managed by one Object. 
+ * This collection is some sort of hybrid between {@link List} and {@link Map} which allow you to have both variables and independent values managed by one Object.
* Note: Variables are managed and accessed classically via {@link Map} methods such as put(String key, Object) and array of independent values is accessed by via {@link List} methods such as add(Object) and get(int)
* Also this is java representation of JUSS Scope group such as: *
@@ -1082,7 +1082,7 @@ public static  T intoNew(Class objCls, GenericScope fro
 		if (objCls.isArray())
 		{
 			if (objCls.getComponentType() == Object.class)
-				return (T) fromScope.toValArray();
+				return (T) fromScope.toArray();
 			
 			return (T) into(Array.newInstance(objCls.getComponentType(), fromScope.valuesCount()), fromScope, fieldNamesToUse);
 		}
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java
index 3dcd9e9..8b0fc6b 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java
@@ -35,7 +35,7 @@
 import org.ugp.serialx.protocols.SerializationProtocol.ProtocolRegistry;
 
 /**
- * {@link org.ugp.serialx.Serializer} is powerful utility class that allows you to serialize any object in Java using custom data format compiled by recursive descent parser consisting of {@link DataParser}s.
+ * {@link org.ugp.serialx.Serializer} is powerful abstract class that allows you to serialize any object in Java using custom data format compiled by recursive descent parser consisting of {@link DataParser}s.
  * This class itself is responsible for formating and managing input-output (IO) of content obtained from parsers and protocols as well as their management of their usage!
  * It is instance of {@link Scope} so we can say that this is scope that can serialize itself using system of already mentioned {@link DataParser} and {@link SerializationProtocol}!
  * 
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java
index ce57623..e55a673 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java
@@ -213,21 +213,19 @@ public Object parse(String str, Object... args)
 		 * 
 		 * @since 1.3.5
 		 */
-		public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ignore, Object... args)
+		public Object parse(String str, boolean returnAsStringIfNotFound, Class ignore, Object... args)
 		{
 			Object obj = null; 
 			if (parsingCache != null)
 				for (DataParser parser : parsingCache)
-					if (parser != null && (obj = parser.parse(this, str, args)) != CONTINUE)
+					if (parser != null && (ignore == null || ignore != parser.getClass()) && (obj = parser.parse(this, str, args)) != CONTINUE)
 						return obj; 
 			
-			registryLoop: for (int i = 0, size = size(); i < size; i++)
+			for (int i = 0, size = size(); i < size; i++)
 			{
 				DataParser parser = get(i);
-				if (ignore != null)
-					for (Class cls : ignore) 
-						if (cls == parser.getClass())
-							continue registryLoop;
+				if (ignore != null && ignore == parser.getClass())
+					continue;
 
 				if ((obj = parser.parse(this, str, args)) != CONTINUE)
 				{
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java
index aae4ce0..e591c13 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/ScopeProtocol.java
@@ -33,7 +33,7 @@ public Object[] serialize(GenericScope object) throws Exception
 		{
 			if (objectClass == args[0].getClass())
 				return (GenericScope) args[0];
-			return objectClass.getConstructor(Map.class, Object[].class).newInstance(((GenericScope) args[0]).toVarMap(), ((GenericScope) args[0]).toValArray());
+			return objectClass.getConstructor(Map.class, Object[].class).newInstance(((GenericScope) args[0]).toVarMap(), ((GenericScope) args[0]).toArray());
 		}
 		return objectClass.getConstructor(Map.class, Object[].class).newInstance(new HashMap<>(), args);
 	}
diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java
index 2b8d50a..20e98a3 100644
--- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java
+++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java
@@ -293,7 +293,8 @@ public ProtocolRegistry clone()
 		@Override
 		public void add(int index, SerializationProtocol element) 
 		{
-			if (GetProtocolFor(element.applicableFor()) != null && element.applicableFor() != Object.class)
+			SerializationProtocol existing;
+			if ((existing = GetProtocolFor(element.applicableFor(), element.getMode())) != null && element.applicableFor() == existing.applicableFor())
 				LogProvider.instance.logErr("Protocol applicable for \"" + element.applicableFor().getName() + "\" is already registred!", null);
 			addDuplicatively(index, element);
 		}
diff --git a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java
index 3bead58..5d5cc77 100644
--- a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java
+++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java
@@ -98,7 +98,7 @@ public CharSequence toString(Object obj, Object... args) {
 	}
 	
 	@Override
-	public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ignore, Object... args) 
+	public Object parse(String str, boolean returnAsStringIfNotFound, Class ignore, Object... args) 
 	{
 		int iterationIndex = 0;
 		if (args.length > 99 && args[99] instanceof Integer)
@@ -112,7 +112,7 @@ public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ign
 			for (int i = 0; i < parsingCache.length; i++)
 			{
 				DataParser parser = parsingCache[i];
-				if (parser != null)
+				if (parser != null && (ignore == null || ignore != parser.getClass()))
 				{
 					try 
 					{
@@ -133,13 +133,11 @@ public Object parse(String str, boolean returnAsStringIfNotFound, Class[] ign
 				}
 			}
 	
-		registryLoop: for (int i = 0, size = size(); i < size; i++)
+		for (int i = 0, size = size(); i < size; i++)
 		{
 			DataParser parser = get(i);
-			if (ignore != null)
-				for (Class cls : ignore) 
-					if (cls == parser.getClass())
-						continue registryLoop;
+			if (ignore != null && ignore == parser.getClass())
+				continue;
 
 			try 
 			{
diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java
index a18a471..7e0038c 100644
--- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java
+++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java
@@ -171,7 +171,7 @@ public Object setMemberOperator(ParserRegistry myHomeRegistry, Object source, St
 		if (source instanceof GenericScope)
 		{
 			if (val == VOID)
-				return ((GenericScope) source).remove(member);
+				return ((GenericScope) source).removeVariable(member);
 			return ((GenericScope) source).put(genericVar ? myHomeRegistry.parse(member, true, null, args) : member, val);
 		}
 		return VOID;
diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java
index b91ecc9..b3cc5fd 100644
--- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java
+++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java
@@ -1,17 +1,20 @@
 package org.ugp.serialx.converters.operators;
 
+import static java.util.Arrays.asList;
 import static org.ugp.serialx.Utils.fastReplace;
+import static org.ugp.serialx.Utils.fromAmbiguousArray;
 import static org.ugp.serialx.Utils.isOneOf;
+import static org.ugp.serialx.Utils.mergeArrays;
 import static org.ugp.serialx.Utils.multilpy;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.ListIterator;
 
+import org.ugp.serialx.GenericScope;
 import org.ugp.serialx.LogProvider;
-import org.ugp.serialx.Scope;
-import org.ugp.serialx.Utils;
 import org.ugp.serialx.converters.DataParser;
 
 /**
@@ -23,7 +26,7 @@
  */
 public class ArithmeticOperators implements DataParser
 {
-	protected String[] priority1Oprs = {"*", "*-", "/", "/-", "%"}, priority2Oprs = {"**", "**-"};
+//	protected String[] priority1Oprs = {"*", "*-", "/", "/-", "%"}, priority2Oprs = {"**", "**-"};
 	
 	@Override
 	public Object parse(ParserRegistry myHomeRegistry, String s, Object... args) 
@@ -38,53 +41,62 @@ public Object parse(ParserRegistry myHomeRegistry, String s, Object... args)
 	 * 
 	 * @since 1.3.0
 	 */
+	@SuppressWarnings("unchecked")
 	protected Object eval(ParserRegistry registryForParsers, String expr, Object... argsForParsers)
 	{
 		while (expr.contains("++") || expr.contains("--") || expr.contains("+-") || expr.contains("-+"))
 			expr = fastReplace(fastReplace(fastReplace(fastReplace(expr, "-+", "-"), "+-", "-"), "--", "+"), "++", "+");
 
-		List[] terms = getTerms(expr, '+', '-', '*', '/', '%');
-		List cofs = terms[0];
+		List[] terms = getAndParseTerms(expr, registryForParsers, argsForParsers, getClass(), '+', '-', '*', '/', '%');
+		ArrayList cofs = (ArrayList) terms[0];
 		if (cofs.size() <= 1)
-			return CONTINUE;
-		List oprs = terms[1];
+			return cofs.get(0);
+		LinkedList oprs = (LinkedList) terms[1];
 
 		Object cof1 = null, cof2 = null;
 		String opr = null;
 		try 
 		{
-			for (int i = 0, index = -1, orderIndex = 0, size = oprs.size(); i < size; index = -1, i++) 
+			for (int i = 0, index = 0, oprsSize = oprs.size(), currentOpPrio = 2; i < oprsSize; index = 0, i++)
 			{
-				for (String adept : priority1Oprs)
-					if ((orderIndex = oprs.indexOf(adept)) > -1 && (index == -1 || orderIndex < index))
-						index = orderIndex;
-				for (String adept : priority2Oprs)
-					if ((orderIndex = oprs.indexOf(adept)) > -1)
-						index = orderIndex;
+				opPrioCheck: //Yes yes... this is quite a shenanigan but it is fast...
+				{
+					for (; currentOpPrio > 0; currentOpPrio--)
+					{
+						for (ListIterator iter = oprs.listIterator(); iter.hasNext();) 
+						{
+							if (getOperatorPriority(opr = iter.next()) == currentOpPrio)
+							{
+								iter.remove();
+								index = iter.nextIndex();
+								break opPrioCheck;
+							}
+						}
+						opr = null;
+					}
+					opr = oprs.poll(); //opr = null;
+				}
 
-				cof1 = cofs.get(index = index < 0 ? 0 : index);
-				if (cof1 instanceof String)
-					cof1 = registryForParsers.parse(cof1.toString().trim(), i > 0, new Class[] {getClass()}, argsForParsers);
-				cof1 = cof1 instanceof ResultWrapper ? ((ResultWrapper) cof1).obj : cof1;
-	
+				cof1 = cofs.get(index);
 				cof2 = cofs.remove(index + 1);
-				if (cof2 instanceof String)
-					cof2 = registryForParsers.parse(cof2.toString().trim(), i > 0, new Class[] {getClass()}, argsForParsers);
-				cof2 = cof2 instanceof ResultWrapper ? ((ResultWrapper) cof2).obj : cof2;
 
-				opr = oprs.remove(index).toString();
-				if (opr.charAt(0) == '+')
-					cofs.set(index, new ResultWrapper(addOperator(cof1, cof2)));
-				else if (opr.charAt(0) == '-')
-					cofs.set(index, new ResultWrapper(subOperator(cof1, cof2)));
-				else if (opr.startsWith("**"))
-					cofs.set(index, new ResultWrapper(powOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1)));
-				else if (opr.charAt(0) == '*')
-					cofs.set(index, new ResultWrapper(multOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1)));
-				else if (opr.charAt(0) == '/')
-					cofs.set(index, new ResultWrapper(divOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1)));
-				else if (opr.charAt(0) == '%')
-					cofs.set(index, new ResultWrapper(modOperator(cof1, cof2)));
+				switch (opr.charAt(0))
+				{
+					case '+':
+						cofs.set(index, addOperator(cof1, cof2)); break;
+					case '-':
+						cofs.set(index, subOperator(cof1, cof2)); break;
+					case '*':
+						if (opr.length() > 1 && opr.charAt(1) == '*')
+						{
+							cofs.set(index, powOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1)); break;
+						}
+						cofs.set(index, multOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1)); break;
+					case '/':
+						cofs.set(index, divOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1)); break;
+					case '%':
+						cofs.set(index, modOperator(cof1, cof2)); break;
+				}
 			}
 		}
 		catch (ClassCastException ex)
@@ -100,7 +112,22 @@ else if (opr.charAt(0) == '%')
 			LogProvider.instance.logErr(ex.getMessage(), ex);
 		}
 		
-		return (cof1 = cofs.get(0)) instanceof ResultWrapper ? ((ResultWrapper) cof1).obj : cof1;
+		return cofs.get(0);
+	}
+	
+	public int getOperatorPriority(String op)
+	{
+		switch (op.charAt(0))
+		{
+			case '+':
+			case '-':
+				return 0; // Low
+			case '*':
+				if (op.length() > 1 && op.charAt(1) == '*')
+					return 2; // High  **
+			default:
+				return 1; // Medium  * / %
+		}
 	}
 	
 	/** 
@@ -186,29 +213,29 @@ public static Object add(Object cof, Object cof2)
 		}
 		
 		if (cof.getClass().isArray())
-			return Utils.mergeArrays(cof, cof2);
+			return mergeArrays(cof, cof2);
 		
 		if (cof instanceof Collection)
 		{
 			if (cof2 instanceof Collection)
 				((Collection) cof).addAll(((Collection) cof2));
 			else if (cof2.getClass().isArray())
-				((Collection) cof).addAll(Arrays.asList(Utils.fromAmbiguousArray(cof2)));
+				((Collection) cof).addAll(asList(fromAmbiguousArray(cof2)));
 			else 
 				((Collection) cof).add(cof2);
 			return cof;
 		}
 		
-		if (cof instanceof Scope)
+		if (cof instanceof GenericScope)
 		{
-			if (cof2 instanceof Scope)
-				((Scope) cof).addAll(((Scope) cof2));
+			if (cof2 instanceof GenericScope)
+				((GenericScope) cof).addAll(((GenericScope) cof2));
 			else if (cof2 instanceof Collection)
-				((Scope) cof).addAll((Collection) cof2);
+				((GenericScope) cof).addAll((Collection) cof2);
 			else if (cof2.getClass().isArray())
-				((Scope) cof).addAll(Utils.fromAmbiguousArray(cof2));
+				((GenericScope) cof).addAll(fromAmbiguousArray(cof2));
 			else 
-				((Scope) cof).add(cof2);
+				((GenericScope) cof).add(cof2);
 			return cof;
 		}
 		return String.valueOf(cof) + String.valueOf(cof2);
@@ -241,20 +268,20 @@ public static Object sub(Object cof, Object cof2)
 			if (cof2 instanceof Collection)
 				((Collection) cof).removeAll(((Collection) cof2));
 			else if (cof2.getClass().isArray())
-				((Collection) cof).removeAll(Arrays.asList(Utils.fromAmbiguousArray(cof2)));
+				((Collection) cof).removeAll(asList(fromAmbiguousArray(cof2)));
 			else 
 				((Collection) cof).remove(cof2);
 			return cof;
 		}
 		
-		if (cof instanceof Scope)
+		if (cof instanceof GenericScope)
 		{
 			if (cof2 instanceof Collection)
-				((Scope) cof).values().removeAll((Collection) cof2);
+				((GenericScope) cof).values().removeAll((Collection) cof2);
 			else if (cof2.getClass().isArray())
-				((Scope) cof).values().removeAll(Arrays.asList(cof2));
+				((GenericScope) cof).values().removeAll(asList(cof2));
 			else 
-				((Scope) cof).values().remove(cof2);
+				((GenericScope) cof).values().remove(cof2);
 			return cof;
 		}
 		
@@ -356,15 +383,15 @@ else if (cof instanceof Integer || cof2 instanceof Integer)
 	 * 
 	 * @return List of terms splitted according to inserted arguments! For example getTerm("5 + 6", true, '+') will return [+], while getTerm("5 + 6", false, '+') will return [5, 6]! 
 	 *
-	 * @since 1.3.0
+	 * @since 1.3.7 (originally getTerms since 1.3.0)
 	 */
 	@SuppressWarnings("unchecked")
-	public static List[] getTerms(CharSequence str, char... oprs)
+	public static List[] getAndParseTerms(String str, ParserRegistry registryForParsers, Object[] argsForParsers, Class classToIgnore, char... oprs)
 	{
-		List[] ret = new ArrayList[] {new ArrayList<>(), new ArrayList<>()}; //cofs, ops
-		
-		StringBuilder[] sbs = {new StringBuilder(), new StringBuilder()}; //cofs, ops
+		List[] ret = new List[] {new ArrayList(), new LinkedList()}; //cofs, ops
 		
+		StringBuilder[] sbs = {new StringBuilder(), new StringBuilder()}; //cofs, ops TODO
+
 		int i = 0, type = 0, len = str.length();
 		for (; i < len; i++) //in case of start cof sign
 		{
@@ -391,7 +418,7 @@ else if ((ch | ' ') == '}')
 				{
 					String s = sbs[lastType].toString().trim();
 					if (!s.isEmpty())
-						ret[lastType].add(s);
+						ret[lastType].add(lastType == 0 ? registryForParsers.parse(s, false, classToIgnore, argsForParsers) : s);
 					sbs[lastType] = new StringBuilder();
 				}
 				else
@@ -405,7 +432,7 @@ else if ((ch | ' ') == '}')
 		{
 			String s = sbs[type].toString().trim();
 			if (!s.isEmpty())
-				ret[type].add(s);
+				ret[type].add(type == 0 ? registryForParsers.parse(s, false, classToIgnore, argsForParsers) : s);
 		}
 		return ret;
 	}
@@ -467,6 +494,8 @@ public static Object toNum(Object obj)
 	}
 	
 	/**
+	 * @deprecated THIS WAS QUIET A MESSY WORKAROUND, DO NOT USE!
+ * * Used internally by {@link ArithmeticOperators} to wrap result of evaluation! * Mainly used by String results! * @@ -474,6 +503,7 @@ public static Object toNum(Object obj) * * @since 1.3.0 */ + @Deprecated protected static class ResultWrapper { public final Object obj; From dce815db698594d50b8fede7592bb1136d9b26e0 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Tue, 9 Jul 2024 23:47:29 +0200 Subject: [PATCH 30/48] finally finsihing refactor of operators AritOprs and LogiOpers, reverting mistake with debug try catch, optimizing some stuff... --- .../src/main/java/org/ugp/serialx/Utils.java | 49 ++-- .../serialx/converters/NumberConverter.java | 2 +- .../serialx/devtools/DebugParserRegistry.java | 32 +-- .../org/ugp/serialx/juss/JussSerializer.java | 24 +- .../operators/ArithmeticOperators.java | 233 +++++++++--------- .../operators/ComparisonOperators.java | 2 +- .../operators/LogicalOperators.java | 94 ++++--- 7 files changed, 225 insertions(+), 211 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index 43dd25c..f7eae53 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -596,13 +596,14 @@ else if (quote % 2 != 0) */ public static int indexOfNotInObj(CharSequence s, char... oneOf) { - return indexOfNotInObj(s, 0, s.length(), true, oneOf); + return indexOfNotInObj(s, 0, s.length(), -1, true, oneOf); } /** * @param s | CharSequence to search! * @param from | The beginning index, where to start the search (should be 0 in most cases). * @param to | Ending index of search (exclusive, should be s.length()). + * @param defaultReturn | Index to return by default (usually -1). * @param firstIndex | If true, first index will be returned, if false last index will be returned. * @param oneOf | Characters to find! * @@ -610,9 +611,8 @@ public static int indexOfNotInObj(CharSequence s, char... oneOf) * * @since 1.3.5 */ - public static int indexOfNotInObj(CharSequence s, int from, int to, boolean firstIndex, char... oneOf) + public static int indexOfNotInObj(CharSequence s, int from, int to, int defaultReturn, boolean firstIndex, char... oneOf) { - int index = -1; for (int brackets = 0, quote = 0; from < to; from++) { char ch = s.charAt(from); @@ -625,7 +625,7 @@ public static int indexOfNotInObj(CharSequence s, int from, int to, boolean firs { if (firstIndex) return from; - index = from; + defaultReturn = from; } else if ((ch | ' ') == '{') brackets++; @@ -638,7 +638,7 @@ else if ((ch | ' ') == '}') } } } - return index; + return defaultReturn; } /** @@ -714,23 +714,24 @@ else if ((ch | ' ') == '}') */ public static String fastReplace(String str, String target, CharSequence replacement) { - int targetLength = target.length(); - if (targetLength == 0) - return str; - - int i1 = 0, i2 = str.indexOf(target); - if (i2 < 0) - return str; - - StringBuilder sb = new StringBuilder(targetLength > replacement.length() ? str.length() : str.length() * 2); - do - { - sb.append(str, i1, i2).append(replacement); - i1 = i2 + targetLength; - i2 = str.indexOf(target, i1); - } while (i2 > 0); - - return sb.append(str, i1, str.length()).toString(); + int targetLength = target.length(); + if (targetLength == 0) + return str; + + int i1 = 0, i2 = str.indexOf(target); + if (i2 < 0) + return str; + + int len = str.length(); + StringBuilder sb = new StringBuilder(targetLength > replacement.length() ? len : len * 2); + do + { + sb.append(str, i1, i2).append(replacement); + i1 = i2 + targetLength; + i2 = str.indexOf(target, i1); + } while (i2 > 0); + + return sb.append(str, i1, len).toString(); } /** @@ -797,14 +798,14 @@ public static boolean equalsLowerCase(CharSequence str, CharSequence lowerCaseOt * @param str | String to display! * @param pos | Position to display! * - * @return String with displayed position! + * @return String with displayed position by using »! * Use for debugging or error printing! * * @since 1.3.2 */ public static String showPosInString(CharSequence str, int pos) { - return str + "\n" + multilpy(' ', pos) + "^"; + return str.subSequence(0, pos) + "»" + str.subSequence(pos, str.length()); } /* Arrays */ diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java index 10631eb..4ce0ae8 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -165,7 +165,7 @@ public String format(Number num) /** * @param str | Source char sequence with number to parse. * @param ch0 | Should be str.charAt(0). This is to ensure that string is not null or empty and also for possible optimizations. - * @param end | Index of where to end with parsing. If whole string is meant to be parsed, then str.length()-1, should not be greater than that! + * @param end | Index of where to end with parsing (inclusive). If whole string is meant to be parsed, then str.length()-1, should not be greater than that! * @param base | Base of the parsed number. Theoretically can be anything but usually should be 2, 8, 10 or 16... Note that base will be overridden by suffixes #. for 16, 0x for 16, 0b for 2 or 0 for 8 (only if not followed by .). * @param type | Preferred datatype of of the number represented by suffixes 'S' for {@link Short}, 'Y' for {@link Byte}, 'L' for {@link Long}, 'D' for {@link Double}, 'F' for {@link Float}. Other stands for {@link Integer}.
* Note that floating point numberer will be treated as {@link Double} if no suffix is present by default. Also numbers in E-notation format with negative exponents can be converted to {@link Double}. Further more, integers will be auto-converted to {@link Long} if overflow should occur!
diff --git a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java index 5d5cc77..bc7e8e0 100644 --- a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java +++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java @@ -114,8 +114,8 @@ public Object parse(String str, boolean returnAsStringIfNotFound, Class>\t\"" + str + "\"\t -->\t" + SerializationDebugger.toStringAndCls(obj)); return obj; } - } - catch (Exception ex) - { - iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " (from cache)\n>>\t\"" + str + "\"\tthrew\t" + ex); - return null; - } +// } +// catch (Exception ex) +// { +// iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + " (from cache)\n>>\t\"" + str + "\"\tthrew\t" + ex); +// return null; +// } } } @@ -139,8 +139,8 @@ public Object parse(String str, boolean returnAsStringIfNotFound, Class>\t\"" + str + "\"\t -->\t" + SerializationDebugger.toStringAndCls(obj)); return obj; } - } - catch (Exception ex) - { - iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + "\n>>\t\"" + str + "\"\tthrew\t" + ex); - return null; - } +// } +// catch (Exception ex) +// { +// iterationStackTrace.put(iterationIndex, "[" + i + "] " + parser + "\n>>\t\"" + str + "\"\tthrew\t" + ex); +// return null; +// } } if (returnAsStringIfNotFound) diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index 57a19f9..939f75e 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -408,8 +408,8 @@ public S LoadFrom(Reader reader, Object... args) if (args[3] == null) args[3] = getProtocols(); - String str = readAndFormat(reader, formatRequired); - List objs = splitAndParse(str, 0, args); + StringBuilder str = readAndFormat(reader, formatRequired); + List objs = splitAndParse(str, args); addAll(objs); //double t0 = System.nanoTime(); @@ -504,7 +504,7 @@ else if (ch == '}' || ch == ']') * * @since 1.3.2 */ - protected String readAndFormat(Reader reader, boolean format) + protected StringBuilder readAndFormat(Reader reader, boolean format) { int quote = 0, multLineCom = -1; //int brackets = 0, lastIndex = 0, delChars = 0; @@ -581,7 +581,7 @@ else if (ch == '}' || ch == ']') e.printStackTrace(); } - return sb.toString(); + return sb; } /** @@ -589,16 +589,16 @@ else if (ch == '}' || ch == ']') * * @since 1.3.2 */ - protected List splitAndParse(String formattedStr, int offset, Object... parserArgs) + protected List splitAndParse(StringBuilder formattedStr, Object... parserArgs) { List result = new ArrayList<>(); ParserRegistry reg = getParsers(); //DataParser[] parsers = new DataParser[DataParser.REGISTRY.size()]; - int brackets = 0, quote = 0, lastIndex = 0; + int brackets = 0, quote = 0, lastIndex = 0, len = formattedStr.length(); //boolean isBracketSplit = false; - for (int i = 0, len = formattedStr.length(); i < len; i++) + for (int i = 0; i < len; i++) { char ch = formattedStr.charAt(i); if (ch == '"') @@ -611,8 +611,8 @@ protected List splitAndParse(String formattedStr, int offset, Object... isBracketSplit = false;*/ if (brackets == 0 && (ch == ';' || ch == ',')/* || (brackets == 1 && (isBracketSplit = ch == '}' || ch == ']'))*/) { - String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i /*+ (isBracketSplit ? 1 : 0)*/); - if (!(str = str.trim()).isEmpty()) + String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i /*+ (isBracketSplit ? 1 : 0)*/).trim(); + if (!str.isEmpty()) { Object obj = parseObject(reg, str, parserArgs); if (obj != VOID) @@ -638,8 +638,8 @@ else if (brackets > 0) throw new IllegalArgumentException("Unclosed brackets in: " + formattedStr); else { - String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, formattedStr.length()); - if (!(str = str.trim()).isEmpty()) + String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, len).trim(); + if (!str.isEmpty()) { Object obj = parseObject(reg, str, parserArgs); if (obj != VOID) @@ -704,7 +704,7 @@ public T cloneOf(String variableName) */ public T cloneOf(String variableName, T defaultValue) { - T obj = get(variableName , defaultValue); + T obj = get(variableName, defaultValue); if (obj == defaultValue) return defaultValue; return Clone(obj, getParsers(), new Object[] {-99999, 0, this, getProtocols(), isGenerateComments()}, this, null, null, getProtocols()); diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java index b3cc5fd..91b4a9d 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -1,11 +1,7 @@ package org.ugp.serialx.converters.operators; import static java.util.Arrays.asList; -import static org.ugp.serialx.Utils.fastReplace; -import static org.ugp.serialx.Utils.fromAmbiguousArray; -import static org.ugp.serialx.Utils.isOneOf; -import static org.ugp.serialx.Utils.mergeArrays; -import static org.ugp.serialx.Utils.multilpy; +import static org.ugp.serialx.Utils.*; import java.util.ArrayList; import java.util.Collection; @@ -26,96 +22,108 @@ */ public class ArithmeticOperators implements DataParser { -// protected String[] priority1Oprs = {"*", "*-", "/", "/-", "%"}, priority2Oprs = {"**", "**-"}; - - @Override - public Object parse(ParserRegistry myHomeRegistry, String s, Object... args) - { - if (s.length() > 2 && isExpression(s, '+', '-', '*', '/', '%')) - return eval(myHomeRegistry, s, args); - return CONTINUE; - } + /** + * @deprecated DO NOT USE! USE {@link ArithmeticOperators#evalOperator(Object, String, Object)} AND {@link ArithmeticOperators#getOperatorPriority(String)} INSTEAD! + */ + @Deprecated + protected String[] priority1Oprs = {"*", "*-", "/", "/-", "%"}, priority2Oprs = {"**", "**-"}; /** - * @return Result of evaluated expression that was inserted! For instance 5 + 5, result 10! + * Operator characters recognized by {@link ArithmeticOperators}, operators can be any combination of provided characters. Exact behavior is handled by {@link ArithmeticOperators#operator(Object, String, Object)}.
Intended for override, should not be null or empty! * - * @since 1.3.0 + * @since 1.3.7 */ + protected char[] operators = {'+', '-', '*', '/', '%'}; + @SuppressWarnings("unchecked") - protected Object eval(ParserRegistry registryForParsers, String expr, Object... argsForParsers) + @Override + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { - while (expr.contains("++") || expr.contains("--") || expr.contains("+-") || expr.contains("-+")) - expr = fastReplace(fastReplace(fastReplace(fastReplace(expr, "-+", "-"), "+-", "-"), "--", "+"), "++", "+"); + int len; + if ((len = str.length()) > 2 && isExpression(str, len, operators)) + { + for (int i; (i = indexOfNotInObj(str, 0, len, len, true, '+', '-')+1) < len && isOneOf(str.charAt(i), '+', '-'); ) // Handle duplicates of [+-]{2} + str = fastReplace(fastReplace(fastReplace(fastReplace(str, "-+", "-"), "+-", "-"), "--", "+"), "++", "+"); - List[] terms = getAndParseTerms(expr, registryForParsers, argsForParsers, getClass(), '+', '-', '*', '/', '%'); - ArrayList cofs = (ArrayList) terms[0]; - if (cofs.size() <= 1) - return cofs.get(0); - LinkedList oprs = (LinkedList) terms[1]; + List[] terms = getAndParseTerms(str, myHomeRegistry, args, getClass(), operators); + ArrayList cofs = (ArrayList) terms[0]; + if (cofs.size() <= 1) + return cofs.get(0); + LinkedList oprs = (LinkedList) terms[1]; - Object cof1 = null, cof2 = null; - String opr = null; - try - { - for (int i = 0, index = 0, oprsSize = oprs.size(), currentOpPrio = 2; i < oprsSize; index = 0, i++) + String op = null; + int index = 1; + try { - opPrioCheck: //Yes yes... this is quite a shenanigan but it is fast... - { - for (; currentOpPrio > 0; currentOpPrio--) + for (int opPrio = 2; opPrio > 0; opPrio--) + for (ListIterator iter = oprs.listIterator(); iter.hasNext(); ) { - for (ListIterator iter = oprs.listIterator(); iter.hasNext();) + if (getOperatorPriority(op = iter.next()) == opPrio) { - if (getOperatorPriority(opr = iter.next()) == currentOpPrio) - { - iter.remove(); - index = iter.nextIndex(); - break opPrioCheck; - } + iter.remove(); + cofs.set(index = iter.nextIndex(), operator(cofs.get(index), op, cofs.remove(index + 1))); } - opr = null; } - opr = oprs.poll(); //opr = null; - } - - cof1 = cofs.get(index); - cof2 = cofs.remove(index + 1); - - switch (opr.charAt(0)) - { - case '+': - cofs.set(index, addOperator(cof1, cof2)); break; - case '-': - cofs.set(index, subOperator(cof1, cof2)); break; - case '*': - if (opr.length() > 1 && opr.charAt(1) == '*') - { - cofs.set(index, powOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1)); break; - } - cofs.set(index, multOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1)); break; - case '/': - cofs.set(index, divOperator(cof1, cof2, opr.endsWith("-") ? -1 : 1)); break; - case '%': - cofs.set(index, modOperator(cof1, cof2)); break; - } + + for (index = 1; (op = oprs.poll()) != null; ) + cofs.set(0, operator(cofs.get(0), op, cofs.get(index++))); } + catch (ClassCastException ex) + { + LogProvider.instance.logErr("Arithmetic operator " + op + " is undefined between provided operands because " + ex.getMessage() + "!", ex); + } + catch (IndexOutOfBoundsException ex) + { + LogProvider.instance.logErr("Missing operand in \"" + str + "\"!", null); + } + catch (ArithmeticException ex) + { + LogProvider.instance.logErr(ex.getMessage(), ex); + } + + return cofs.get(0); } - catch (ClassCastException ex) - { - LogProvider.instance.logErr("Arithmetic operator " + opr + " is undefined between " + cof1.getClass().getName() + " and " + cof2.getClass().getName() + "!", ex); - } - catch (IndexOutOfBoundsException ex) - { - LogProvider.instance.logErr("Missing coefficient in \"" + expr + "\"!", null); - } - catch (ArithmeticException ex) + return CONTINUE; + } + + /** + * @param opr1 | Operand 1 + * @param op | The operator/operation + * @param opr2 | Operand 2 + * + * @return Result of binary operation described by op between opr1 and opr2! If operator is not known, opr1 will be returned by default! + * + * @since 1.3.7 + */ + public Object operator(Object opr1, String op, Object opr2) + { +// System.err.println(opr1 + op + opr2); + switch (op.charAt(0)) { - LogProvider.instance.logErr(ex.getMessage(), ex); + case '+': + return addOperator(opr1, opr2); + case '-': + return subOperator(opr1, opr2); + case '*': + if (op.length() > 1 && op.charAt(1) == '*') + return powOperator(opr1, opr2, op.endsWith("-") ? -1 : 1); + return multOperator(opr1, opr2, op.endsWith("-") ? -1 : 1); + case '/': + return divOperator(opr1, opr2, op.endsWith("-") ? -1 : 1); + case '%': + return modOperator(opr1, opr2); } - - return cofs.get(0); + return opr1; } - public int getOperatorPriority(String op) + /** + * @param op | The operator/operation + * + * @return Priority of provided operator (higher number = higher priority, 2 = high, 1 = medium, 0 = low) + * + * @since 1.3.7 + */ + public byte getOperatorPriority(String op) { switch (op.charAt(0)) { @@ -360,28 +368,27 @@ public static Object mod(Object cof, Object cof2) */ public static Object pow(Object cof, Object cof2, int sign) { - if (cof instanceof Number && cof2 instanceof Number) - { - double pow = Math.pow(((Number) cof).doubleValue(), ((Number) cof2).doubleValue() * sign); - if (pow > Long.MAX_VALUE || pow < Long.MIN_VALUE || cof instanceof Double || cof2 instanceof Double) - return pow; - else if (pow <= Float.MAX_VALUE && pow >= Float.MIN_VALUE && (cof instanceof Float || cof2 instanceof Float)) - return (float) pow; - - if (pow > Integer.MAX_VALUE || pow < Integer.MIN_VALUE || cof instanceof Long || cof2 instanceof Long) - return (long) pow; - else if (cof instanceof Integer || cof2 instanceof Integer) - return (int) pow; - } - return null; + double pow = Math.pow(((Number) cof).doubleValue(), ((Number) cof2).doubleValue() * sign); + if (pow > Long.MAX_VALUE || pow < Long.MIN_VALUE || cof instanceof Double || cof2 instanceof Double) + return pow; + if (pow <= Float.MAX_VALUE && pow >= Float.MIN_VALUE && (cof instanceof Float || cof2 instanceof Float)) + return (float) pow; + + if (pow > Integer.MAX_VALUE || pow < Integer.MIN_VALUE || cof instanceof Long || cof2 instanceof Long) + return (long) pow; + if (cof instanceof Integer || cof2 instanceof Integer) + return (int) pow; + return pow; } - + /** - * * @param str | String to split! - * @param oprs | Operators to use as a splitters. + * @param registryForParsers | Registry to use for parsing operands! + * @param argsForParsers | Arguments for the parse method! + * @param classToIgnore | Parser to ignore (should be class of the caller if possible)! + * @param oprs | Operators to use as a splitters. 1 or more of these in row will be used as delimiter! * - * @return List of terms splitted according to inserted arguments! For example getTerm("5 + 6", true, '+') will return [+], while getTerm("5 + 6", false, '+') will return [5, 6]! + * @return Array with 2 lists. Index 0 is {@link ArrayList} containing parsed operands of the expression, index 1 is {@link LinkedList} containing operators of the expression! * * @since 1.3.7 (originally getTerms since 1.3.0) */ @@ -390,17 +397,8 @@ public static List[] getAndParseTerms(String str, ParserRegistry registryForP { List[] ret = new List[] {new ArrayList(), new LinkedList()}; //cofs, ops - StringBuilder[] sbs = {new StringBuilder(), new StringBuilder()}; //cofs, ops TODO - - int i = 0, type = 0, len = str.length(); - for (; i < len; i++) //in case of start cof sign - { - char ch = str.charAt(i); - if (isOneOf(ch, oprs)) - sbs[0].append(ch); - else - break; - } + int i = 0, startIndex = 0, type = 0, len = str.length(); + for (; i < len && isOneOf(str.charAt(i), oprs); i++); //in case of start cof sign for (int quote = 0, brackets = 0, lastType = type; i < len; i++) { @@ -416,39 +414,38 @@ else if ((ch | ' ') == '}') { if ((type = isOneOf(ch, oprs) ? 1 : 0) != lastType) { - String s = sbs[lastType].toString().trim(); + String s = str.substring(startIndex, i).trim(); if (!s.isEmpty()) ret[lastType].add(lastType == 0 ? registryForParsers.parse(s, false, classToIgnore, argsForParsers) : s); - sbs[lastType] = new StringBuilder(); + startIndex = i; } else type = lastType; } - - sbs[lastType = type].append(ch); - } - - if (sbs[type].length() > 0) - { - String s = sbs[type].toString().trim(); - if (!s.isEmpty()) - ret[type].add(type == 0 ? registryForParsers.parse(s, false, classToIgnore, argsForParsers) : s); + + lastType = type; } + + String s = str.substring(startIndex, len).trim(); + if (!s.isEmpty()) + ret[type].add(type == 0 ? registryForParsers.parse(s, false, classToIgnore, argsForParsers) : s); +// System.err.println(ret[0] + "\n" + ret[1] + "\n"); return ret; } /** * @param str | String that might be an expression! + * @param to | Ending index of checking, exclusive (should be str.length())! * @param operators | Operators that str must have! * * @return True if inserted string is expression with any coefficients splitted by operators! * * @since 1.3.2 */ - public static boolean isExpression(CharSequence str, char... operators) + public static boolean isExpression(CharSequence str, int to, char... operators) { int hasOpr = -1; - for (int i = 0, len = str.length(), oldCh = 0, isCof = 0, quote = 0, brackets = 0; i < len; i++) + for (int i = 0, oldCh = 0, isCof = 0, quote = 0, brackets = 0; i < to; i++) { char ch = str.charAt(i); if (ch > 32) diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java index b60d778..39a34d7 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java @@ -29,7 +29,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) return CONTINUE; int index, op; - if ((index = indexOfNotInObj(str, '<', '>', '=')) > -1) + if ((index = indexOfNotInObj(str, 0, len, -1, true, '<', '>', '=')) > -1) { if ((op = str.charAt(index)) != '=') // > < { diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java index 5e60f17..be0cbcd 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/LogicalOperators.java @@ -3,7 +3,9 @@ import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static org.ugp.serialx.Utils.indexOfNotInObj; +import static org.ugp.serialx.Utils.multilpy; +import org.ugp.serialx.LogProvider; import org.ugp.serialx.converters.DataParser; /** @@ -16,47 +18,59 @@ public class LogicalOperators implements DataParser { @Override - public Object parse(ParserRegistry myHomeRegistry, String s, Object... args) + public Object parse(ParserRegistry myHomeRegistry, String s, Object... args) { int len; if ((len = s.length()) < 3) return CONTINUE; Object result = CONTINUE; - int i = 0, index; - do + int i = 0, index, op = 0, nextOpIndex; + try { - if ((index = indexOfNotInObj(s, i, len, true, '&', '|', '^')) == -1) - return result; - - int op; - if ((op = s.charAt(i = index)) != '^' && (++i >= len || s.charAt(i) != op)) // Ensure && and || and refuse & and | - continue; - - if (result == CONTINUE) // Beginning - result = myHomeRegistry.parse(s.substring(0, index).trim(), args); - - int nextOpIndex; - if ((nextOpIndex = indexOfNotInObj(s, ++i, len, true, '&', '|', '^')) == -1) - nextOpIndex = len; - - if (op == '&') + do { - if (!FALSE.equals(result)) + if ((index = indexOfNotInObj(s, i, len, -1, true, '&', '|', '^')) == -1) + return result; //CONTINUE; + if ((op = s.charAt(i = index)) != '^' && (++i >= len || s.charAt(i) != op)) // Ensure && and || and refuse & and | + continue; + + if (result == CONTINUE) // Beginning + result = myHomeRegistry.parse(s.substring(0, index).trim(), args); + + if (op == '|') + { + if (TRUE.equals(result)) + return TRUE; + + nextOpIndex = indexOfNotInObj(s, ++i, len, len, true, '&', '|', '^'); + result = orOperator(result, myHomeRegistry.parse(s.substring(i, nextOpIndex).trim(), args)); + } + else if (op == '&') + { + if (FALSE.equals(result)) + { + i = indexOfNotInObj(s, ++i, len, len, true, '|', '^'); + continue; + } + + nextOpIndex = indexOfNotInObj(s, ++i, len, len, true, '&', '|', '^'); result = andOperator(result, myHomeRegistry.parse(s.substring(i, nextOpIndex).trim(), args)); + } + else + { + nextOpIndex = indexOfNotInObj(s, ++i, len, len, true, '&', '|', '^'); + result = xorOperator(result, myHomeRegistry.parse(s.substring(i, nextOpIndex).trim(), args)); + } + + i = nextOpIndex; } - else if (op == '|') - { - if (TRUE.equals(result)) - return TRUE; - result = orOperator(result, myHomeRegistry.parse(s.substring(i, nextOpIndex).trim(), args)); - } - else - result = xorOperator(result, myHomeRegistry.parse(s.substring(i, nextOpIndex).trim(), args)); - - i = nextOpIndex; + while (i < len); + } + catch (ClassCastException ex) + { + LogProvider.instance.logErr("Logical operator " + multilpy((char) op, op != '^' ? 2 : 1) + " is undefined between provided operands because " + ex.getMessage() + "!", ex); } - while (i < len); return result; } @@ -99,19 +113,21 @@ public Object xorOperator(Object obj1, Object obj2) public static Object toBool(Object obj) { if (obj == null) - return false; + return FALSE; if (obj instanceof Number) return ((Number) obj).doubleValue() != 0; if (obj instanceof Character) return (char) obj != 0; - /*if (obj instanceof Map) - return !((Map) obj).isEmpty(); - if (obj instanceof Collection) - return !((Collection) obj).isEmpty(); - if (obj instanceof Scope) - return !((Scope) obj).isEmpty(); - if (obj.getClass().isArray()) - return Array.getLength(obj) > 0;*/ +// if (obj instanceof CharSequence) +// return ((CharSequence) obj).length() > 0; +// if (obj instanceof Map) +// return !((Map) obj).isEmpty(); +// if (obj instanceof Collection) +// return !((Collection) obj).isEmpty(); +// if (obj instanceof Scope) +// return !((Scope) obj).isEmpty(); +// if (obj.getClass().isArray()) +// return Array.getLength(obj) > 0; return obj; } } \ No newline at end of file From bea917d93261385ad2a43e6df85aee79126303b6 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Fri, 12 Jul 2024 21:59:42 +0200 Subject: [PATCH 31/48] fixing bugs and doing small optim --- .../java/org/ugp/serialx/GenericScope.java | 4 ++-- .../main/java/org/ugp/serialx/Serializer.java | 10 +++++++++ .../ugp/serialx/converters/DataParser.java | 2 +- .../serialx/converters/NumberConverter.java | 4 ++-- .../juss/converters/VariableConverter.java | 2 +- .../operators/ArithmeticOperators.java | 21 ++++++++++++------- .../operators/NegationOperator.java | 17 +++++++-------- 7 files changed, 37 insertions(+), 23 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index 359e51d..7f0fb21 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -1024,7 +1024,7 @@ public static GenericScope newBidirectional(Map variablesMap, * * @since 1.3.5 */ - public static GenericScope intoBidirectional(GenericScope scopeToMakeBidirectional, Map variablesMap, List values) + public static > S intoBidirectional(S scopeToMakeBidirectional, Map variablesMap, List values) { return intoBidirectional(scopeToMakeBidirectional, variablesMap, values, null); } @@ -1039,7 +1039,7 @@ public static GenericScope intoBidirectional(GenericScope sco * * @since 1.3.5 */ - public static GenericScope intoBidirectional(GenericScope scopeToMakeBidirectional, Map variablesMap, List values, GenericScope parent) + public static > S intoBidirectional(S scopeToMakeBidirectional, Map variablesMap, List values, GenericScope parent) { scopeToMakeBidirectional.variables = variablesMap; scopeToMakeBidirectional.values = values; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 8b0fc6b..a5bc254 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -164,6 +164,16 @@ public T toObject(Class objClass) throws Exception return toObject(objClass, getProtocols()); } + @SuppressWarnings("unchecked") + @Override + public GenericScope transform(Function trans, boolean includeSubScopes) + { + Serializer transformed = (Serializer) super.transform(trans, includeSubScopes); + transformed.parsers = getParsers(); + transformed.protocols = getProtocols(); + return (GenericScope) transformed; + } + /** * @see Serializer#into(Object, Serializer, String...) */ diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index e55a673..59a1be7 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -45,7 +45,7 @@ public interface DataParser /** * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! - * @param str | Source string! + * @param str | Source string, preferably trimed! * @param args | Some additional args. This can be anything and it demands on implementation of DataParser. Default SerialX API implementation will provide one optional argument with {@link Scope} that value was loaded from! * * @return Object that was parsed from obtained string. Special return types are {@link DataParser#VOID} and {@link DataParser#CONTINUE}. Continue will ignore this parser and jump to another one in registry. diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java index 4ce0ae8..e873476 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -112,8 +112,8 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) int len; if ((len = arg.length()) > 0) { - char ch0 = arg.charAt(0); - if (ch0 == '+' || ch0 == '-' || ch0 == '.' || (ch0 >= '0' && ch0 <= '9')) + char ch0; + if ((ch0 = arg.charAt(0)) >= '0' && ch0 <= '9' || (ch0 == '+' || ch0 == '-' || ch0 == '.') && len > 1 && arg.charAt(1) > '*') { Number num; if ((num = numberOf(arg, ch0, --len, 10, 0)) != null) diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index 7e0038c..9d281e1 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -69,7 +69,7 @@ public Object parse(ParserRegistry myHomeRegistry, String arg, Object... args) op0Index--; } - String vars[] = splitValues(arg, op0Index, 0, 1, new char[] {'?'}, '=', ':'), valStr; + String vars[] = splitValues(arg, op0Index, 0, 1, new char[] {'?', '<', '>', '!'}, '=', ':'), valStr; Object val = null; int iVal = vars.length-1; diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java index 91b4a9d..62f7bf7 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -42,10 +42,14 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) int len; if ((len = str.length()) > 2 && isExpression(str, len, operators)) { - for (int i; (i = indexOfNotInObj(str, 0, len, len, true, '+', '-')+1) < len && isOneOf(str.charAt(i), '+', '-'); ) // Handle duplicates of [+-]{2} - str = fastReplace(fastReplace(fastReplace(fastReplace(str, "-+", "-"), "+-", "-"), "--", "+"), "++", "+"); + for (int i = 0; i < len; ) // Format duplicates of [+-]{2} + if (isOneOf(str.charAt(i++), '+', '-') && i < len && isOneOf(str.charAt(i), '+', '-')) + { + len = (str = fastReplace(fastReplace(fastReplace(fastReplace(str, "-+", "-"), "+-", "-"), "--", "+"), "++", "+")).length(); + i--; + } - List[] terms = getAndParseTerms(str, myHomeRegistry, args, getClass(), operators); + List[] terms = getAndParseTerms(str, len, myHomeRegistry, args, getClass(), operators); ArrayList cofs = (ArrayList) terms[0]; if (cofs.size() <= 1) return cofs.get(0); @@ -383,6 +387,7 @@ public static Object pow(Object cof, Object cof2, int sign) /** * @param str | String to split! + * @param to | Ending index of parsing, exclusive. Everything from this index to the end will be ignored (should be str.length())! * @param registryForParsers | Registry to use for parsing operands! * @param argsForParsers | Arguments for the parse method! * @param classToIgnore | Parser to ignore (should be class of the caller if possible)! @@ -393,14 +398,14 @@ public static Object pow(Object cof, Object cof2, int sign) * @since 1.3.7 (originally getTerms since 1.3.0) */ @SuppressWarnings("unchecked") - public static List[] getAndParseTerms(String str, ParserRegistry registryForParsers, Object[] argsForParsers, Class classToIgnore, char... oprs) + public static List[] getAndParseTerms(String str, int to, ParserRegistry registryForParsers, Object[] argsForParsers, Class classToIgnore, char... oprs) { List[] ret = new List[] {new ArrayList(), new LinkedList()}; //cofs, ops - int i = 0, startIndex = 0, type = 0, len = str.length(); - for (; i < len && isOneOf(str.charAt(i), oprs); i++); //in case of start cof sign + int i = 0, startIndex = 0, type = 0; + for (; i < to && isOneOf(str.charAt(i), oprs); i++); //in case of start cof sign - for (int quote = 0, brackets = 0, lastType = type; i < len; i++) + for (int quote = 0, brackets = 0, lastType = type; i < to; i++) { char ch = str.charAt(i); if (ch == '\"') @@ -426,7 +431,7 @@ else if ((ch | ' ') == '}') lastType = type; } - String s = str.substring(startIndex, len).trim(); + String s = str.substring(startIndex, to).trim(); if (!s.isEmpty()) ret[type].add(type == 0 ? registryForParsers.parse(s, false, classToIgnore, argsForParsers) : s); // System.err.println(ret[0] + "\n" + ret[1] + "\n"); diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java index f644357..99f6702 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java @@ -16,20 +16,19 @@ public class NegationOperator implements DataParser @Override public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { - int ch, len = str.length(); - if (len > 0 && ((ch = str.charAt(0)) == '!' || ch == '-')) + int len, type; + if ((len = str.length()) < 2) + return CONTINUE; + if ((type = str.charAt(0)) == '!' || type == '-') { int negCount = 1; - for (int i = negCount; i < len; i++) - if ((ch = str.charAt(i)) == '!' || ch == '-') - negCount++; - else - break; + for (int ch; negCount < len && ((ch = str.charAt(negCount)) == '!' || ch == '-'); negCount++); - Object obj = myHomeRegistry.parse(str.substring(negCount), args); + Object obj = myHomeRegistry.parse(str.substring(negCount).trim(), false, getClass(), args); if (negCount % 2 == 0) return obj; - Object neg = ch == '!' ? logicalNotOperator(obj) : notOperator(obj); + + Object neg = type == '!' ? logicalNotOperator(obj) : notOperator(obj); if (obj == neg && !(obj instanceof Number && ((Number) obj).intValue() == 0)) LogProvider.instance.logErr("Unable to nagete \"" + obj + "\" because object of \"" + obj.getClass().getName() + "\" cant be negated!", null); return neg; From a644ba6c7a6a2dbc26eff5f673ae62b67276baac Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Fri, 19 Jul 2024 22:21:30 +0200 Subject: [PATCH 32/48] fixing some Json related bugs, small refactoring, intoNew can now handle generics in some cases, and AutoProt and UniversalProt/SelfSerial can too. This greatly increases the Json capabilities. --- .../java/org/ugp/serialx/GenericScope.java | 127 +++--- .../src/main/java/org/ugp/serialx/Scope.java | 374 ++++++++++++------ .../main/java/org/ugp/serialx/Serializer.java | 12 +- .../ugp/serialx/converters/DataParser.java | 2 +- .../org/ugp/serialx/json/JsonSerializer.java | 2 + .../json/converters/JsonObjectConverter.java | 15 +- .../serialx/juss/protocols/AutoProtocol.java | 60 +-- .../UniversalObjectInstantiationProtocol.java | 41 +- 8 files changed, 429 insertions(+), 204 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index 7f0fb21..49aa640 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -3,6 +3,7 @@ import static org.ugp.serialx.Utils.Instantiate; import java.io.Serializable; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -273,8 +274,8 @@ public V get(KeyT variableKey) @SuppressWarnings("unchecked") public V get(KeyT variableKey, V defaultValue) { - V obj = (V) variables().get(variableKey); - if (obj == null) + V obj; + if ((obj = (V) variables().get(variableKey)) == null) return defaultValue; return obj; } @@ -342,7 +343,7 @@ public V get(KeyT... pathToValue) * * @since 1.3.7 */ - public V get(KeyT variableKey, Class cls, V defaultValue) throws Exception + public V get(KeyT variableKey, Class cls, V defaultValue) throws Exception { V obj = get(variableKey, defaultValue); if (obj != null && obj.getClass() == cls) @@ -477,7 +478,7 @@ public boolean addAll(@SuppressWarnings("unchecked") ValT... values) * @since 1.3.7 */ @Override - public boolean containsAll(Collection values) + public boolean containsAll(Collection values) { return values().containsAll(values); } @@ -550,36 +551,41 @@ public GenericScope getGenericScope(K... pathToScope) } /** - * @param objClass | Object of class to create. + * @param type | Class of object to create (may or may not support other implementations of {@link Type}). * - * @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}! + * @return Object of type constructed from this scopes independent values using protocol for given class or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}! * * @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! * * @since 1.2.5 */ - public T toObject(Class objClass) throws Exception + public T toObject(Type type) throws Exception { - return toObject(objClass, SerializationProtocol.REGISTRY); + return toObject(type, SerializationProtocol.REGISTRY); } /** - * @param objClass | Object of class to create using protocols. + * @param type | Class of object to create using protocols (may or may not support other implementations of {@link Type}). * @param protocolsToUse | Registry of protocols to use. * - * @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}! + * @return Object of class constructed from this scopes independent values using protocol for given class or null if there was no protocol found in protocolsToUse! * * @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! * * @since 1.3.2 */ - public T toObject(Class objClass, ProtocolRegistry protocolsToUse) throws Exception + @SuppressWarnings("unchecked") + public T toObject(Type type, ProtocolRegistry protocolsToUse) throws Exception { - SerializationProtocol pro = protocolsToUse == null ? null : protocolsToUse.GetProtocolFor(objClass, SerializationProtocol.MODE_DESERIALIZE); - if (pro != null) + if (protocolsToUse == null) + return null; + + Class objClass; + SerializationProtocol pro; + if ((pro = protocolsToUse.GetProtocolFor(objClass = (Class) type, SerializationProtocol.MODE_DESERIALIZE)) != null) { - T obj = pro.unserialize(objClass, this.variablesCount() > 0 ? new Object[] {this} : this.toArray()); - if (obj != null) + T obj; + if ((obj = pro.unserialize(objClass, variablesCount() > 0 ? new Object[] {this} : toArray())) != null) return obj; } return null; @@ -588,7 +594,7 @@ public T toObject(Class objClass, ProtocolRegistry protocolsToUse) throws /** * @param predicate | Predicate object with filter condition in test method! * - * @return Original scope after filtration using inserted predicate! If some object can't be casted to {@link Predicate#test(Object)} argument, it will be treated as invalid and will be filtered away! Sub-scopes are not included! + * @return Scope after filtration using inserted predicate! If some object can't be casted to {@link Predicate#test(Object)} argument, it will be treated as invalid and will be filtered away! Sub-scopes are not included! * * @since 1.2.5 */ @@ -603,14 +609,14 @@ public GenericScope filter(Predicate predicate) * If sub-scope is empty after filtration it will not be included in result! * Note: Remember that this will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope})! * - * @return Original scope after filtration using inserted predicate! If some object can't be casted to {@link Predicate#test(Object)} argument, it will be treated as invalid and will be filtered away! + * @return Scope after filtration using inserted predicate! If some object can't be casted to {@link Predicate#test(Object)} argument, it will be treated as invalid and will be filtered away! * * @since 1.2.5 */ @SuppressWarnings("unchecked") public GenericScope filter(Predicate predicate, boolean includeSubScopes) { - return (GenericScope) transform(new Function() + return (GenericScope) transform(new Function() { @Override public Object apply(ValT t) @@ -623,7 +629,7 @@ public Object apply(ValT t) /** * @param trans | Function to transform objects of this scope! * - * @return Original scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! Sub-scopes are not included! + * @return Scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! Sub-scopes are not included! * * @since 1.2.5 */ @@ -638,7 +644,7 @@ public GenericScope transform(Function trans) * If sub-scope is empty after transformation it will not be included in result! * Note: Remember that this will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope})! * - * @return Original scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! + * @return Scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! * * @since 1.2.5 */ @@ -648,41 +654,40 @@ public GenericScope transform(Function trans, boolean incl if (trans == null || isEmpty()) return (GenericScope) this; - List fltVals = map(trans, includeSubScopes); - LinkedHashMap fltVars = new LinkedHashMap<>(); - + LinkedHashMap mappedVars = new LinkedHashMap<>(); for (Entry ent : this.varEntrySet()) try { Object obj = ent.getValue(); - if (obj instanceof GenericScope && includeSubScopes) + if (includeSubScopes && obj instanceof GenericScope) { GenericScope sc = ((GenericScope) obj).transform(trans, includeSubScopes); if (!sc.isEmpty()) - fltVars.put(ent.getKey(), (V) sc); + mappedVars.put(ent.getKey(), (V) sc); } else if ((obj = trans.apply((ValT) obj)) != DataParser.VOID) - fltVars.put(ent.getKey(), trans.apply((ValT) obj)); + mappedVars.put(ent.getKey(), trans.apply((ValT) obj)); } catch (ClassCastException e) {} - try + List mappedVals = map(trans, includeSubScopes); + try { GenericScope clone = Instantiate(getClass()); - clone.values = fltVals; - clone.variables = fltVars; + clone.values = mappedVals; + clone.variables = mappedVars; clone.parent = getParent(); return clone; } catch (Exception e) { - return new GenericScope<>(fltVars, fltVals, getParent()); + return new GenericScope<>(mappedVars, mappedVals, getParent()); } } /** - * @param trans | Function to transform objects of this scope! + * @param trans | Function to transform independent objects of this scope! * * @return Original scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! * @@ -694,7 +699,7 @@ public List map(Function trans) } /** - * @param trans | Function to transform objects of this scope! + * @param trans | Function to transform independent objects of this scope! * @param includeSubScopes | If true transformation will be also applied on sub-scopes, if false sub-scopes will be treated as other things (parsed in to {@link Function#apply(Object)}). * If sub-scope is empty after transformation it will not be included in result! * Note: Remember that this will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope})! @@ -706,23 +711,50 @@ public List map(Function trans) @SuppressWarnings("unchecked") public List map(Function trans, boolean includeSubScopes) { - List fltVals = new ArrayList<>(); - for (Object obj : this) +// List mapped = new ArrayList<>(size()); +// for (Object obj : this) +// try +// { +// if (obj instanceof GenericScope && includeSubScopes) +// { +// GenericScope sc = (GenericScope) ((GenericScope) obj).map(trans, includeSubScopes); +// if (!sc.isEmpty()) +// mapped.add((V) sc); +// } +// else if ((obj = trans.apply((ValT) obj)) != DataParser.VOID) +// mapped.add((V) obj); +// } +// catch (ClassCastException e) +// {} + + List mapped = (List) toValList(); + for (int i = valuesCount()-1; i >= 0; i--) + { try { - if (obj instanceof GenericScope && includeSubScopes) + Object obj = mapped.get(i); + if (includeSubScopes && obj instanceof GenericScope) { - GenericScope sc = ((GenericScope) obj).transform(trans, includeSubScopes); + GenericScope sc = (GenericScope) ((GenericScope) obj).map(trans, includeSubScopes); if (!sc.isEmpty()) - fltVals.add((V) sc); + { + mapped.set(i, (V) sc); + continue; + } } else if ((obj = trans.apply((ValT) obj)) != DataParser.VOID) - fltVals.add((V) obj); + { + mapped.set(i, (V) obj); + continue; + } } - catch (ClassCastException e) + catch (ClassCastException e) {} + + mapped.remove(i); + } - return fltVals; + return mapped; } /** @@ -857,13 +889,14 @@ public boolean isEmpty() } /** - * @return The parent scope of this scope or null if this scope has no parent such as default one in file. + * @return The parent scope of this scope or null if this scope has no parent such as default one in file.
+ * Note: This may or may not be always null based on the way this scope was instantiated... * * @since 1.2.0 */ public > T getParent() { - return getParent(1); + return getParent(1); } /** @@ -871,7 +904,8 @@ public boolean isEmpty() * If you want to get the root parent (the one that has no parent), simply put a big number as depth. 99 should be enough! * * @return The parent scope based on depth or null if this scope has no parent which means its already root (default one in file). - * If depth was bigger than 1, null will be never returned, last not null parent will be returned instead!
+ * If depth was bigger than 1, null will not be returned, last not null parent will be returned instead!
+ * Note: This may or may not be always null based on the way this scope was instantiated... * * @since 1.3.2 */ @@ -888,7 +922,7 @@ public boolean isEmpty() } /** - * @return New {@link LinkedHashMap} with variables of this a in defined order! Key is a KeyT of variable and value is its value!
+ * @return New {@link LinkedHashMap} with variables of this a in defined order! Key is a KeyT of variable and value is its value!
* Modifying this map will not affect this GenericScope object! * * @since 1.2.0 @@ -900,7 +934,8 @@ public boolean isEmpty() /** * @return New {@link ArrayList} with independent values of this {@link GenericScope}. These values have nothing to do with values of variables, they are independent! - * Modifying this list will not affect this GenericScope object! + * Modifying this list will not affect this GenericScope object!
+ * Note: Returning other {@link List} implementations than {@link ArrayList} (or other collection that stores elements in "array-like fashion") may result in serious performance implications! Queues or LinkedLists are the prime examples to avoid! * * @since 1.2.0 */ @@ -1056,7 +1091,7 @@ public static > S intoBidirectional(S scopeTo * @since 1.3.7 */ @SuppressWarnings("unchecked") - public static Map mapKvArray(Map map, Object... kVkVkV) + public static > M mapKvArray(M map, Object... kVkVkV) { for (int i = 1; i < kVkVkV.length; i+=2) map.put((K) kVkVkV[i-1], (V) kVkVkV[i]); diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java index ca80662..a7a9fc0 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java @@ -1,17 +1,22 @@ package org.ugp.serialx; import static org.ugp.serialx.Utils.Instantiate; +import static org.ugp.serialx.Utils.equalsLowerCase; import static org.ugp.serialx.converters.DataParser.VOID; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -111,25 +116,28 @@ public Scope clone() } /** - * @param objClass | Object of class to create using protocols. + * @param objClass | Class of object to create using protocols. * @param protocolsToUse | Registry of protocols to use. * - * @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}! + * @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in protocolsToUse! * If there were no suitable deserialization protocols found, {@link Scope#into(Class, String...)} will be used! * * @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! * * @see Scope#into(Class, String...) - * @see Scope#intoNew(Class, GenericScope, String...) + * @see Scope#intoNew(Type, GenericScope, String...) * * @since 1.3.5 */ @Override - public T toObject(Class objClass, ProtocolRegistry protocolsToUse) throws Exception + public T toObject(Type objClass, ProtocolRegistry protocolsToUse) throws Exception { - T obj = super.toObject(objClass, protocolsToUse); - if (obj != null) - return obj; + if (objClass instanceof Class) + { + T obj; + if ((obj = super.toObject(objClass, protocolsToUse)) != null) + return obj; + } try { @@ -137,7 +145,7 @@ public T toObject(Class objClass, ProtocolRegistry protocolsToUse) throws } catch (Exception e) { - LogProvider.instance.logErr("Unable to create new instance of " + objClass.getName() + " because none of provided protocols were suitable and class introspection has failed as well!", e); + LogProvider.instance.logErr("Unable to create new instance of " + objClass + " because none of provided protocols were suitable and class introspection has failed as well!", e); return null; } } @@ -146,7 +154,9 @@ public T toObject(Class objClass, ProtocolRegistry protocolsToUse) throws * @param variableName | Variables name. * * @return Byte value of variable with name or 0 if there is no such a one! - * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Byte will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -160,7 +170,9 @@ public byte getByte(String variableName) * @param defaultValue | Default value to return. * * @return Byte value of variable with name or defaultValue if there is no such a one or given key contains null! - * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Byte will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -173,7 +185,9 @@ public byte getByte(String variableName, byte defaultValue) * @param variableName | Variables name. * * @return Byte value of variable with name or 0 if there is no such a one! - * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Byte will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -187,7 +201,9 @@ public short getShort(String variableName) * @param defaultValue | Default value to return. * * @return Byte value of variable with name or defaultValue if there is no such a one or given key contains null! - * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Byte will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -200,7 +216,9 @@ public short getShort(String variableName, short defaultValue) * @param variableName | Variables name. * * @return Int value of variable with name or 0 if there is no such a one! - * Int will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Int will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -214,7 +232,9 @@ public int getInt(String variableName) * @param defaultValue | Default value to return. * * @return Int value of variable with name or defaultValue if there is no such a one or given key contains null! - * Int will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Int will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -227,13 +247,15 @@ public int getInt(String variableName, int defaultValue) * @param variableName | Variables name. * * @return Long value of variable with name or 0 if there is no such a one! - * Long will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Long will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ - public int getLong(String variableName) + public long getLong(String variableName) { - return getInt(variableName, 0); + return getLong(variableName, 0); } /** @@ -241,7 +263,9 @@ public int getLong(String variableName) * @param defaultValue | Default value to return. * * @return Long value of variable with name or defaultValue if there is no such a one or given key contains null! - * Long will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Long will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -254,7 +278,9 @@ public long getLong(String variableName, long defaultValue) * @param variableName | Variables name. * * @return Float value of variable with name or 0 if there is no such a one! - * Float will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Float will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -268,7 +294,9 @@ public float getFloat(String variableName) * @param defaultValue | Default value to return. * * @return Float value of variable with name or defaultValue if there is no such a one or given key contains null! - * Float will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Float will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -281,7 +309,9 @@ public float getFloat(String variableName, float defaultValue) * @param variableName | Variables name. * * @return Double value of variable with name or 0 if there is no such a one! - * Double will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Double will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -295,7 +325,9 @@ public double getDouble(String variableName) * @param defaultValue | Default value to return. * * @return Double value of variable with name or defaultValue if there is no such a one or given key contains null! - * Double will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Double will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -304,18 +336,16 @@ public double getDouble(String variableName, double defaultValue) Object obj = get(variableName, defaultValue); if (obj instanceof Number) return ((Number) obj).doubleValue(); - else if (obj instanceof Character) + if (obj instanceof Character) return (double) (char) obj; - else if (obj instanceof CharSequence) - return Double.parseDouble(obj.toString()); - return (double) obj; + return Double.parseDouble(obj.toString()); } /** * @param variableName | Variables name. * * @return String value of variable with name or null if there is no such a one! - * String will be also parsed from any object using {@link Object#toString()}! + * String will be also obtained from any object using {@link String#valueOf(Object)}! * * @since 1.2.5 */ @@ -329,7 +359,7 @@ public String getString(String variableName) * @param defaultValue | Default value to return. * * @return String value of variable with name or defaultValue if there is no such a one or given key contains null! - * String will be also parsed from any object using {@link Object#toString()}! + * String will be also obtained from any object using {@link String#valueOf(Object)}! * * @since 1.2.5 */ @@ -342,13 +372,13 @@ public String getString(String variableName, String defaultValue) * @param variableName | Variables name. * * @return Char value of variable with name or {@code (char) 0} if there is no such a one! - * Char will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Char will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! * * @since 1.2.5 */ public char getChar(String variableName) { - return getChar(variableName, (char) 0); + return getChar(variableName, '\0'); } /** @@ -356,7 +386,7 @@ public char getChar(String variableName) * @param defaultValue | Default value to return. * * @return Char value of variable with name or defaultValue if there is no such a one or given key contains null! - * Char will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Char will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! * * @since 1.2.5 */ @@ -365,11 +395,9 @@ public char getChar(String variableName, char defaultValue) Object obj = get(variableName, defaultValue); if (obj instanceof Character) return (char) obj; - else if (obj instanceof CharSequence) - return ((CharSequence) obj).charAt(0); - else if (obj instanceof Number) + if (obj instanceof Number) return (char) ((Number) obj).intValue(); - return (char) obj; + return obj.toString().charAt(0); } /** @@ -390,7 +418,7 @@ public boolean getBool(String variableName) * @param defaultValue | Default value to return. * * @return Boolean value of variable with name or defaultValue if there is no such a one or given key contains null! - * Boolean will be also parsed from {@link Number}, or {@link CharSequence} if possible! + * Boolean will be also parsed from {@link Number}, or {@link Object#toString()} if possible! * * @since 1.2.5 */ @@ -399,17 +427,13 @@ public boolean getBool(String variableName, boolean defaultValue) Object obj = get(variableName, defaultValue); if (obj instanceof Boolean) return (boolean) obj; - else if (obj instanceof Number) - return ((Number) obj).doubleValue() > 0; - else - { - String str = obj.toString(); - if (str.equalsIgnoreCase("t")) - return true; - else if (str.equalsIgnoreCase("f")) - return false; - return Boolean.parseBoolean(obj.toString()); - } + if (obj instanceof Number) + return ((Number) obj).doubleValue() != 0; + + String str = obj.toString(); + int len; + return (str.charAt(0) | ' ') == 't' && ((len = str.length()) == 1 || len == 4 && equalsLowerCase(str, "true", 1, 4)); +// return Boolean.parseBoolean(str); } /** @@ -417,7 +441,9 @@ else if (str.equalsIgnoreCase("f")) * {@link IndexOutOfBoundsException} will be thrown if index is too big! * * @return Independent byte value with valueIndex. - * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Byte will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -431,7 +457,9 @@ public byte getByte(int valueIndex) * {@link IndexOutOfBoundsException} will be thrown if index is too big! * * @return Independent short value with valueIndex. - * Byte will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Byte will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -445,7 +473,9 @@ public short getShort(int valueIndex) * {@link IndexOutOfBoundsException} will be thrown if index is too big! * * @return Independent int value with valueIndex. - * Int will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Int will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -459,7 +489,9 @@ public int getInt(int valueIndex) * {@link IndexOutOfBoundsException} will be thrown if index is too big! * * @return Independent long value with valueIndex. - * Long will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Long will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -473,7 +505,9 @@ public long getLong(int valueIndex) * {@link IndexOutOfBoundsException} will be thrown if index is too big! * * @return Independent float value with valueIndex. - * Float will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Float will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -487,7 +521,9 @@ public float getFloat(int valueIndex) * {@link IndexOutOfBoundsException} will be thrown if index is too big! * * @return Independent double value with valueIndex. - * Double will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Double will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! + * + * @throws NumberFormatException if string form of an object can't be parsed to a number! * * @since 1.2.5 */ @@ -496,11 +532,9 @@ public double getDouble(int valueIndex) Object obj = get(valueIndex); if (obj instanceof Number) return ((Number) obj).doubleValue(); - else if (obj instanceof Character) + if (obj instanceof Character) return (double) (char) obj; - else if (obj instanceof CharSequence) - return Double.parseDouble(obj.toString()); - return (double) obj; + return obj == null ? 0 : Double.parseDouble(obj.toString()); } /** @@ -522,7 +556,7 @@ public String getString(int valueIndex) * {@link IndexOutOfBoundsException} will be thrown if index is too big! * * @return Independent char value with valueIndex. - * Char will be also parsed from {@link Number}, {@link Character} or {@link CharSequence} if possible! + * Char will be also parsed from {@link Number}, {@link Character} or {@link Object#toString()} if possible! * * @since 1.2.5 */ @@ -531,11 +565,9 @@ public char getChar(int valueIndex) Object obj = get(valueIndex); if (obj instanceof Character) return (char) obj; - else if (obj instanceof CharSequence) - return ((CharSequence) obj).charAt(0); - else if (obj instanceof Number) + if (obj instanceof Number) return (char) ((Number) obj).intValue(); - return (char) obj; + return obj == null ? 0 : obj.toString().charAt(0); } /** @@ -543,7 +575,7 @@ else if (obj instanceof Number) * {@link IndexOutOfBoundsException} will be thrown if index is too big! * * @return Independent boolean value with valueIndex. - * Boolean will be also parsed from {@link Number}, or {@link CharSequence} if possible! + * Boolean will be also parsed from {@link Number}, or {@link Object#toString()} if possible! * * @since 1.2.5 */ @@ -552,17 +584,12 @@ public boolean getBool(int valueIndex) Object obj = get(valueIndex); if (obj instanceof Boolean) return (boolean) obj; - else if (obj instanceof Number) - return ((Number) obj).doubleValue() > 0; - else - { - String str = obj.toString(); - if (str.equalsIgnoreCase("t")) - return true; - else if (str.equalsIgnoreCase("f")) - return false; - return Boolean.parseBoolean(obj.toString()); - } + if (obj instanceof Number) + return ((Number) obj).doubleValue() != 0; + + String str = String.valueOf(obj); + int len; + return (str.charAt(0) | ' ') == 't' && ((len = str.length()) == 1 || len == 4 && equalsLowerCase(str, "true", 1, 4)); } /** @@ -876,21 +903,21 @@ else if (includeSubScopes) } /** - * @param objCls | Class of object to instantiate! + * @param objCls | Class of object to instantiate! Can also be {@link ParameterizedType}! * @param fieldNamesToUse | Array of objCls field names to map/populate instantiated object from scopes variables using setters (write method)! PropertyDescriptors of these fields will be obtained using Scope.getPropertyDescriptorsOf(Class, String)! This is used only as a last (default) option! * - * @return New instance of object according to {@link GenericScope#intoNew(Class, GenericScope, String...)} similarly to {@link GenericScope#toObject(Class)} except this one will not use any protocols! + * @return New instance of object according to {@link GenericScope#intoNew(Type, GenericScope, String...)} similarly to {@link GenericScope#toObject(Class)} except this one will not use any protocols! * * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often)! * @throws IntrospectionException when there were no {@link PropertyDescriptor} found for obj class! * - * @see Scope#intoNew(Class, GenericScope, String...) + * @see Scope#intoNew(Type, GenericScope, String...) * * @since 1.3.5 */ - public T into(Class objCls, String... fieldNamesToUse) throws IntrospectionException, Exception + public T into(Type objCls, String... fieldNamesToUse) throws IntrospectionException, Exception { - return (T) intoNew(objCls, this, fieldNamesToUse); + return intoNew(objCls, this, fieldNamesToUse); } /** @@ -902,7 +929,7 @@ public T into(Class objCls, String... fieldNamesToUse) throws Introspecti * @throws Exception if calling of some {@link PropertyDescriptor}s write method fails (should not happen often)! * @throws IntrospectionException when there were no {@link PropertyDescriptor} found for obj class! * - * @see Scope#intoNew(Class, GenericScope, String...) + * @see Scope#intoNew(Type, GenericScope, String...) * * @since 1.3.5 */ @@ -1026,7 +1053,7 @@ public static Scope from(Object obj, List fieldsToUse) throw } /** - * @param objCls | Class of object to instantiate! + * @param type | Class of object to instantiate! Can also be {@link ParameterizedType}! * @param fromScope | Source scope with data to instantiate from! * @param fieldNamesToUse | Array of objCls field names to map/populate instantiated object from scopes variables using setters (write method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link Scope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! * @@ -1074,17 +1101,20 @@ New object instance (return) * @since 1.3.5 */ @SuppressWarnings("unchecked") - public static T intoNew(Class objCls, GenericScope fromScope, String... fieldNamesToUse) throws IntrospectionException, Exception + public static T intoNew(Type type, GenericScope fromScope, String... fieldNamesToUse) throws IntrospectionException, Exception { - if (objCls == null) + if (type == null) return null; - if (objCls.isArray()) + boolean isGenricType; + Class objCls = (Class) ((isGenricType = type instanceof ParameterizedType) ? ((ParameterizedType) type).getRawType() : type); + Class elmType; + if ((elmType = objCls.getComponentType()) != null) { - if (objCls.getComponentType() == Object.class) + if (elmType == Object.class) return (T) fromScope.toArray(); - return (T) into(Array.newInstance(objCls.getComponentType(), fromScope.valuesCount()), fromScope, fieldNamesToUse); + return (T) into(Array.newInstance(elmType, fromScope.valuesCount()), fromScope, fieldNamesToUse); } if (GenericScope.class.isAssignableFrom(objCls)) @@ -1092,6 +1122,12 @@ public static T intoNew(Class objCls, GenericScope fro GenericScope result = ((GenericScope) fromScope).clone((Class>)objCls); if (fieldNamesToUse != null && fieldNamesToUse.length > 0) result.variables().keySet().retainAll(Arrays.asList(fieldNamesToUse)); + + if (isGenricType) + { + intoGeneric(result.values(), (ParameterizedType) type); + intoGeneric(result.variables(), (ParameterizedType) type); + } return (T) result; } @@ -1099,7 +1135,8 @@ public static T intoNew(Class objCls, GenericScope fro { if (Collection.class.isAssignableFrom(objCls)) { - return (T) fromScope.toValList(); + List list = fromScope.toValList(); + return (T) (isGenricType ? intoGeneric(list, (ParameterizedType) type) : list); } if (Map.class.isAssignableFrom(objCls)) @@ -1107,11 +1144,25 @@ public static T intoNew(Class objCls, GenericScope fro Map map = fromScope.toVarMap(); if (fieldNamesToUse != null && fieldNamesToUse.length > 0) map.keySet().retainAll(Arrays.asList(fieldNamesToUse)); - return (T) map; + return (T) (isGenricType ? intoGeneric(map, (ParameterizedType) type) : map); + } + } + + T newObj = into(Instantiate(objCls), fromScope, fieldNamesToUse); + if (isGenricType) + { + if (newObj instanceof List) + return (T) intoGeneric((List) newObj, (ParameterizedType) type); + if (newObj instanceof Map) + return (T) intoGeneric((Map) newObj, (ParameterizedType) type); + if (newObj instanceof GenericScope) + { + intoGeneric(((GenericScope) newObj).values(), (ParameterizedType) type); + intoGeneric(((GenericScope) newObj).variables(), (ParameterizedType) type); } } - return into(Instantiate(objCls), fromScope, fieldNamesToUse); + return newObj; } /** @@ -1168,10 +1219,15 @@ public static T into(T obj, GenericScope fromScope, Strin { if (obj == null) return null; - if (obj.getClass().isArray()) + + Class elmType; + if ((elmType = obj.getClass().getComponentType()) != null) { for (int i = 0, arrLen = Array.getLength(obj), scSize = fromScope.valuesCount(); i < arrLen && i < scSize; i++) - Array.set(obj, i, fromScope.get(i)); + { + Object elm = fromScope.get(i); + Array.set(obj, i, elm instanceof GenericScope && elmType != elm.getClass() ? ((GenericScope) elm).toObject(elmType) : elm); + } return obj; } @@ -1216,16 +1272,90 @@ public static T into(T obj, GenericScope fromScope, List< { for (PropertyDescriptor var : fieldsToUse) { - Object varValue = ((GenericScope) fromScope).get(var.getName(), VOID); - if (varValue != VOID) - var.getWriteMethod().invoke(obj, varValue); + Object varValue; + if ((varValue = ((GenericScope) fromScope).variables().getOrDefault(var.getName(), VOID)) != VOID) + { + Method setter = var.getWriteMethod(); + Type expectedType = setter.getGenericParameterTypes()[0]; + setter.invoke(obj, varValue instanceof GenericScope && expectedType != varValue.getClass() ? ((GenericScope) varValue).toObject(expectedType) : varValue); + } } return obj; } + /** + * @param listToGenerify | List to modify/map its elements into specified type. + * @param genericType | Requested type of lists elements. + * + * @return The same list after its {@link GenericScope} elements were turned into elements of provided genericType. If generic type can't be inferred, the whole process will stop. + * + * @throws Exception if Scope#intoNew(Type, GenericScope, String...) fails... + * + * @since 1.3.7 + */ + @SuppressWarnings("unchecked") + public static List intoGeneric(List listToGenerify, ParameterizedType genericType) throws Exception + { + try + { + if (listToGenerify.isEmpty()) + return (List) listToGenerify; + + ListIterator iter = listToGenerify.listIterator(0); + Type elmType; + do + { + Object obj; + if ((obj = iter.next()) instanceof GenericScope) + { + iter.set(((GenericScope) obj).toObject(elmType = ((ParameterizedType) genericType).getActualTypeArguments()[0])); + + while (iter.hasNext()) + if ((obj = iter.next()) instanceof GenericScope) + iter.set(((GenericScope) obj).toObject(elmType)); + break; + } + } + while (iter.hasNext()); + } + catch (ClassCastException | IndexOutOfBoundsException e) + {} + return (List) listToGenerify; + } + + /* + * @param listToGenerify | Map whose values should be modify/map its elements into specified type. + * @param genericType | Requested type of lists elements. + * + * @return The same map after its {@link GenericScope} values were turned into values of provided genericType. If generic type can't be inferred, the whole process will stop. + * + * @throws Exception if Scope#intoNew(Type, GenericScope, String...) fails... + * + * @since 1.3.7 + */ + @SuppressWarnings("unchecked") + public static Map intoGeneric(Map mapToGenerify, ParameterizedType genericType) throws Exception + { + try + { + if (mapToGenerify.size() < 1) + return (Map) mapToGenerify; + Type elmType = ((ParameterizedType) genericType).getActualTypeArguments()[1]; //0 = key, 1 = val + for (Map.Entry entry : mapToGenerify.entrySet()) + { + Object obj; + if ((obj = entry.getValue()) instanceof GenericScope) + entry.setValue(((GenericScope) obj).toObject(elmType)); + } + } + catch (ClassCastException | IndexOutOfBoundsException e) + {} + return (Map) mapToGenerify; + } + /** * @param cls | Class to inspect! - * @param fieldNames | Names of fields to get descriptors for, if this array is empty or null, descriptors for all fields with public getters and setters will be obtained! + * @param fieldNames | Names of fields to get descriptors for, if this array is empty or null, descriptors for all not-static and not-transient fields with public getters and setters that will be obtained! * * @return List of {@link PropertyDescriptor}s of cls representing access methods of required fields! Only descriptors of fields that have valid and public getter and setter will be returned! * @@ -1237,14 +1367,13 @@ public static T into(T obj, GenericScope fromScope, List< */ public static List getPropertyDescriptorsOf(Class cls, String... fieldNames) throws IntrospectionException { - return getPropertyDescriptorsOf(cls, null, fieldNames); + return getPropertyDescriptorsOf(cls, null, fieldNames); } - /** * @param cls | Class to inspect! * @param cache | Cache to store generated results into! - * @param fieldNames | Names of fields to get descriptors for, if this array is empty or null, descriptors for all fields with public getters and setters will be obtained! + * @param fieldNames | Names of fields to get descriptors for, if this array is empty or null, descriptors for all not-static and not-transient fields with public getters and setters that will be obtained! * * @return List of {@link PropertyDescriptor}s of cls representing access methods of required fields! Only descriptors of fields that have valid and public getter and setter will be returned! * @@ -1255,39 +1384,56 @@ public static List getPropertyDescriptorsOf(Class cls, St * @since 1.3.5 */ public static List getPropertyDescriptorsOf(Class cls, Map, List> cache, String... fieldNames) throws IntrospectionException + { + return getPropertyDescriptorsOf(cls, null, Modifier.STATIC | Modifier.TRANSIENT, fieldNames); + } + + /** + * @param cls | Class to inspect! + * @param cache | Cache to store generated results into! + * @param modifiersToIgnore | If field has this {@link Modifier} it will not be included. Only works when fieldNames are null or empty and cache is not provided. + * @param fieldNames | Names of fields to get descriptors for, if this array is empty or null, descriptors for all fields that do not have modifiersToIgnore and have public getters and setters that will be obtained! + * + * @return List of {@link PropertyDescriptor}s of cls representing access methods of required fields! Only descriptors of fields that have valid and public getter and setter will be returned! + * + * @throws IntrospectionException when there are no suitable fields with valid and public getters and setters. + * + * @see PropertyDescriptor + * + * @since 1.3.7 + */ + public static List getPropertyDescriptorsOf(Class cls, Map, List> cache, int modifiersToIgnore, String... fieldNames) throws IntrospectionException { List fieldDescriptors = new ArrayList<>(), cached = cache == null ? null : cache.get(cls); - if (cached != null) - return cached; - - if (fieldNames == null || fieldNames.length <= 0) + if (cached != null) + return cached; + + if (fieldNames == null || fieldNames.length <= 0) { for (Class c = cls; c != Object.class; c = c.getSuperclass()) for (Field field : c.getDeclaredFields()) - if (!Modifier.isStatic(field.getModifiers())) + if ((field.getModifiers() & modifiersToIgnore) == 0) try { fieldDescriptors.add(new PropertyDescriptor(field.getName(), cls)); } catch (Exception e) {} - + if (cache != null && !fieldDescriptors.isEmpty()) - { cache.put(cls, fieldDescriptors); - } } - else - { + else + { for (int i = 0; i < fieldNames.length; i++) try - { + { fieldDescriptors.add(new PropertyDescriptor(fieldNames[i], cls)); - } - catch (Exception e) - {} - } - + } + catch (Exception e) + {} + } + if (fieldDescriptors.isEmpty()) throw new IntrospectionException("No suitable fields with valid and public getters and setters to use in " + cls.getSimpleName()); return fieldDescriptors; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index a5bc254..07f0b61 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -19,6 +19,7 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.io.StringReader; +import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; @@ -158,8 +159,17 @@ public T toObjectOf(String variableWithscope, Class objClass, T defaultVa return toObjectOf(variableWithscope, objClass, defaultValue, getProtocols()); } + /** + * @param type | Class of object to create. + * + * @return Object of type constructed from this scopes independent values using protocol for given class or null if there was no protocol found in this {@link Serializer#getProtocols()}! + * + * @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! + * + * @since 1.2.5 + */ @Override - public T toObject(Class objClass) throws Exception + public T toObject(Type objClass) throws Exception { return toObject(objClass, getProtocols()); } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index 59a1be7..e92a264 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -184,7 +184,7 @@ public CharSequence toString(Object obj, Object... args) } } - 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); + 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); return null; } diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java index 09ac8ab..0a33ab2 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java @@ -166,6 +166,8 @@ public S LoadFrom(Reader reader, Object... formatArgs) { Scope sc = super.LoadFrom(reader, formatArgs); + if (formatArgs.length > 0 && formatArgs[0] instanceof Serializer) + return (S) sc; Object jsonScope; if (sc.valuesCount() == 1 && (jsonScope = sc.get(0)) instanceof Scope) return (S) jsonScope; diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java index 1807b9e..09091ec 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java @@ -1,5 +1,7 @@ package org.ugp.serialx.json.converters; +import java.util.Map; + import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; import org.ugp.serialx.Utils; @@ -21,18 +23,23 @@ public class JsonObjectConverter extends ObjectConverter public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) { if (arg.getClass().isArray()) - arg = new Scope(Utils.fromAmbiguousArray(arg)); + return super.toString(myHomeRegistry, new Scope(Utils.fromAmbiguousArray(arg)), args); + + if (arg instanceof Map) + { + Map map = (Map) arg; + if (map.isEmpty() || map.keySet().iterator().next() instanceof CharSequence) + return super.toString(myHomeRegistry, new Scope((Map) map), args); + } SerializationProtocol prot = (SerializationProtocol) getProtocolFor(arg, SerializationProtocol.MODE_SERIALIZE, args); - if (prot != null && !(arg instanceof Scope)) try { Object[] objArgs = prot.serialize(arg); if (objArgs.length == 1 && objArgs[0] instanceof Scope) return super.toString(myHomeRegistry, objArgs[0], args); - else - return super.toString(myHomeRegistry, new Scope(objArgs), args); + return super.toString(myHomeRegistry, new Scope(objArgs), args); } catch (Exception e) {} diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java index 1f869ed..5028812 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java @@ -4,10 +4,13 @@ import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; -import java.util.ArrayList; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Arrays; import java.util.HashMap; import java.util.List; +import org.ugp.serialx.GenericScope; import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; import org.ugp.serialx.protocols.SerializationProtocol; @@ -24,8 +27,9 @@ */ public class AutoProtocol extends SerializationProtocol { - static { - UNIVERSAL_INTROSPECTION = new ArrayList<>(); + static + { + UNIVERSAL_INTROSPECTION = Arrays.asList(); } /** @@ -55,7 +59,7 @@ public class AutoProtocol extends SerializationProtocol public static final List UNIVERSAL_INTROSPECTION; protected final Class applicableFor; - protected List fieldDescriptors = new ArrayList<>(); + protected List fieldDescriptors; protected HashMap, List> cache = new HashMap<>(); protected boolean useScope; @@ -94,7 +98,7 @@ public AutoProtocol(Class applicableFor, List fieldsToSer */ public AutoProtocol(Class applicableFor, boolean useScope, String... fieldsToSerialize) throws IntrospectionException { - this(applicableFor, useScope, fieldsToSerialize.length == 0 ? UNIVERSAL_INTROSPECTION : Scope.getPropertyDescriptorsOf(applicableFor, fieldsToSerialize)); + this(applicableFor, useScope, fieldsToSerialize == null || fieldsToSerialize.length == 0 ? UNIVERSAL_INTROSPECTION : Scope.getPropertyDescriptorsOf(applicableFor, fieldsToSerialize)); } /** @@ -109,13 +113,13 @@ public AutoProtocol(Class applicableFor, boolean useScope, List objectClass) throws Exception @Override public Object[] serialize(T object) throws Exception { - List fieldDescriptors = this.fieldDescriptors; + List fieldDescriptors = getFieldDescriptors(); if (fieldDescriptors == UNIVERSAL_INTROSPECTION) fieldDescriptors = Scope.getPropertyDescriptorsOf(object.getClass(), cache); if (isUseScope()) - { return new Object[] {Scope.from(object, fieldDescriptors)}; - } - else - { - int size = fieldDescriptors.size(); - Object[] args = new Object[size]; - for (int i = 0; i < size; i++) - args[i] = fieldDescriptors.get(i).getReadMethod().invoke(object); - return args; - } + + int size = fieldDescriptors.size(); + Object[] args = new Object[size]; + for (int i = 0; i < size; i++) + args[i] = fieldDescriptors.get(i).getReadMethod().invoke(object); + return args; } + @SuppressWarnings("unchecked") @Override public T unserialize(Class objectClass, Object... args) throws Exception { - List fieldDescriptors = this.fieldDescriptors; + List fieldDescriptors = getFieldDescriptors(); if (fieldDescriptors == UNIVERSAL_INTROSPECTION) fieldDescriptors = Scope.getPropertyDescriptorsOf(objectClass, cache); @@ -167,25 +168,24 @@ public T unserialize(Class objectClass, Object... args) throws Exce return Scope.into(obj, (Scope) args[0], fieldDescriptors); } - for (int i = 0, size = fieldDescriptors.size(); i < size && i < args.length; i++) - fieldDescriptors.get(i).getWriteMethod().invoke(obj, args[i]); + for (int i = 0, size = fieldDescriptors.size(); i < size && i < args.length; i++) + { + Method setter = fieldDescriptors.get(i).getWriteMethod(); + Type expectedType = setter.getGenericParameterTypes()[0]; + setter.invoke(obj, args[i] instanceof GenericScope && expectedType != args[i].getClass() ? ((GenericScope) args[i]).toObject(expectedType) : args[i]); + } return obj; } /** - * @param variableName | Name of variable! - * - * @return PropertyDescriptor of variable with name or null if this protocols can't serialize variable with given name!
- * Note: I would recommend to tread this as read only and not set anything that you are not sure of. This will ensure correct functionality... + * @return PropertyDescriptors of variables that are used by this protocol!
+ * Note: I would recommend to tread this as read only and not modify anything that you are not sure of. This will ensure correct functionality of this protocol... * * @since 1.3.2 */ - public PropertyDescriptor getfieldDescriptorsDescriptor(String variableName) + public List getFieldDescriptors() { - for (PropertyDescriptor var : fieldDescriptors) - if (var.getName().equals(variableName)) - return var; - return null; + return this.fieldDescriptors; } @Override diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java index a773ea9..22a8e25 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java @@ -1,8 +1,10 @@ package org.ugp.serialx.juss.protocols; import java.lang.reflect.Constructor; +import java.lang.reflect.Type; import java.util.Arrays; +import org.ugp.serialx.GenericScope; import org.ugp.serialx.LogProvider; import org.ugp.serialx.Utils; import org.ugp.serialx.protocols.SerializationProtocol; @@ -42,19 +44,42 @@ public Object[] serialize(T object) @Override public T unserialize(Class objectClass, Object... args) throws Exception { - try + try { return objectClass.getConstructor(Utils.ToClasses(args)).newInstance(args); } catch (Exception e0) { - for (Constructor cons : objectClass.getConstructors()) - try - { - return (T) cons.newInstance(args); - } - catch (IllegalArgumentException e) - {} + int argCount = args.length; + for (Constructor cons : objectClass.getConstructors()) + if (cons.getParameterCount() == argCount) + try + { + return (T) cons.newInstance(args); + } + catch (IllegalArgumentException e) + { + try + { + for (int i = 0; i < argCount; i++) + { + Object arg; + if ((arg = args[i]) instanceof GenericScope) + { + Type[] paramTypes; + args = args.clone(); + args[i] = ((GenericScope) arg).toObject((paramTypes = cons.getGenericParameterTypes())[i]); + + for (i++; i < argCount; i++) + if ((arg = args[i]) instanceof GenericScope) + args[i] = ((GenericScope) arg).toObject(paramTypes[i]); + return (T) cons.newInstance(args); + } + } + } + catch (IllegalArgumentException e2) + {} + } } LogProvider.instance.logErr("Unable to create new instance of \"" + objectClass + "\" because inserted arguments " + Arrays.asList(args) + " cannot be applied on any public constructor in required class!", null); return null; From c50659deeb21f39d5a8f482fb6e021f32d0cd9a5 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sat, 20 Jul 2024 19:53:22 +0200 Subject: [PATCH 33/48] finishing.... --- .../serialx/juss/protocols/SelfSerializableProtocol.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java index efa1aaa..a4317af 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java @@ -9,7 +9,7 @@ * * @see UniversalObjectInstantiationProtocol */ -public class SelfSerializableProtocol extends UniversalObjectInstantiationProtocol +public class SelfSerializableProtocol extends UniversalObjectInstantiationProtocol { /** * @param applicableFor | Class implementing {@link SelfSerializable} that can be serialized using this protocol.
@@ -17,13 +17,13 @@ public class SelfSerializableProtocol extends UniversalObjectInstantiationProtoc * * @since 1.3.7 */ - public SelfSerializableProtocol(Class applicableFor) + public SelfSerializableProtocol(Class applicableFor) { super(applicableFor); } @Override - public Object[] serialize(SelfSerializable object) + public Object[] serialize(T object) { return object.serialize(); } From 6743767a5033e424e622735f7acd13b926944a4e Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Wed, 31 Jul 2024 21:29:16 +0200 Subject: [PATCH 34/48] Small refactor of ArrConv, improving performance and security of OpGroups, DataRegi is now DataParser --- .../src/main/java/org/ugp/serialx/Utils.java | 4 +- .../ugp/serialx/converters/DataParser.java | 33 ++++++-- .../juss/converters/ArrayConverter.java | 45 ++++++----- .../juss/converters/OperationGroups.java | 76 +++++++++++-------- 4 files changed, 98 insertions(+), 60 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index f7eae53..024a320 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -820,8 +820,8 @@ public static String showPosInString(CharSequence str, int pos) */ public static Object castArray(Object[] sourceArray, Class toType) { - int len = sourceArray.length; - Object arr = Array.newInstance(ToClasses(toType)[0], len); + int len; + Object arr = Array.newInstance(ToClasses(toType)[0], len = sourceArray.length); for (int i = 0; i < len; i++) Array.set(arr, i, sourceArray[i]); return arr; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index e92a264..e215655 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -75,7 +75,7 @@ public static Object parseObj(String str, Object... args) * * @since 1.3.5 */ - public static class ParserRegistry extends Registry + public static class ParserRegistry extends Registry implements DataParser { private static final long serialVersionUID = -2598324826689380752L; @@ -167,11 +167,11 @@ public DataConverter getConverterFor(Object obj, Object... args) */ public CharSequence toString(Object obj, Object... args) { - CharSequence str = null; + CharSequence str; if (convertingCache != null) for (DataParser parser : convertingCache) if (parser != null && (str = ((DataConverter) parser).toString(this, obj, args)) != CONTINUE) - return str; + return str; for (int i = 0, size = size(); i < size; i++) { @@ -188,6 +188,28 @@ public CharSequence toString(Object obj, Object... args) return null; } + /** + * @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. + * @param str | Source string to parse using suitable parser from registry. + * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! + * + * @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! + * 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!
+ * 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! + * + * @see DataParser#parseObj(String, Object...) + * + * @since 1.3.7 + */ + @Override + public Object parse(ParserRegistry parentRegistry, String str, Object... args) + { + Object result; + if ((result = parse(str, true, this == parentRegistry ? getClass() : null, args)) == str) + return CONTINUE; + return result; + } + /** * @param str | Source string to parse using suitable parser from registry. * @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) /** * @param str | Source string to parse using suitable parser from registry. - * @param returnAsStringIfNotFound | If true, inserted string will be returned instead of null and error message! + * @param returnAsStringIfNotFound | If true, inserted string will be returned instead of null and error message in case of suitable parser not found! * @param ignore | {@link DataParser} class to ignore! * @param args | Additional arguments that will be obtained in {@link DataParser#parse(String, Object...)}! * @@ -215,7 +237,7 @@ public Object parse(String str, Object... args) */ public Object parse(String str, boolean returnAsStringIfNotFound, Class ignore, Object... args) { - Object obj = null; + Object obj; if (parsingCache != null) for (DataParser parser : parsingCache) if (parser != null && (ignore == null || ignore != parser.getClass()) && (obj = parser.parse(this, str, args)) != CONTINUE) @@ -345,5 +367,6 @@ public DataParser[] getConverterCache() { return convertingCache; } + } } diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java index 0849c5f..b5882bd 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java @@ -51,32 +51,35 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { if (indexOfNotInObj(str, ' ') > 0) { - boolean findArrType = true; - if (args.length > 1 && args[1] instanceof Boolean) - findArrType = (boolean) args[1]; - String[] strObjs = tokenize(str); - int len = strObjs.length; - Object[] objs = new Object[len]; + int len, i = 0; + Object[] objs = new Object[len = strObjs.length]; - Class arrClass = null; - for (int i = 0; i < len; i++) + if (args.length < 2 || !(args[1] instanceof Boolean) || (boolean) args[1]) { - Object obj = objs[i] = myHomeRegistry.parse(strObjs[i], args); - if (obj != null) - if (arrClass == null) - arrClass = obj.getClass(); - else if (arrClass != obj.getClass()) - arrClass = Object.class; - } - - if (findArrType && arrClass != null && !arrClass.equals(Object.class)) - try + Class arrClass = null; + for (; i < len; i++) { - return castArray(objs, arrClass); + Object obj = objs[i] = myHomeRegistry.parse(strObjs[i], args); + if (obj != null) + if (arrClass == null) + arrClass = obj.getClass(); + else if (arrClass != obj.getClass()) + arrClass = Object.class; } - catch (IllegalArgumentException e) - {} + + if (arrClass != null && arrClass != Object.class) + try + { + return castArray(objs, arrClass); + } + catch (IllegalArgumentException e) + {} + return objs; + } + + for (; i < len; i++) + objs[i] = myHomeRegistry.parse(strObjs[i], args); return objs; } return CONTINUE; diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java index 9315151..f62765b 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java @@ -7,7 +7,6 @@ import java.util.Map; import org.ugp.serialx.LogProvider; -import org.ugp.serialx.Serializer; import org.ugp.serialx.converters.DataParser; /** @@ -27,46 +26,59 @@ public class OperationGroups implements DataParser { /** + * @deprecated (since 1.3.7) DO NOT USE, USE {@link OperationGroups#groupMark} instead!
+ * * Opening and closing of group mark! * * @since 1.3.0 */ - public static final String GROUP_MARK_OP = new String(new char[] {127, 128, 129}), GROUP_MARK_CLS = new String(new char[] {129, 128, 127}); + @Deprecated + public static final char[] GROUP_MARK_OP = new char[] {127, 128, 129}, GROUP_MARK_CLS = new char[] {129, 128, 127}; + + /** + * Character marking the opening of {@link OperationGroups} mark in processed string, closing should be marked as this character -1.
+ * This character is generated in sami-random fashion but it will never be an ASCII character. + * + * @since 1.3.7 + */ + protected final char groupMark = (char) (System.nanoTime() | 128); @SuppressWarnings("unchecked") @Override - public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) + public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) { if (str.length() > 1) { - int opIndex = indexOfOpening(str, 0, '('), clsIndex = -1; + int opIndex = indexOfOpening(str, 0, '('), clsIndex; if (opIndex > -1 && (clsIndex = indexOfClosing(str, opIndex, new char[] {'('}, ')')) > -1) { - Map runtimeGroupStack = new HashMap<>(); + Map runtimeGroups; if (args.length > 2 && args[2] instanceof Map) - runtimeGroupStack = (Map) args[2]; + runtimeGroups = (Map) args[2]; else { if (args.length < 3) args = Arrays.copyOf(args, 3); - args[2] = runtimeGroupStack; + args[2] = runtimeGroups = new HashMap<>(); } - String mark = GROUP_MARK_OP + runtimeGroupStack.size() + GROUP_MARK_CLS; - runtimeGroupStack.put(mark, str.substring(opIndex+1, clsIndex).trim()); - StringBuilder sb = new StringBuilder(str).replace(opIndex, clsIndex+1, mark); - return myHomeRegistry.parse(sb.toString(), args); + int groupId; + runtimeGroups.put(groupId = runtimeGroups.size(), str.substring(opIndex+1, clsIndex).trim()); + + StringBuilder newStr = new StringBuilder(str).replace(opIndex, clsIndex+1, new StringBuilder().append(groupMark).append(groupId).append((char) (groupMark-1)).toString()); + return myHomeRegistry.parse(newStr.toString(), args); } - if (isGroupMark(str)) + int groupId; + if ((groupId = isGroupMark(str, groupMark)) != -1) { if (args.length > 2 && args[2] instanceof Map) { - Map runtimeGroupStack = (Map) args[2]; + Map runtimeGroups = (Map) args[2]; Object[] newArgs = args.clone(); - newArgs[2] = new HashMap(); - return myHomeRegistry.parse(runtimeGroupStack.get(str), newArgs); + newArgs[2] = new HashMap(); + return myHomeRegistry.parse(runtimeGroups.get(groupId), newArgs); } LogProvider.instance.logErr("Runtime group stack is trying to be accessed using " + str + " however it was not provided yet!", null); return null; @@ -78,30 +90,30 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) /** * @param s | Char sequence to check! + * @param groupMark | Opening character identifying this group mark, closing should be this character -1 * - * @return Return true if inserted CharSequence match the runtime group mark wrapper! + * @return Id of the group mark if inserted CharSequence matches the runtime group mark wrapper format! -1 otherwise.
* This is used for internal purposes of {@link OperationGroups}. * * @since 1.3.0 */ - public static boolean isGroupMark(CharSequence s) + public static int isGroupMark(CharSequence s, char groupMark) { - String op = GROUP_MARK_OP, cls = GROUP_MARK_CLS; - int lo = op.length(), lc = cls.length(), len = s.length(); - if (len < lo + lc + 1) - return false; - for (int i = 0; i < lo; i++) - if (s.charAt(i) != op.charAt(i)) - return false; + int i = s.length()-1; + if (i < 2 || s.charAt(0) != groupMark-- || s.charAt(i--) != groupMark) + return -1; - for (int i = lo, ch; i < len - lc; i++) + int groupId; + if ((groupId = s.charAt(i--) - '0') < 0 || groupId > 9) + return -1; + for (int ch, baseCof = 10; i >= 1; i--, baseCof *= 10) + { if ((ch = s.charAt(i)) < '0' || ch > '9') - return false; + return -1; + groupId += (ch - '0') * baseCof; + } - for (int i = 0; i < lc; i++) - if (s.charAt(len-i-1) != cls.charAt(lc-i-1)) - return false; - return true; + return groupId; } /** @@ -109,7 +121,7 @@ public static boolean isGroupMark(CharSequence s) * @param from | Beginning index of search! * @param openings | Openings to find! * - * @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...)}! + * @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...)}! * * @since 1.3.0 */ @@ -145,7 +157,7 @@ else if (brackets == 0 && isOneOf(ch, openings)) * @param openings | Openings to count with! * @param closing | Closings to find! * - * @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...)}! + * @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...)}! * * @since 1.3.0 */ From 7bebded8a153d7a35bb29bcd50d528e664a3d35f Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Wed, 31 Jul 2024 23:32:01 +0200 Subject: [PATCH 35/48] make it 1.3.8 --- .../java/org/ugp/serialx/GenericScope.java | 28 +++++++++---------- .../src/main/java/org/ugp/serialx/Scope.java | 6 ++-- .../main/java/org/ugp/serialx/Serializer.java | 4 +-- .../src/main/java/org/ugp/serialx/Utils.java | 10 +++---- .../ugp/serialx/converters/DataParser.java | 2 +- .../serialx/converters/NumberConverter.java | 4 +-- .../serialx/converters/ProtocolConverter.java | 10 +++---- .../serialx/converters/StringConverter.java | 8 +++--- .../serialx/converters/VariableParser.java | 6 ++-- .../converters/imports/ImportsProvider.java | 2 +- .../serialx/devtools/DebugParserRegistry.java | 2 +- .../devtools/SerializationDebugger.java | 4 +-- .../org/ugp/serialx/json/JsonSerializer.java | 2 +- .../converters/JsonCharacterConverter.java | 8 +++--- .../json/converters/JsonNumberConverter.java | 2 +- .../org/ugp/serialx/juss/JussSerializer.java | 2 +- .../juss/converters/OperationGroups.java | 4 +-- .../juss/converters/VariableConverter.java | 2 +- .../protocols/SelfSerializableProtocol.java | 2 +- .../UniversalObjectInstantiationProtocol.java | 2 +- .../org/ugp/serialx/converters/Operators.java | 10 +++---- .../operators/ArithmeticOperators.java | 8 +++--- .../operators/NegationOperator.java | 2 +- 23 files changed, 65 insertions(+), 65 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index 49aa640..a47d582 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -209,7 +209,7 @@ public ValT put(KeyT variableKey, ValT variableValue) * * @return Array of values previously at keys from kv array. * - * @since 1.3.7 + * @since 1.3.8 */ @SuppressWarnings("unchecked") public ValT[] putAllKv(Object... kVkVkV) @@ -303,7 +303,7 @@ public V get(KeyT variableKey, V defaultValue) * If there is no other variable called "value" in the scope tree then you can also simplify it to scope.get("value"), but make sure that there is no equally-named variable!
* Note: Make sure that you are not calling {@link GenericScope#get(Object, Object)} by accident when you are using inline vargas array (unspecified count of arguments)! * - * @since 1.3.7 + * @since 1.3.8 */ @SuppressWarnings("unchecked") public V get(KeyT... pathToValue) @@ -341,7 +341,7 @@ public V get(KeyT... pathToValue) * * @throws Exception | If converting to object of cls failed from some reason! This can differ from implementation to implementation! By default it uses {@link GenericScope#toObject(cls)} * - * @since 1.3.7 + * @since 1.3.8 */ public V get(KeyT variableKey, Class cls, V defaultValue) throws Exception { @@ -370,7 +370,7 @@ public boolean containsVariable(KeyT variableKey) * * @return True if independent value was found in this scope. * - * @since 1.3.7 + * @since 1.3.8 */ @Override public boolean contains(Object value) @@ -415,7 +415,7 @@ public V get(int valueIndex) * * @throws Exception | If converting to object of cls failed from some reason! This can differ from implementation to implementation! * - * @since 1.3.7 + * @since 1.3.8 */ public V get(int valueIndex, Class cls) throws Exception { @@ -475,7 +475,7 @@ public boolean addAll(@SuppressWarnings("unchecked") ValT... values) * * @return True all provided values are contained in this scope as independent values! * - * @since 1.3.7 + * @since 1.3.8 */ @Override public boolean containsAll(Collection values) @@ -488,7 +488,7 @@ public boolean containsAll(Collection values) * * @return {@link Collection#removeAll(Collection)} for the independent values,,, * - * @since 1.3.7 + * @since 1.3.8 */ @Override public boolean removeAll(Collection values) @@ -501,7 +501,7 @@ public boolean removeAll(Collection values) * * @return {@link Collection#retainAll(Collection)} for the independent values,,, * - * @since 1.3.7 + * @since 1.3.8 */ @Override public boolean retainAll(Collection values) @@ -774,7 +774,7 @@ public ValT remove(int valueIndex) * * @return Value of variable that was removed! * - * @since 1.3.7 + * @since 1.3.8 */ @Override public boolean remove(Object independentValue) @@ -787,7 +787,7 @@ public boolean remove(Object independentValue) * * @return Value of variable that was removed! * - * @since 1.3.7 + * @since 1.3.8 */ public ValT removeVariable(KeyT variableKey) { @@ -869,7 +869,7 @@ public int variablesCount() /** * @return Total number of variables and independent values of this scope! (vvaluesCount() + variablesCount()) * - * @since 1.3.7 (before 1.3.7 known as totalSize) + * @since 1.3.8 (before 1.3.8 known as totalSize) */ @Override public int size() @@ -948,7 +948,7 @@ public List toValList() * @return Primitive array with independent values of this {@link GenericScope}. These values have nothing to do with values of variables, they are independent! * Modifying this list will not affect this {@link GenericScope} object! * - * @since 1.3.7 (before 1.3.7 known as toValArray) + * @since 1.3.8 (before 1.3.8 known as toValArray) */ @Override public Object[] toArray() @@ -962,7 +962,7 @@ public Object[] toArray() * @return Primitive array with independent values of this {@link GenericScope}. These values have nothing to do with values of variables, they are independent! * Modifying this list will not affect this {@link GenericScope} object! * - * @since 1.3.7 (before 1.3.7 known as toValArray) + * @since 1.3.8 (before 1.3.8 known as toValArray) */ @Override public T[] toArray(T[] vals) @@ -1088,7 +1088,7 @@ public static > S intoBidirectional(S scopeTo * * @return Same map populated with kV array. * - * @since 1.3.7 + * @since 1.3.8 */ @SuppressWarnings("unchecked") public static > M mapKvArray(M map, Object... kVkVkV) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java index a7a9fc0..00e7652 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java @@ -1291,7 +1291,7 @@ public static T into(T obj, GenericScope fromScope, List< * * @throws Exception if Scope#intoNew(Type, GenericScope, String...) fails... * - * @since 1.3.7 + * @since 1.3.8 */ @SuppressWarnings("unchecked") public static List intoGeneric(List listToGenerify, ParameterizedType genericType) throws Exception @@ -1331,7 +1331,7 @@ public static List intoGeneric(List listToGenerify, ParameterizedType * * @throws Exception if Scope#intoNew(Type, GenericScope, String...) fails... * - * @since 1.3.7 + * @since 1.3.8 */ @SuppressWarnings("unchecked") public static Map intoGeneric(Map mapToGenerify, ParameterizedType genericType) throws Exception @@ -1400,7 +1400,7 @@ public static List getPropertyDescriptorsOf(Class cls, Ma * * @see PropertyDescriptor * - * @since 1.3.7 + * @since 1.3.8 */ public static List getPropertyDescriptorsOf(Class cls, Map, List> cache, int modifiersToIgnore, String... fieldNames) throws IntrospectionException { diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 07f0b61..95fd1d3 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -605,7 +605,7 @@ public A SerializeAsSubscope(A source, char[] wrappingBra * * @return Object that was parsed from string at given index, using parsers of this {@link Serializer}! * - * @since 1.3.7 + * @since 1.3.8 */ @SuppressWarnings("unchecked") public T getParsed(int indexWithStringValue, Object... args) @@ -619,7 +619,7 @@ public T getParsed(int indexWithStringValue, Object... args) * * @return Object that was parsed from value of given variable, using parsers of this {@link Serializer}! * - * @since 1.3.7 + * @since 1.3.8 */ @SuppressWarnings("unchecked") public T getParsed(String variableWithStringValue, Object... args) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index 024a320..52e35b2 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -30,7 +30,7 @@ * * @author PETO * - * @since 1.3.7 + * @since 1.3.8 */ public final class Utils { private Utils() {} @@ -522,7 +522,7 @@ public static String[] splitValues(String s, int limit, int splittingStrategy, c * * @return String splitted after splitters according to arguments. Each resulting token will be {@link String#trim() trim}med! * - * @since 1.3.7 + * @since 1.3.8 */ public static String[] splitValues(String s, int i, int limit, int splittingStrategy, char[] splitBreaks, char... splitter) { @@ -784,7 +784,7 @@ public static boolean contains(CharSequence str, char... oneOf) * Note that this function was designed for non-blank ASCII strings and may not work properly for others...
* Also sufficient length of both strings is not checked so adjust from and to accordingly. * - * @since 1.3.7 + * @since 1.3.8 */ public static boolean equalsLowerCase(CharSequence str, CharSequence lowerCaseOther, int from, int to) { @@ -852,7 +852,7 @@ public static Object[] mergeArrays(Object arr1, Object arr2) * * @throws IllegalArgumentException if the specified object is not an array! * - * @since 1.3.2 (since 1.3.7 moved from ArrayConverter) + * @since 1.3.2 (since 1.3.8 moved from ArrayConverter) */ public static Object[] fromAmbiguousArray(Object array) { @@ -912,7 +912,7 @@ public static void post(Serializer serializer, HttpURLConnection conn) throws IO * * @since 1.2.2 * - * @deprecated (in 1.3.7) NO LONGER NEEDED, DO NOT USE THIS! You were never supposed to... + * @deprecated (in 1.3.8) NO LONGER NEEDED, DO NOT USE THIS! You were never supposed to... */ public static final class NULL //TODO: REMOVE IN NEXT V!!!! { diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index e215655..2b7ac42 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -199,7 +199,7 @@ public CharSequence toString(Object obj, Object... args) * * @see DataParser#parseObj(String, Object...) * - * @since 1.3.7 + * @since 1.3.8 */ @Override public Object parse(ParserRegistry parentRegistry, String str, Object... args) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java index e873476..2b4a998 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/NumberConverter.java @@ -155,7 +155,7 @@ public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Ob * * @return Number formated to string! * - * @since 1.3.7 + * @since 1.3.8 */ public String format(Number num) { @@ -174,7 +174,7 @@ public String format(Number num) * @return {@link Number} parsed from str with rules specified above. This function was designed to act as more optimized merger of {@link Byte#valueOf(String, int)}, {@link Short#valueOf(String, int)}, {@link Integer#valueOf(String, int)}, {@link Long#valueOf(String, int)} and {@link Float#valueOf(String)}, {@link Double#valueOf(String)} all encapsulated in 1 universal function.
* Note: This function will not check for incorrect number formats in order to save performance. Only incorrect format is when inserted string contains space, in this case it will return null! * - * @since 1.3.7 + * @since 1.3.8 */ public static Number numberOf(CharSequence str, char ch0, int end, int base, int type) { diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java index c41079c..6c8332a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java @@ -54,7 +54,7 @@ * * @author PETO * - * @since 1.3.0 (separated from ObjectConverter since 1.3.7) + * @since 1.3.0 (separated from ObjectConverter since 1.3.8) */ public class ProtocolConverter implements DataConverter { @@ -96,7 +96,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... compile * * @return Object od objClass parsed from str in accordance with compilerArgs! * - * @since 1.3.7 + * @since 1.3.8 */ protected Object parse(ParserRegistry myHomeRegistry, Class objClass, String str, Object... compilerArgs) { @@ -284,7 +284,7 @@ public void setUseBase64IfCan(boolean useBase64IfCan) /** * @return True if invocation of static members (:: operator) is allowed (false by default)! * - * @since 1.3.7 + * @since 1.3.8 */ public boolean isAllowStaticMemberInvocation() { @@ -294,7 +294,7 @@ public boolean isAllowStaticMemberInvocation() /** * @param allowStaticMemberInvocation | Enable/disable the invocation of static members (:: operator) (false by default)! * - * @since 1.3.7 + * @since 1.3.8 */ public void setAllowStaticMemberInvocation(boolean allowStaticMemberInvocation) { @@ -407,7 +407,7 @@ public static char[] secondarySubscopeWrappers() * @return {@link Utils#InvokeStaticFunc(Class, String, Object...)} or null if {@link InvocationTargetException} occurred.
* Note: If you are not sure what this does, preferably use {@link Utils#InvokeStaticFunc(Class, String, Object...)}! * - * @since 1.3.7 + * @since 1.3.8 */ public static Object InvokeStaticFunc(Class cls, Class oldCls, String name, Object[] args, Object... compilerArgs) { try diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java index 1314103..2e61b8b 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java @@ -108,7 +108,7 @@ public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Ob * Recommended: Enable this when parsing a lot of strings that are the same, otherwise this will not have a big impact.
* Rule of thumb, is that this cache should be modified only by this converter however adding some pre-cached entries is possible but should be performed with caution! * - * @since 1.3.7 + * @since 1.3.8 */ public void setParsingCache(Map cache) { @@ -120,7 +120,7 @@ public void setParsingCache(Map cache) * Null will be returned if caching is disabled, which is by default...
* Note: Rule of thumb, is that this cache should be modified only by this converter however adding some pre-cached entries is possible but should be performed with caution! * - * @since 1.3.7 + * @since 1.3.8 */ public Map getParsingCache() { @@ -130,7 +130,7 @@ public Map getParsingCache() /** * @return Will return value of {@link StringConverter#serializeStringNormally}! * - * @since 1.3.7 (it was static before = not good) + * @since 1.3.8 (it was static before = not good) */ public boolean isSerializeStringNormally() { @@ -140,7 +140,7 @@ public boolean isSerializeStringNormally() /** * @param serializeStringNormally | Set value of {@link StringConverter#serializeStringNormally}! * - * @since 1.3.7 (it was static before = not good) + * @since 1.3.8 (it was static before = not good) */ public void setSerializeStringNormally(boolean serializeStringNormally) { diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java index ba99062..0f9af02 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java @@ -18,7 +18,7 @@ * * @author PETO * - * @since 1.3.7 + * @since 1.3.8 */ public class VariableParser implements DataParser { @@ -40,7 +40,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) * @return The value of member from given source. You can think about this as ekvivalent to source.member in Java. If member with provided name/key is not present in the source or its value is not possible to get, {@link VOID} has to be returned! If source can't be accessed/dereferenced, null has to be returned!
* Note: This method is meant to be overridden in order to add support for accessing multiple sources because by default it supports only {@link GenericScope} * - * @since 1.3.7 + * @since 1.3.8 */ @SuppressWarnings("unchecked") public Object getMemberOperator(Object source, Object member) @@ -58,7 +58,7 @@ public Object getMemberOperator(Object source, Object member) * * @return Value of variable read from scope is str was suitable. Special return types are {@link DataParser#VOID} and {@link DataParser#CONTINUE}. Continue will ignore this parser and jump to another one in registry. * - * @since 1.3.7 + * @since 1.3.8 */ protected Object parse(ParserRegistry myHomeRegistry, String str, GenericScope scope, Object... args) { diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java index 06a89a7..835bcc7 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java @@ -22,7 +22,7 @@ public interface ImportsProvider * Cache of Classes to their respective names/aliases.
* Note: Treat as read only if possible! * - * @since 1.3.7 + * @since 1.3.8 */ public static final Map> CLASS_CACHE = new HashMap>(); diff --git a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java index bc7e8e0..cf31e39 100644 --- a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java +++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/DebugParserRegistry.java @@ -38,7 +38,7 @@ public DebugParserRegistry clone() * * @return Clone of this {@link DebugParserRegistry} * - * @since 1.3.7 + * @since 1.3.8 */ public DebugParserRegistry clone(boolean copyStackTrace) { diff --git a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java index bcbc5c4..7a7a970 100644 --- a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java +++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java @@ -32,7 +32,7 @@ public class SerializationDebugger implements DataConverter * Output object that will be used for logging... * If null, it will be set automatically! * - * @since 1.3.7 + * @since 1.3.8 */ public static PrintWriter out; @@ -145,7 +145,7 @@ else if (args[99] instanceof Integer && (int) args[99] > 0) /** * Helper method for printing contents of {@link ParserRegistry#getParsingCache()}. * - * @since 1.3.7 + * @since 1.3.8 */ public static void printCacheInfo(PrintWriter out, DataParser[] cache, String cacheType, String additional) { diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java index 0a33ab2..a5ae395 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java @@ -257,7 +257,7 @@ public static JsonSerializer fromJussSerializer(JussSerializer jussSerializer) * * @return JussSerializer created from JsonSerializer, all values and variables will remain intact! * - * @since 1.3.2 (since 1.3.7 moved from {@link JussSerializer} and renamed from "fromJsonSerializer" to "toJussSerializer") + * @since 1.3.2 (since 1.3.8 moved from {@link JussSerializer} and renamed from "fromJsonSerializer" to "toJussSerializer") */ public static JussSerializer toJussSerializer(JsonSerializer jsonSerializer) { diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java index d9fc561..9067423 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonCharacterConverter.java @@ -7,7 +7,7 @@ * * @author PETO * - * @since 1.3.7 + * @since 1.3.8 */ public class JsonCharacterConverter extends CharacterConverter { @@ -16,7 +16,7 @@ public class JsonCharacterConverter extends CharacterConverter /** * @param formatAsString | If true, character will be serialized in a letter form. Otherwise it will be serialized as ASCII value (int). * - * @since 1.3.7 + * @since 1.3.8 */ public JsonCharacterConverter(boolean formatAsString) { @@ -34,7 +34,7 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object.. /** * @return True if character is going to be serialized in a letter form. If false, it will be serialized as ASCII value (int). * - * @since 1.3.7 + * @since 1.3.8 */ public boolean isFormatAsString() { @@ -44,7 +44,7 @@ public boolean isFormatAsString() /** * @param formatAsString | If true, character will be serialized in a letter form. Otherwise it will be serialized as ASCII value (int). * - * @since 1.3.7 + * @since 1.3.8 */ public void setFormatAsString(boolean formatAsString) { diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java index 0f2e76e..402f0e8 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonNumberConverter.java @@ -7,7 +7,7 @@ * * @author PETO * - * @since 1.3.7 + * @since 1.3.8 */ public class JsonNumberConverter extends NumberConverter { diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index 939f75e..ce5faab 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -67,7 +67,7 @@ public class JussSerializer extends Serializer implements ImportsProvider /** * {@link ParserRegistry} with all parsers required to parse JUSS with additional operators. *
- * Since 1.3.7 this requires "org.ugp.serialx.converters.Operators" from SerialX "operators" modules to be present on the classpath! + * Since 1.3.8 this requires "org.ugp.serialx.converters.Operators" from SerialX "operators" modules to be present on the classpath! * * @since 1.3.2 */ diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java index f62765b..56f4331 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java @@ -26,7 +26,7 @@ public class OperationGroups implements DataParser { /** - * @deprecated (since 1.3.7) DO NOT USE, USE {@link OperationGroups#groupMark} instead!
+ * @deprecated (since 1.3.8) DO NOT USE, USE {@link OperationGroups#groupMark} instead!
* * Opening and closing of group mark! * @@ -39,7 +39,7 @@ public class OperationGroups implements DataParser * Character marking the opening of {@link OperationGroups} mark in processed string, closing should be marked as this character -1.
* This character is generated in sami-random fashion but it will never be an ASCII character. * - * @since 1.3.7 + * @since 1.3.8 */ protected final char groupMark = (char) (System.nanoTime() | 128); diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index 9d281e1..a322a66 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -163,7 +163,7 @@ public CharSequence getDescription(ParserRegistry myHomeRegistry, Object objToDe * * @return By default it returns the previous value of the member. If member with provided name/key is not present in the source or its value is not possible to set, {@link VOID} should be returned! * - * @since 1.3.7 + * @since 1.3.8 */ @SuppressWarnings("unchecked") public Object setMemberOperator(ParserRegistry myHomeRegistry, Object source, String member, Object val, boolean genericVar, Object... args) diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java index a4317af..3afe55f 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java @@ -15,7 +15,7 @@ public class SelfSerializableProtocol extends Univer * @param applicableFor | Class implementing {@link SelfSerializable} that can be serialized using this protocol.
* Note: Passing {@link SelfSerializable#getClass()} will make this protocol universal and work for any {@link SelfSerializable} instance, this can be considered unsafe in some cases... * - * @since 1.3.7 + * @since 1.3.8 */ public SelfSerializableProtocol(Class applicableFor) { diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java index 22a8e25..cf60821 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java @@ -27,7 +27,7 @@ public class UniversalObjectInstantiationProtocol extends SerializationProtoc * @param applicableFor | Class that can be serialized using this protocol. * Note: Passing {@link Object#getClass()} will make this protocol universal and work for any {@link Object} instance, this can be considered unsafe in some cases... * - * @since 1.3.7 + * @since 1.3.8 */ public UniversalObjectInstantiationProtocol(Class applicableFor) { diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/Operators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/Operators.java index 64c0c9f..e0aa691 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/Operators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/Operators.java @@ -14,7 +14,7 @@ * * @see Operators#install(ParserRegistry) * - * @since 1.3.7 + * @since 1.3.8 * * @author PETO */ @@ -28,7 +28,7 @@ public class Operators { * {@link ArithmeticOperators}
* In given order! * - * @since 1.3.7 + * @since 1.3.8 */ public static final DataParser[] BINARY = { new ConditionalAssignmentOperators(), new LogicalOperators(), new ComparisonOperators(), new ArithmeticOperators() }; @@ -37,7 +37,7 @@ public class Operators { * {@link NegationOperator}
* In given order! * - * @since 1.3.7 + * @since 1.3.8 */ public static final DataParser[] UNARY = { new NegationOperator() }; @@ -46,7 +46,7 @@ public class Operators { * * @return The same registry with operators inserted! * - * @since 1.3.7 + * @since 1.3.8 */ public static ParserRegistry install(ParserRegistry registry) { registry.addAllBefore(StringConverter.class, true, BINARY); @@ -59,7 +59,7 @@ public static ParserRegistry install(ParserRegistry registry) { * * @return The same registry with no more operators! * - * @since 1.3.7 + * @since 1.3.8 */ public static ParserRegistry uninstall(ParserRegistry registry) { registry.removeAll(Arrays.asList(BINARY)); diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java index 62f7bf7..8508845 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -31,7 +31,7 @@ public class ArithmeticOperators implements DataParser /** * Operator characters recognized by {@link ArithmeticOperators}, operators can be any combination of provided characters. Exact behavior is handled by {@link ArithmeticOperators#operator(Object, String, Object)}.
Intended for override, should not be null or empty! * - * @since 1.3.7 + * @since 1.3.8 */ protected char[] operators = {'+', '-', '*', '/', '%'}; @@ -97,7 +97,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) * * @return Result of binary operation described by op between opr1 and opr2! If operator is not known, opr1 will be returned by default! * - * @since 1.3.7 + * @since 1.3.8 */ public Object operator(Object opr1, String op, Object opr2) { @@ -125,7 +125,7 @@ public Object operator(Object opr1, String op, Object opr2) * * @return Priority of provided operator (higher number = higher priority, 2 = high, 1 = medium, 0 = low) * - * @since 1.3.7 + * @since 1.3.8 */ public byte getOperatorPriority(String op) { @@ -395,7 +395,7 @@ public static Object pow(Object cof, Object cof2, int sign) * * @return Array with 2 lists. Index 0 is {@link ArrayList} containing parsed operands of the expression, index 1 is {@link LinkedList} containing operators of the expression! * - * @since 1.3.7 (originally getTerms since 1.3.0) + * @since 1.3.8 (originally getTerms since 1.3.0) */ @SuppressWarnings("unchecked") public static List[] getAndParseTerms(String str, int to, ParserRegistry registryForParsers, Object[] argsForParsers, Class classToIgnore, char... oprs) diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java index 99f6702..2f727bb 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/NegationOperator.java @@ -55,7 +55,7 @@ public Object notOperator(Object obj) * @return Negated object supposed to be returned or same object as argument if object can't be negated! Should, but do not strictly has to be boolean!
* Node: By default it has same behavior as {@link NegationOperator#notOperator(Object)} but it can be overridden! * - * @since 1.3.7 + * @since 1.3.8 */ public Object logicalNotOperator(Object obj) { From 6b93039678956eac21cb41b1a373ea04a55990e4 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sun, 4 Aug 2024 16:19:45 +0200 Subject: [PATCH 36/48] poms --- SerialX-core/pom.xml | 2 +- .../ugp/serialx/converters/ProtocolConverter.java | 13 ++++--------- SerialX-devtools/pom.xml | 2 +- .../java/org/ugp/serialx/json/JsonSerializer.java | 4 +--- .../ugp/serialx/juss/converters/ArrayConverter.java | 7 ++----- .../serialx/juss/converters/VariableConverter.java | 6 ++---- 6 files changed, 11 insertions(+), 23 deletions(-) diff --git a/SerialX-core/pom.xml b/SerialX-core/pom.xml index 561fa3b..fec3b0e 100644 --- a/SerialX-core/pom.xml +++ b/SerialX-core/pom.xml @@ -11,5 +11,5 @@ 1.3.7 SerialX core - Core of SerialX + Core of SerialX. Contains core features and utilities shared across the library. \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java index 6c8332a..a5a5a3c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java @@ -190,23 +190,18 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Serializ if (preferedProtocol != null || (preferedProtocol = (SerializationProtocol) getProtocolFor(arg, SerializationProtocol.MODE_SERIALIZE, args)) != null) { - Object[] objArgs; Class oldObjectClass = null; try { - int tabs = 0, index = 0; - if (args.length > 1 && args[1] instanceof Integer) - tabs = (int) args[1]; - - if (args.length > 2 && args[2] instanceof Integer) - index = (int) args[2]; + int tabs = args.length > 1 && args[1] instanceof Integer ? (int) args[1] : 0; + int index = args.length > 2 && args[2] instanceof Integer ? (int) args[2] : 0; if (args.length < 5) args = Arrays.copyOf(args, 5); oldObjectClass = (Class) args[4]; args[4] = arg.getClass();; - objArgs = preferedProtocol.serialize(arg); + Object[] objArgs = preferedProtocol.serialize(arg); StringBuilder sb = new StringBuilder(ImportsProvider.getAliasFor(args.length > 0 ? args[0] : null, arg.getClass()) + (objArgs.length <= 0 ? "" : " ")); args = args.clone(); @@ -231,7 +226,7 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Serializ args[4] = oldObjectClass; return index > 0 && objArgs.length > 0 ? sb.insert(0, '{').append('}') : sb; } - catch (Exception e) + catch (Exception e) { LogProvider.instance.logErr("Exception while serializing instance of \"" + arg.getClass().getName() + "\":", e); e.printStackTrace(); diff --git a/SerialX-devtools/pom.xml b/SerialX-devtools/pom.xml index 2140bc2..f53382c 100644 --- a/SerialX-devtools/pom.xml +++ b/SerialX-devtools/pom.xml @@ -11,7 +11,7 @@ 1.3.7 SerialX devtools - Tools for debugging... + Tools for debugging, mainly for Parser/Converter API. It is intended for DSL developers and people who want to add their own data formats. diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java index a5ae395..2209204 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java @@ -177,9 +177,7 @@ public S LoadFrom(Reader reader, Object... formatArgs) @Override public A SerializeTo(A source, Object... args) throws IOException { - int tabs = 0; - if (args.length > 1 && args[1] instanceof Integer) - tabs = (int) args[1]; + int tabs = args.length > 1 && args[1] instanceof Integer ? (int) args[1] : 0; if (tabs == 0 && !(valuesCount() == 1 && variablesCount() <= 0 && get(0) instanceof Scope)) { diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java index b5882bd..a71e0d3 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ArrayConverter.java @@ -90,14 +90,11 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object.. { if (obj != null && myHomeRegistry != null && obj.getClass().isArray()) { - int tabs = 0, index = 0; - if (args.length > 2 && args[2] instanceof Integer) - index = (int) args[2]; + int index = args.length > 2 && args[2] instanceof Integer ? (int) args[2] : 0; if (index <= 0 || myHomeRegistry.indexOf(OperationGroups.class) > -1) { - if (args.length > 1 && args[1] instanceof Integer) - tabs = (int) args[1]; + int tabs = args.length > 1 && args[1] instanceof Integer ? (int) args[1] : 0; if (args.length > 2) { diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index a322a66..e331296 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -132,11 +132,9 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object.. if (obj instanceof Entry) { Entry var = (Entry) obj; - int tabs = 0; - if (args.length > 1 && args[1] instanceof Integer) - tabs = (int) args[1]; + int tabs = args.length > 1 && args[1] instanceof Integer ? (int) args[1] : 0; - boolean jsonStyle = isJsonStyle(), genericVar = false; + boolean jsonStyle = isJsonStyle(), genericVar; Object key = (genericVar = !((key = var.getKey()) instanceof String)) ? myHomeRegistry.toString(key, args) : key, val = var.getValue(); return new StringBuilder().append(jsonStyle && !genericVar ? "\""+key+"\"" : key) .append(val instanceof GenericScope && !((GenericScope) val).isEmpty() ? (jsonStyle ? " : " : " =\n" + multilpy('\t', tabs)) : (jsonStyle ? " : " : " = ")) From 22e0c60917e642e8866ac9240184666d4afaeace Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Mon, 12 Aug 2024 23:08:08 +0200 Subject: [PATCH 37/48] Doing static static member invocation the right way... fixing ObjConv is protocols expr bug, optimizing and improving, docs --- .../src/main/java/org/ugp/serialx/Utils.java | 159 ++++++++++-------- .../ugp/serialx/converters/DataConverter.java | 4 +- .../ugp/serialx/converters/DataParser.java | 2 +- .../serialx/converters/ProtocolConverter.java | 34 ++-- .../serialx/converters/VariableParser.java | 5 +- .../org/ugp/serialx/juss/JussSerializer.java | 70 ++++---- .../juss/converters/ObjectConverter.java | 16 +- .../juss/converters/OperationGroups.java | 72 ++++---- .../juss/converters/VariableConverter.java | 29 ++-- .../ConditionalAssignmentOperators.java | 12 +- 10 files changed, 194 insertions(+), 209 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index 52e35b2..d6c455a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -181,8 +181,8 @@ public static Object InvokeFunc(Object obj, Class objCls, String name, Class< try { Method method = objCls.getMethod(name, argClasses); - Object resualt = method.invoke(obj, args); - return method.getReturnType().equals(void.class) ? VOID : resualt; + Object result = method.invoke(obj, args); + return method.getReturnType().equals(void.class) ? VOID : result; } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException find) { @@ -190,8 +190,8 @@ public static Object InvokeFunc(Object obj, Class objCls, String name, Class< if (method.getName().equals(name)) try { - Object resualt = method.invoke(obj, args); - return method.getReturnType().equals(void.class) ? VOID : resualt; + Object result = method.invoke(obj, args); + return method.getReturnType().equals(void.class) ? VOID : result; } catch (IllegalArgumentException e) {} @@ -224,8 +224,8 @@ public static T Clone(T obj) /** * @param obj | Object to clone. * @param parsersToUse | Parsers that will be used for cloning... - * @param converterArgs | Argument for {@link DataConverter#objToString(Registry, Object, Object...)}! - * @param parserArgs | Arguments for {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)}! + * @param converterArgs | Argument for {@link DataConverter#objToString(Object, Object...)}! + * @param parserArgs | Arguments for {@link ParserRegistry#parse(String, boolean, Class, Object...)}! * * @return Cloned object using {@link DataParser}, {@link DataConverter} and {@link SerializationProtocol} or the same object as inserted one if cloning is not possible, for instance when protocol was not found and object is not instance of {@link Cloneable}. * This clone function will always prioritized the Protocol variation, regular cloning is used only when there is no protocol registered or exception occurs.
@@ -534,18 +534,21 @@ public static String[] splitValues(String s, int i, int limit, int splittingStra List result = new ArrayList<>(); - int brackets = 0, quote = 0, lastIndex = 0, len = s.length(); + int brackets = 0, lastIndex = 0, len = s.length(); for (int count = 1, oldCh = 0; i < len && (limit <= 0 || count < limit); i++) { char ch = s.charAt(i); if (ch == '"') - quote++; - - if (quote % 2 == 0) + { + do if (++i >= len) + throw new IllegalArgumentException("Unclosed or missing quotes in: " + s); + while (s.charAt(i) != '"'); + } + else { if (isOneOf(ch, splitBreaks)) { - brackets = quote = 0; + brackets = 0; break; } @@ -576,13 +579,8 @@ else if ((ch | ' ') == '}') if (brackets > 0) throw new IllegalArgumentException("Unclosed brackets in: " + s); - else if (quote % 2 != 0) - throw new IllegalArgumentException("Unclosed or missing quotes in: " + s); - else - { - result.add(s.substring(lastIndex, len).trim()); - } - + + result.add(s.substring(lastIndex, len).trim()); return result.toArray(new String[0]); } @@ -609,33 +607,29 @@ public static int indexOfNotInObj(CharSequence s, char... oneOf) * * @return Index of first character found that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}', otherwise -1! * - * @since 1.3.5 + * @since 1.3.5 (expanded in 1.3.8) */ public static int indexOfNotInObj(CharSequence s, int from, int to, int defaultReturn, boolean firstIndex, char... oneOf) { - for (int brackets = 0, quote = 0; from < to; from++) + for (int brackets = 0; from < to; from++) { char ch = s.charAt(from); if (ch == '"') - quote++; - - if (quote % 2 == 0) + while (++from < to && s.charAt(from) != '"'); + else if (brackets == 0 && /*oneOf.length == 0 ? ch == oneOf[0] :*/ isOneOf(ch, oneOf)) { - if (brackets == 0 && /*oneOf.length == 0 ? ch == oneOf[0] :*/ isOneOf(ch, oneOf)) - { - if (firstIndex) - return from; - defaultReturn = from; - } - else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing closing bracket in: " + s); - } + if (firstIndex) + return from; + defaultReturn = from; + } + else if ((ch | ' ') == '{') + brackets++; + else if ((ch | ' ') == '}') + { + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing closing bracket in: " + s); } } return defaultReturn; @@ -643,64 +637,71 @@ else if ((ch | ' ') == '}') /** * @param s | CharSequence to search! - * @param sequenceToFind | CharSequence to find! + * @param sequencesToFind | Character sequences to find, index of any of these will be returned accordingly, none of these should contain and object structure! * * @return Index of first found CharSequence that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! * * @since 1.3.0 */ - public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind) + public static int indexOfNotInObj(CharSequence s, CharSequence... sequencesToFind) { - return indexOfNotInObj(s, sequenceToFind, true); + return indexOfNotInObj(s, 0, s.length(), -1, true, sequencesToFind); } /** * @param s | CharSequence to search! - * @param sequenceToFind | CharSequence to find! + * @param from | The beginning index, where to start the search (should be 0 in most cases). + * @param to | Ending index of search (exclusive, should be s.length()). + * @param defaultReturn | Index to return by default (usually -1). * @param firstIndex | If true, first index will be returned, if false last index will be returned. + * @param sequencesToFind | Character sequences to find, index of any of these will be returned accordingly, none of these should contain and object structure! * * @return Index of first found CharSequence that is not in object meaning it is not in string nor between '{' or '[' and ']' or '}'! * - * @since 1.3.5 + * @since 1.3.5 (expanded in 1.3.8) */ - public static int indexOfNotInObj(CharSequence s, CharSequence sequenceToFind, boolean firstIndex) + public static int indexOfNotInObj(CharSequence s, int from, int to, int defaultReturn, boolean firstIndex, CharSequence... sequencesToFind) { - int len = s.length(), lenToFind = sequenceToFind.length(); - if (len < lenToFind) - return -1; - int found = -1; - for (int i = 0, brackets = 0, quote = 0, match = 0; i < len; i++) + if (sequencesToFind.length < 1) + return defaultReturn; + + for (int brackets = 0; from < to; from++) { - char ch = s.charAt(i); + char ch = s.charAt(from); if (ch == '"') - quote++; - - if (quote % 2 == 0) + while (++from < to && s.charAt(from) != '"'); + else if ((ch | ' ') == '{') + brackets++; + else if ((ch | ' ') == '}') { - if (brackets == 0 && ch == sequenceToFind.charAt(match++)) + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing closing bracket in: " + s); + } + else if (brackets == 0) + { + findMatch: for (int cur = 0, seqsLen = sequencesToFind.length; cur < seqsLen; cur++) { - if (match == lenToFind) + CharSequence currentMatch; + if (ch == (currentMatch = sequencesToFind[cur]).charAt(0)) { - found = i - match + 1; - if (firstIndex) - return found; - match = 0; + int match = 1, lenToFind = currentMatch.length(); + for (int i = from+1; i < to && match < lenToFind; i++, match++) + if (s.charAt(i) != currentMatch.charAt(match)) + continue findMatch; + + if (match == lenToFind) + { + defaultReturn = from; + if (firstIndex) + return defaultReturn; + } } } - else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing closing bracket in: " + s); - } - else - match = 0; } } - return found; + return defaultReturn; } /** @@ -798,14 +799,26 @@ public static boolean equalsLowerCase(CharSequence str, CharSequence lowerCaseOt * @param str | String to display! * @param pos | Position to display! * - * @return String with displayed position by using »! + * @return String with displayed position by using » or ^ under it! * Use for debugging or error printing! * * @since 1.3.2 */ public static String showPosInString(CharSequence str, int pos) { - return str.subSequence(0, pos) + "»" + str.subSequence(pos, str.length()); + if (pos < 0) + return str.toString(); + + try + { + if (contains(str, '\n', '\r')) + return str.subSequence(0, pos) + "»" + str.subSequence(pos, str.length()); + return multilpy(' ', pos).append('^').insert(0, '\n').insert(0, str).toString(); + } + catch (IndexOutOfBoundsException e) + { + return str.toString(); + } } /* Arrays */ diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java index 6c11480..71bc6e2 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataConverter.java @@ -1,7 +1,5 @@ package org.ugp.serialx.converters; -import org.ugp.serialx.Registry; - /** * This is DataParser with extended functionality! {@link DataConverter} can also parse data like DataParser but is also capable of converting them back to string! * 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! @@ -15,7 +13,7 @@ public interface DataConverter extends DataParser { /** - * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @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)! * @param obj | Object to convert into string! * @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)! * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java index 2b7ac42..d9d1509 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/DataParser.java @@ -44,7 +44,7 @@ public interface DataParser public static final ParserRegistry REGISTRY = new ParserRegistry(new VariableParser(), new StringConverter(), new ProtocolConverter(), new NumberConverter(), new BooleanConverter(), new CharacterConverter(), new NullConverter(), new SerializableBase64Converter()); /** - * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parse(String, boolean, Class, Object...)} otherwise it demands on implementation (it should not be null)! * @param str | Source string, preferably trimed! * @param args | Some additional args. This can be anything and it demands on implementation of DataParser. Default SerialX API implementation will provide one optional argument with {@link Scope} that value was loaded from! * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java index a5a5a3c..033879a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java @@ -9,10 +9,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; +import java.util.HashSet; +import java.util.Set; import org.ugp.serialx.GenericScope; import org.ugp.serialx.LogProvider; -import org.ugp.serialx.Registry; import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; import org.ugp.serialx.Utils; @@ -70,17 +71,17 @@ public class ProtocolConverter implements DataConverter */ protected boolean useBase64IfCan = false; - protected boolean allowStaticMemberInvocation = false; + protected Set> invokableClasses = new HashSet<>(Arrays.asList(Math.class, Scope.class, Double.class, Float.class, String.class)); @Override public Object parse(ParserRegistry myHomeRegistry, String str, Object... compilerArgs) { - int len; + int len; if ((len = str.length()) > 0) { if ((str.charAt(0) | ' ') == '{' && (str.charAt(--len) | ' ') == '}') // Unwrap if wrapped in {} str = str.substring(1, len).trim(); - + Class objClass; if ((objClass = getProtocolExprClass(str, compilerArgs)) != null) // Get class of protocol expr or continue if there is none return parse(myHomeRegistry, objClass, str, compilerArgs); @@ -117,9 +118,9 @@ protected Object parse(ParserRegistry myHomeRegistry, Class objClass, String if ((args[0].charAt(0) | ' ') != '{' && (nameIndex = args[0].indexOf("::")) > -1) //Is static member invocation { String memberName = args[0].substring(nameIndex + 2); - if (!isAllowStaticMemberInvocation()) + if (!getInvokableClasses().contains(objClass)) { - LogProvider.instance.logErr("Invocation of static member \"" + memberName + "\" from class \"" + objClass.getName() + "\" was denied because this feature is disabled by default for security reasons!", null); + LogProvider.instance.logErr("Invocation of static member \"" + memberName + "\" from class \"" + objClass.getName() + "\" was denied because it was not enabled for this class for security reasons!", null); return null; } @@ -169,7 +170,7 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object.. } /** - * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @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)! * @param obj | Object to convert into string! * @param preferedProtocol | Protocol to use preferably. * @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)! @@ -277,23 +278,14 @@ public void setUseBase64IfCan(boolean useBase64IfCan) } /** - * @return True if invocation of static members (:: operator) is allowed (false by default)! - * - * @since 1.3.8 - */ - public boolean isAllowStaticMemberInvocation() - { - return allowStaticMemberInvocation; - } - - /** - * @param allowStaticMemberInvocation | Enable/disable the invocation of static members (:: operator) (false by default)! + * @return Classes that are eligible for public static member invocation (:: operator)!
+ * Note: {@link Math} {@link Scope} {@link Double}, {@link Float} and {@link String} are invokable by default! If you want to disable static member invocation completely, call {@link Set#clear()} on this method! * - * @since 1.3.8 + * @since 1.3.8 */ - public void setAllowStaticMemberInvocation(boolean allowStaticMemberInvocation) + public Set> getInvokableClasses() { - this.allowStaticMemberInvocation = allowStaticMemberInvocation; + return invokableClasses; } /** diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java index 0f9af02..1734435 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java @@ -5,7 +5,6 @@ import static org.ugp.serialx.Utils.splitValues; import org.ugp.serialx.GenericScope; -import org.ugp.serialx.Registry; import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; @@ -51,7 +50,7 @@ public Object getMemberOperator(Object source, Object member) } /** - * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @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)! * @param str | Source string, should not be null or empty (preferably with some variables to read)! * @param scope | Source scope to read from, can't be null! * @param args | Some additional args. This can be anything and it demands on implementation of DataParser. @@ -112,4 +111,4 @@ else if (newModif = str.endsWith("::new")) return CONTINUE; } -} +} \ No newline at end of file diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index ce5faab..f857eeb 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -569,7 +569,7 @@ else if (ch == '}' || ch == ']') sb.append(ch); } } - sb.append(lastNotBlank == '}' || lastNotBlank == ']' ? ';' : ' '); + sb.append((lastNotBlank | ' ') == '}' ? ';' : ' '); } else sb.append(line).append('\n'); @@ -596,57 +596,49 @@ protected List splitAndParse(StringBuilder formattedStr, Object... parse ParserRegistry reg = getParsers(); //DataParser[] parsers = new DataParser[DataParser.REGISTRY.size()]; - int brackets = 0, quote = 0, lastIndex = 0, len = formattedStr.length(); + int brackets = 0, lastIndex = 0, len = formattedStr.length(); //boolean isBracketSplit = false; for (int i = 0; i < len; i++) { char ch = formattedStr.charAt(i); if (ch == '"') - quote++; - - if (quote % 2 == 0) { - /*if (isBracketSplit) - add = 0; - isBracketSplit = false;*/ - if (brackets == 0 && (ch == ';' || ch == ',')/* || (brackets == 1 && (isBracketSplit = ch == '}' || ch == ']'))*/) - { - String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i /*+ (isBracketSplit ? 1 : 0)*/).trim(); - if (!str.isEmpty()) - { - Object obj = parseObject(reg, str, parserArgs); - if (obj != VOID) - result.add(obj); - } - //add = 1; - } - else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') + do if (++i >= len) + throw new IllegalArgumentException("Unclosed or missing quotes in: " + formattedStr); + while (formattedStr.charAt(i) != '"'); + } + else if (brackets == 0 && (ch == ';' || ch == ',')/* || (brackets == 1 && (isBracketSplit = ch == '}' || ch == ']'))*/) + { + String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i /*+ (isBracketSplit ? 1 : 0)*/).trim(); + if (!str.isEmpty()) { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing opening bracket in: " + formattedStr); + Object obj = parseObject(reg, str, parserArgs); + if (obj != VOID) + result.add(obj); } + //add = 1; } - } - - if (quote % 2 != 0) - throw new IllegalArgumentException("Unclosed or missing quotes in: " + formattedStr); - else if (brackets > 0) - throw new IllegalArgumentException("Unclosed brackets in: " + formattedStr); - else - { - String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, len).trim(); - if (!str.isEmpty()) + else if ((ch | ' ') == '{') + brackets++; + else if ((ch | ' ') == '}') { - Object obj = parseObject(reg, str, parserArgs); - if (obj != VOID) - result.add(obj); + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing opening bracket in: " + formattedStr); } } + if (brackets > 0) + throw new IllegalArgumentException("Unclosed brackets in: " + formattedStr); + + String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, len).trim(); + if (!str.isEmpty()) + { + Object obj = parseObject(reg, str, parserArgs); + if (obj != VOID) + result.add(obj); + } return result; } diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java index 086ac55..e666a2d 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java @@ -9,7 +9,6 @@ import java.util.Base64; import org.ugp.serialx.GenericScope; -import org.ugp.serialx.Registry; import org.ugp.serialx.Scope; import org.ugp.serialx.Serializer; import org.ugp.serialx.converters.DataParser; @@ -79,16 +78,19 @@ public class ObjectConverter extends ProtocolConverter @Override public Object parse(ParserRegistry myHomeRegistry, String str, Object... compilerArgs) { - int len; + int len; if ((len = str.length()) > 0) { - boolean hasOp, hasCls = false; - if ((hasOp = (str.charAt(0) | ' ') == '{') && (hasCls = (str.charAt(--len) | ' ') == '}')) // Unwrap if wrapped in {} - len = (str = str.substring(1, len).trim()).length(); + boolean hasOp, hasCls; + if ((hasOp = (str.charAt(0) | ' ') == '{') && (hasCls = (str.charAt(len-1) | ' ') == '}')) // Unwrap if wrapped in {} + len = (str = str.substring(1, --len).trim()).length(); + else + hasCls = false; Class objClass; int chI; - if (((chI = indexOfNotInObj(str, '=', ':', ';', ',')) < 0 || (++chI < len && str.charAt(chI) == ':')) && (objClass = getProtocolExprClass(str, compilerArgs)) != null) // Is protocol expr +// if (((chI = indexOfNotInObj(str, '=', ':', ';', ',')) == -1 || indexOfNotInObj(str, chI, len, -1, true, "==", "::") != -1) && (objClass = getProtocolExprClass(str, compilerArgs)) != null) + if (((chI = indexOfNotInObj(str, '=', ':', ';', ',')) == -1 || ++chI < len && str.charAt(chI) == ':' && indexOfNotInObj(str, ++chI, len, -1, true, ';', ',', '=') == -1) && (objClass = getProtocolExprClass(str, compilerArgs)) != null) // Is protocol expr in disguise (I know I know but come up with something better before judging...) return parse(myHomeRegistry, objClass, str, compilerArgs); if (hasOp && hasCls) //Is scope @@ -126,7 +128,7 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object.. } /** - * @param myHomeRegistry | Registry where this parser is registered provided by {@link DataParser#parseObj(Registry, String, boolean, Class[], Object...)} otherwise it demands on implementation (it should not be null)! + * @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)! * @param obj | Object to convert into string! * @param preferedProtocol | Protocol to use preferably. * @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)! diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java index 56f4331..f0d4cce 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java @@ -23,7 +23,7 @@ * * @since 1.3.0 */ -public class OperationGroups implements DataParser +public class OperationGroups implements DataParser { /** * @deprecated (since 1.3.8) DO NOT USE, USE {@link OperationGroups#groupMark} instead!
@@ -127,26 +127,22 @@ public static int isGroupMark(CharSequence s, char groupMark) */ public static int indexOfOpening(CharSequence str, int from, char... openings) { - for (int len = str.length(), quote = 0, brackets = 0; from < len; from++) + for (int len = str.length(), brackets = 0; from < len; from++) { char ch = str.charAt(from); - - if (ch == '\"') - quote++; - else if (quote % 2 == 0) + if (ch == '"') + while (++from < len && str.charAt(from) != '"'); + else if ((ch | ' ') == '{') + brackets++; + else if ((ch | ' ') == '}') { - if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing opening bracket in: " + str); - } - else if (brackets == 0 && isOneOf(ch, openings)) - return from; + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing opening bracket in: " + str); } + else if (brackets == 0 && isOneOf(ch, openings)) + return from; } return -1; } @@ -163,33 +159,29 @@ else if (brackets == 0 && isOneOf(ch, openings)) */ public static int indexOfClosing(CharSequence str, int from, char[] openings, char... closing) { - for (int len = str.length(), quote = 0, brackets = 0, ops = 0; from < len; from++) + for (int len = str.length(), brackets = 0, ops = 0; from < len; from++) { char ch = str.charAt(from); - - if (ch == '\"') - quote++; - else if (quote % 2 == 0) + if (ch == '"') + while (++from < len && str.charAt(from) != '"'); + else if ((ch | ' ') == '{') + brackets++; + else if ((ch | ' ') == '}') { - if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing opening bracket in: " + str); - } - else if (brackets == 0) + if (brackets > 0) + brackets--; + else + throw new IllegalArgumentException("Missing opening bracket in: " + str); + } + else if (brackets == 0) + { + if (isOneOf(ch, openings)) + ops++; + else if (isOneOf(ch, closing)) { - if (isOneOf(ch, openings)) - ops++; - else if (isOneOf(ch, closing)) - { - if (ops == 1) - return from; - ops--; - } + if (ops == 1) + return from; + ops--; } } } diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index e331296..0f00452 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -204,24 +204,21 @@ public void setJsonStyle(boolean jsonStyle) */ public static int isVarAssignment(CharSequence s) { - for (int i = 0, brackets = 0, quote = 0, len = s.length(), oldCh = -1, chNext; i < len; i++) + for (int i = 0, brackets = 0, len = s.length(), oldCh = -1, chNext; i < len; i++) { char ch = s.charAt(i); if (ch == '"') - quote++; - - if (quote % 2 == 0) - { - if (ch == '?') - return -1; - else if (brackets == 0 && (ch == '=' || ch == ':') && !(oldCh == '=' || oldCh == ':' || oldCh == '!' || oldCh == '>'|| oldCh == '<') && (i >= len-1 || !((chNext = s.charAt(i+1)) == '=' || chNext == ':' || chNext == '!' || chNext == '>'|| chNext == '<'))) - return i; - else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - if (brackets > 0) - brackets--; - } + while (++i < len && s.charAt(i) != '"'); + else if (ch == '?') + return -1; + else if (brackets == 0 && (ch == '=' || ch == ':') && !(oldCh == '=' || oldCh == ':' || oldCh == '!' || oldCh == '>'|| oldCh == '<') && (i >= len-1 || !((chNext = s.charAt(i+1)) == '=' || chNext == ':' || chNext == '!' || chNext == '>'|| chNext == '<'))) + return i; + else if ((ch | ' ') == '{') + brackets++; + else if ((ch | ' ') == '}') + if (brackets > 0) + brackets--; + oldCh = ch; } return -1; @@ -248,4 +245,4 @@ public static Entry NewVariable(String varName, T varValue) { return new AbstractMap.SimpleImmutableEntry<>(varName, varValue); } -} +} \ No newline at end of file diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java index e3ad5cf..768f863 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java @@ -66,16 +66,16 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) */ public static int indexOfTernaryElse(CharSequence str, int defaultCountOfConfitions, char... ternaryOperators) { - for (int i = 0, len = str.length(), oldCh = -1, tokenCount = 0, quote = 0, brackets = 0; i < len; i++) + for (int i = 0, len = str.length(), oldCh = -1, tokenCount = 0, brackets = 0; i < len; i++) { char ch = str.charAt(i); if (ch == '\"') - quote++; + while (++i < len && str.charAt(i) != '"'); else if ((ch | ' ') == '{') brackets++; else if ((ch | ' ') == '}') brackets--; - else if (quote % 2 == 0 && brackets == 0) + else if (brackets == 0) { for (char token : ternaryOperators) if (ch == token && oldCh != token && (i >= len-1 || str.charAt(i+1) != token)) @@ -103,16 +103,16 @@ else if (quote % 2 == 0 && brackets == 0) */ public static int indexOfOne(CharSequence str, int from, char oneChar) { - for (int len = str.length(), oldCh = -1, quote = 0, brackets = 0; from < len; from++) + for (int len = str.length(), oldCh = -1, brackets = 0; from < len; from++) { char ch = str.charAt(from); if (ch == '\"') - quote++; + while (++from < len && str.charAt(from) != '"'); else if ((ch | ' ') == '{') brackets++; else if ((ch | ' ') == '}') brackets--; - else if (quote % 2 == 0 && brackets == 0 && ch == oneChar && oldCh != oneChar && (from >= len-1 || str.charAt(from+1) != oneChar)) + else if (brackets == 0 && ch == oneChar && oldCh != oneChar && (from >= len-1 || str.charAt(from+1) != oneChar)) return from; oldCh = ch; } From df5babeaf6c29193c332c5d0f277bfd7c029d285 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Wed, 14 Aug 2024 00:44:36 +0200 Subject: [PATCH 38/48] small perfromacne improve for string analyse utils, finilizing mvn 1.3.8 --- SerialX-core/pom.xml | 2 +- .../src/main/java/org/ugp/serialx/Utils.java | 120 ++++++++++-------- SerialX-devtools/pom.xml | 2 +- SerialX-json/pom.xml | 2 +- SerialX-juss/pom.xml | 2 +- .../org/ugp/serialx/juss/JussSerializer.java | 32 ++--- .../juss/converters/OperationGroups.java | 46 ++++--- .../juss/converters/VariableConverter.java | 25 ++-- SerialX-operators/pom.xml | 2 +- .../operators/ArithmeticOperators.java | 42 +++--- .../ConditionalAssignmentOperators.java | 44 +++++-- pom.xml | 9 +- 12 files changed, 193 insertions(+), 135 deletions(-) diff --git a/SerialX-core/pom.xml b/SerialX-core/pom.xml index fec3b0e..1d7592f 100644 --- a/SerialX-core/pom.xml +++ b/SerialX-core/pom.xml @@ -8,7 +8,7 @@ org.ugp.serialx core - 1.3.7 + 1.3.8 SerialX core Core of SerialX. Contains core features and utilities shared across the library. diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index d6c455a..3b9f370 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -466,7 +466,8 @@ public static StringBuilder multilpy(CharSequence str, int times) * @param s | String to split and check some syntax. * @param splitter | Chars where string will be split! * - * @return String splitted after splitters. More than one splitter in row will be take as 1. Each resulting token will be {@link String#trim() trim}med! + * @return String splitted after splitters. More than one splitter in row will be take as 1. Each resulting token will be {@link String#trim() trim}med!
+ * Note: Splitting will only occur if splitter is not in object meaning it is not in string nor between '{' or '[' and ']' or '} * * @since 1.0.0 */ @@ -483,7 +484,8 @@ public static String[] splitValues(String s, char... splitter) * If 2, splitting will occur after any number of splitters, n number of splitters in row will be treated as 1! * @param splitter | Chars where string will be split! * - * @return String splitted after splitters according to arguments. Each resulting token will be {@link String#trim() trim}med! + * @return String splitted after splitters according to arguments. Each resulting token will be {@link String#trim() trim}med!
+ * Note: Splitting will only occur if splitter is not in object meaning it is not in string nor between '{' or '[' and ']' or '}' * * @since 1.3.0 */ @@ -501,7 +503,8 @@ public static String[] splitValues(String s, int limit, int splittingStrategy, c * @param splitBreaks | When some of these characters is encountered, splitting is terminated for the rest of the string! * @param splitter | Chars where string will be split! * - * @return String splitted after splitters according to arguments. Each resulting token will be {@link String#trim() trim}med! + * @return String splitted after splitters according to arguments. Each resulting token will be {@link String#trim() trim}med!
+ * Note: Splitting will only occur if splitter is not in object meaning it is not in string nor between '{' or '[' and ']' or '}' * * @since 1.3.5 */ @@ -517,10 +520,11 @@ public static String[] splitValues(String s, int limit, int splittingStrategy, c * @param splittingStrategy | If 0, splitting will occur after each splitter! * If 1, string will be splitted after only one splitter, more than one splitters in row will be ignored! * If 2, splitting will occur after any number of splitters, n number of splitters in row will be treated as 1! - * @param splitBreaks | When some of these characters is encountered, splitting is terminated for the rest of the string! + * @param splitBreaks | When some of these characters is encountered (not in object), splitting is terminated for the rest of the string! * @param splitter | Chars where string will be split! * - * @return String splitted after splitters according to arguments. Each resulting token will be {@link String#trim() trim}med! + * @return String splitted after splitters according to arguments. Each resulting token will be {@link String#trim() trim}med!
+ * Note: Splitting will only occur if splitter is not in object meaning it is not in string nor between '{' or '[' and ']' or '}' * * @since 1.3.8 */ @@ -534,51 +538,47 @@ public static String[] splitValues(String s, int i, int limit, int splittingStra List result = new ArrayList<>(); - int brackets = 0, lastIndex = 0, len = s.length(); + int lastIndex = 0, len = s.length(); for (int count = 1, oldCh = 0; i < len && (limit <= 0 || count < limit); i++) { - char ch = s.charAt(i); + int ch = s.charAt(i); if (ch == '"') { do if (++i >= len) throw new IllegalArgumentException("Unclosed or missing quotes in: " + s); while (s.charAt(i) != '"'); } - else + else if ((ch | ' ') == '{') { - if (isOneOf(ch, splitBreaks)) + for (int brackets = 1; brackets != 0; ) { - brackets = 0; - break; - } - - if (brackets == 0 && isOneOf(ch, splitter) && - (splittingStrategy != 1 || ch != oldCh && (i >= len-1 || !isOneOf(s.charAt(i+1), splitter)))) - { - String tok = s.substring(lastIndex, i).trim(); - if (splittingStrategy < 2 || result.isEmpty() || !tok.isEmpty()) - { - result.add(tok); - lastIndex = i + 1; - - count++; - } + if (++i >= len) + throw new IllegalArgumentException("Missing ("+ brackets + ") closing bracket in: " + s); + if ((ch = (s.charAt(i) | ' ')) == '{') + brackets++; + else if (ch == '}') + brackets--; + else if (ch == '"') + while (++i < len && s.charAt(i) != '"'); } - else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') + } + else if (isOneOf(ch, splitBreaks)) + break; + else if (isOneOf(ch, splitter) && + (splittingStrategy != 1 || ch != oldCh && (i >= len-1 || !isOneOf(s.charAt(i+1), splitter)))) + { + String tok = s.substring(lastIndex, i).trim(); + if (splittingStrategy < 2 || result.isEmpty() || !tok.isEmpty()) { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing opening bracket in: " + s); + result.add(tok); + lastIndex = i + 1; + + count++; } } + oldCh = ch; } - - if (brackets > 0) - throw new IllegalArgumentException("Unclosed brackets in: " + s); result.add(s.substring(lastIndex, len).trim()); return result.toArray(new String[0]); @@ -611,26 +611,31 @@ public static int indexOfNotInObj(CharSequence s, char... oneOf) */ public static int indexOfNotInObj(CharSequence s, int from, int to, int defaultReturn, boolean firstIndex, char... oneOf) { - for (int brackets = 0; from < to; from++) + for (; from < to; from++) { - char ch = s.charAt(from); + int ch = s.charAt(from); if (ch == '"') while (++from < to && s.charAt(from) != '"'); - else if (brackets == 0 && /*oneOf.length == 0 ? ch == oneOf[0] :*/ isOneOf(ch, oneOf)) + else if ((ch | ' ') == '{') + { + for (int brackets = 1; brackets != 0; ) + { + if (++from >= to) + throw new IllegalArgumentException("Missing ("+ brackets + ") closing bracket in: " + s); + if ((ch = (s.charAt(from) | ' ')) == '{') + brackets++; + else if (ch == '}') + brackets--; + else if (ch == '"') + while (++from < to && s.charAt(from) != '"'); + } + } + else if (isOneOf(ch, oneOf)) { if (firstIndex) return from; defaultReturn = from; } - else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing closing bracket in: " + s); - } } return defaultReturn; } @@ -665,21 +670,26 @@ public static int indexOfNotInObj(CharSequence s, int from, int to, int defaultR if (sequencesToFind.length < 1) return defaultReturn; - for (int brackets = 0; from < to; from++) + for (; from < to; from++) { - char ch = s.charAt(from); + int ch = s.charAt(from); if (ch == '"') while (++from < to && s.charAt(from) != '"'); else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing closing bracket in: " + s); + for (int brackets = 1; brackets != 0; ) + { + if (++from >= to) + throw new IllegalArgumentException("Missing ("+ brackets + ") closing bracket in: " + s); + if ((ch = (s.charAt(from) | ' ')) == '{') + brackets++; + else if (ch == '}') + brackets--; + else if (ch == '"') + while (++from < to && s.charAt(from) != '"'); + } } - else if (brackets == 0) + else { findMatch: for (int cur = 0, seqsLen = sequencesToFind.length; cur < seqsLen; cur++) { diff --git a/SerialX-devtools/pom.xml b/SerialX-devtools/pom.xml index f53382c..62408a9 100644 --- a/SerialX-devtools/pom.xml +++ b/SerialX-devtools/pom.xml @@ -8,7 +8,7 @@ org.ugp.serialx devtools - 1.3.7 + 1.3.8 SerialX devtools Tools for debugging, mainly for Parser/Converter API. It is intended for DSL developers and people who want to add their own data formats. diff --git a/SerialX-json/pom.xml b/SerialX-json/pom.xml index 3477e6c..099d015 100644 --- a/SerialX-json/pom.xml +++ b/SerialX-json/pom.xml @@ -8,7 +8,7 @@ org.ugp.serialx json - 1.3.7 + 1.3.8 SerialX json SerialX Json support diff --git a/SerialX-juss/pom.xml b/SerialX-juss/pom.xml index 2c451bd..a37638a 100644 --- a/SerialX-juss/pom.xml +++ b/SerialX-juss/pom.xml @@ -8,7 +8,7 @@ org.ugp.serialx juss - 1.3.7 + 1.3.8 SerialX-juss SerialX support for Java Universal Serial Script data format, custom default format of SerialX! diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index f857eeb..16d8cbe 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -596,18 +596,32 @@ protected List splitAndParse(StringBuilder formattedStr, Object... parse ParserRegistry reg = getParsers(); //DataParser[] parsers = new DataParser[DataParser.REGISTRY.size()]; - int brackets = 0, lastIndex = 0, len = formattedStr.length(); + int lastIndex = 0, len = formattedStr.length(); //boolean isBracketSplit = false; for (int i = 0; i < len; i++) { - char ch = formattedStr.charAt(i); + int ch = formattedStr.charAt(i); if (ch == '"') { do if (++i >= len) throw new IllegalArgumentException("Unclosed or missing quotes in: " + formattedStr); while (formattedStr.charAt(i) != '"'); } - else if (brackets == 0 && (ch == ';' || ch == ',')/* || (brackets == 1 && (isBracketSplit = ch == '}' || ch == ']'))*/) + else if ((ch | ' ') == '{') + { + for (int brackets = 1; brackets != 0; ) + { + if (++i >= len) + throw new IllegalArgumentException("Missing ("+ brackets + ") closing bracket in: " + formattedStr); + if ((ch = (formattedStr.charAt(i) | ' ')) == '{') + brackets++; + else if (ch == '}') + brackets--; + else if (ch == '"') + while (++i < len && formattedStr.charAt(i) != '"'); + } + } + else if ((ch == ';' || ch == ',')/* || (brackets == 1 && (isBracketSplit = ch == '}' || ch == ']'))*/) { String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, lastIndex = i /*+ (isBracketSplit ? 1 : 0)*/).trim(); if (!str.isEmpty()) @@ -618,20 +632,8 @@ protected List splitAndParse(StringBuilder formattedStr, Object... parse } //add = 1; } - else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing opening bracket in: " + formattedStr); - } } - if (brackets > 0) - throw new IllegalArgumentException("Unclosed brackets in: " + formattedStr); - String str = formattedStr.substring(lastIndex == 0 ? 0 : lastIndex + 1, len).trim(); if (!str.isEmpty()) { diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java index f0d4cce..9a95205 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/OperationGroups.java @@ -127,21 +127,26 @@ public static int isGroupMark(CharSequence s, char groupMark) */ public static int indexOfOpening(CharSequence str, int from, char... openings) { - for (int len = str.length(), brackets = 0; from < len; from++) + for (int len = str.length(); from < len; from++) { - char ch = str.charAt(from); + int ch = str.charAt(from); if (ch == '"') while (++from < len && str.charAt(from) != '"'); else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing opening bracket in: " + str); + for (int brackets = 1; brackets != 0; ) + { + if (++from >= len) + throw new IllegalArgumentException("Missing ("+ brackets + ") closing bracket in: " + str); + if ((ch = (str.charAt(from) | ' ')) == '{') + brackets++; + else if (ch == '}') + brackets--; + else if (ch == '"') + while (++from < len && str.charAt(from) != '"'); + } } - else if (brackets == 0 && isOneOf(ch, openings)) + else if (isOneOf(ch, openings)) return from; } return -1; @@ -159,21 +164,26 @@ else if (brackets == 0 && isOneOf(ch, openings)) */ public static int indexOfClosing(CharSequence str, int from, char[] openings, char... closing) { - for (int len = str.length(), brackets = 0, ops = 0; from < len; from++) + for (int len = str.length(), ops = 0; from < len; from++) { - char ch = str.charAt(from); + int ch = str.charAt(from); if (ch == '"') while (++from < len && str.charAt(from) != '"'); else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') { - if (brackets > 0) - brackets--; - else - throw new IllegalArgumentException("Missing opening bracket in: " + str); + for (int brackets = 1; brackets != 0; ) + { + if (++from >= len) + throw new IllegalArgumentException("Missing ("+ brackets + ") closing bracket in: " + str); + if ((ch = (str.charAt(from) | ' ')) == '{') + brackets++; + else if (ch == '}') + brackets--; + else if (ch == '"') + while (++from < len && str.charAt(from) != '"'); + } } - else if (brackets == 0) + else { if (isOneOf(ch, openings)) ops++; diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index 0f00452..dbeaf18 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -204,20 +204,29 @@ public void setJsonStyle(boolean jsonStyle) */ public static int isVarAssignment(CharSequence s) { - for (int i = 0, brackets = 0, len = s.length(), oldCh = -1, chNext; i < len; i++) + for (int i = 0, len = s.length(), oldCh = -1, chNext; i < len; i++) { - char ch = s.charAt(i); + int ch = s.charAt(i); if (ch == '"') while (++i < len && s.charAt(i) != '"'); else if (ch == '?') return -1; - else if (brackets == 0 && (ch == '=' || ch == ':') && !(oldCh == '=' || oldCh == ':' || oldCh == '!' || oldCh == '>'|| oldCh == '<') && (i >= len-1 || !((chNext = s.charAt(i+1)) == '=' || chNext == ':' || chNext == '!' || chNext == '>'|| chNext == '<'))) - return i; else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - if (brackets > 0) - brackets--; + { + for (int brackets = 1; brackets != 0; ) + { + if (++i >= len) + throw new IllegalArgumentException("Missing ("+ brackets + ") closing bracket in: " + s); + if ((ch = (s.charAt(i) | ' ')) == '{') + brackets++; + else if (ch == '}') + brackets--; + else if (ch == '"') + while (++i < len && s.charAt(i) != '"'); + } + } + else if ((ch == '=' || ch == ':') && !(oldCh == '=' || oldCh == ':' || oldCh == '!' || oldCh == '>'|| oldCh == '<') && (i >= len-1 || !((chNext = s.charAt(i+1)) == '=' || chNext == ':' || chNext == '!' || chNext == '>'|| chNext == '<'))) + return i; oldCh = ch; } diff --git a/SerialX-operators/pom.xml b/SerialX-operators/pom.xml index f27574e..cf840c6 100644 --- a/SerialX-operators/pom.xml +++ b/SerialX-operators/pom.xml @@ -8,7 +8,7 @@ org.ugp.serialx operators - 1.3.7 + 1.3.8 SerialX operators This modul contains basic operators contained in almost every programing language... diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java index 8508845..e888b44 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -414,8 +414,7 @@ else if ((ch | ' ') == '{') brackets++; else if ((ch | ' ') == '}') brackets--; - - if (type == 1 || quote % 2 == 0 && brackets == 0) + else if (type == 1 || quote % 2 == 0 && brackets == 0) { if ((type = isOneOf(ch, oprs) ? 1 : 0) != lastType) { @@ -450,29 +449,36 @@ else if ((ch | ' ') == '}') public static boolean isExpression(CharSequence str, int to, char... operators) { int hasOpr = -1; - for (int i = 0, oldCh = 0, isCof = 0, quote = 0, brackets = 0; i < to; i++) + for (int i = 0, oldCh = 0, isCof = 0; i < to; i++) { - char ch = str.charAt(i); + int ch = str.charAt(i); if (ch > 32) { - if (ch == '\"') - quote++; - else if (quote % 2 == 0) + if (ch == '"') + while (++i < to && str.charAt(i) != '"'); + else if ((ch | ' ') == '{') { - if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - brackets--; - else if (brackets == 0) + for (int brackets = 1; brackets != 0; ) { - if (isOneOf(ch, operators)) - hasOpr = isCof = 0; - else if (oldCh <= 32 && isCof == 1) - return false; - else - isCof = 1; + if (++i >= to) + throw new IllegalArgumentException("Missing ("+ brackets + ") closing bracket in: " + str); + if ((ch = (str.charAt(i) | ' ')) == '{') + brackets++; + else if (ch == '}') + brackets--; + else if (ch == '"') + while (++i < to && str.charAt(i) != '"'); } } + else + { + if (isOneOf(ch, operators)) + hasOpr = isCof = 0; + else if (oldCh <= 32 && isCof == 1) + return false; + else + isCof = 1; + } } oldCh = ch; } diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java index 768f863..0b2a761 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java @@ -66,16 +66,26 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) */ public static int indexOfTernaryElse(CharSequence str, int defaultCountOfConfitions, char... ternaryOperators) { - for (int i = 0, len = str.length(), oldCh = -1, tokenCount = 0, brackets = 0; i < len; i++) + for (int i = 0, len = str.length(), oldCh = -1, tokenCount = 0; i < len; i++) { - char ch = str.charAt(i); + int ch = str.charAt(i); if (ch == '\"') while (++i < len && str.charAt(i) != '"'); else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - brackets--; - else if (brackets == 0) + { + for (int brackets = 1; brackets != 0; ) + { + if (++i >= len) + throw new IllegalArgumentException("Missing ("+ brackets + ") closing bracket in: " + str); + if ((ch = (str.charAt(i) | ' ')) == '{') + brackets++; + else if (ch == '}') + brackets--; + else if (ch == '"') + while (++i < len && str.charAt(i) != '"'); + } + } + else { for (char token : ternaryOperators) if (ch == token && oldCh != token && (i >= len-1 || str.charAt(i+1) != token)) @@ -103,16 +113,26 @@ else if (brackets == 0) */ public static int indexOfOne(CharSequence str, int from, char oneChar) { - for (int len = str.length(), oldCh = -1, brackets = 0; from < len; from++) + for (int len = str.length(), oldCh = -1; from < len; from++) { - char ch = str.charAt(from); + int ch = str.charAt(from); if (ch == '\"') while (++from < len && str.charAt(from) != '"'); else if ((ch | ' ') == '{') - brackets++; - else if ((ch | ' ') == '}') - brackets--; - else if (brackets == 0 && ch == oneChar && oldCh != oneChar && (from >= len-1 || str.charAt(from+1) != oneChar)) + { + for (int brackets = 1; brackets != 0; ) + { + if (++from >= len) + throw new IllegalArgumentException("Missing ("+ brackets + ") closing bracket in: " + str); + if ((ch = (str.charAt(from) | ' ')) == '{') + brackets++; + else if (ch == '}') + brackets--; + else if (ch == '"') + while (++from < len && str.charAt(from) != '"'); + } + } + else if (ch == oneChar && oldCh != oneChar && (from >= len-1 || str.charAt(from+1) != oneChar)) return from; oldCh = ch; } diff --git a/pom.xml b/pom.xml index de6c8cc..1068d9c 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,7 @@ SerialX root Store Java objects into file via SerialX. SerialX is a powerful utility library to serialize objects in Java programmatically via recursive descent parser for custom domain-specific languages! https://github.com/SimplyProgrammer/Java-SerialX + 2020 @@ -42,7 +43,7 @@ 8 - 1.3.7 + 1.3.8 UTF-8 ${java.version} @@ -68,12 +69,12 @@ org.codehaus.plexus plexus-compiler-eclipse - 2.8.8 + 2.9.0 - + org.eclipse.jdt ecj - 3.33.0 + 3.25.0 From 6206993f70629e3eef433e602e28fc180a8c96c9 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Wed, 14 Aug 2024 19:59:28 +0200 Subject: [PATCH 39/48] fixing broken jdocs links, adding source generator and jdoc generator --- .../src/main/java/org/ugp/serialx/Scope.java | 4 +-- .../src/main/java/org/ugp/serialx/Utils.java | 8 ++--- .../serialx/converters/ProtocolConverter.java | 20 +++++------ .../converters/imports/ImportsProvider.java | 2 +- .../devtools/SerializationDebugger.java | 2 +- .../org/ugp/serialx/json/JsonSerializer.java | 2 +- .../org/ugp/serialx/juss/JussSerializer.java | 14 ++++---- .../juss/converters/ObjectConverter.java | 16 ++++----- .../operators/ArithmeticOperators.java | 2 +- .../ConditionalAssignmentOperators.java | 2 +- pom.xml | 34 ++++++++++++++++++- 11 files changed, 69 insertions(+), 37 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java index 00e7652..ca2f71c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java @@ -93,7 +93,7 @@ public Scope(GenericScope sourceScope) /** * @param variablesMap | Initial variables to be added in to this scope! * @param values | Initial independent values to be added in to this scope! - * @param | Parent of this scope. + * @param parent | Parent of this scope. * @since 1.3.5 */ @@ -103,7 +103,7 @@ public Scope(Map variablesMap, Collection values, GenericScope objCls, String name, Object /** * @param obj | The object the underlying method is invoked from! - * @param cls | Class to invoke method from. + * @param objCls | Class to invoke method from. * @param name | Name of public static method to be called. * @param argClasses | Classes of args. * @param args | Arguments of method. Arguments should be certain if method is overloaded! @@ -447,8 +447,8 @@ public static StringBuilder multilpy(char ch, int times) } /** - * @param ch | String to multiply! - * @param str | Count of multiplication! + * @param str | String to multiply! + * @param times | Count of multiplication! * * @return Multiplied char, for example multilpy("a", 5) will return "aaaaa"; * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java index 033879a..2c7e923 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java @@ -164,9 +164,9 @@ protected Object parse(ParserRegistry myHomeRegistry, Class objClass, String } @Override - public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) { - return toString(myHomeRegistry, arg, null, args); + return toString(myHomeRegistry, obj, null, args); } /** @@ -181,15 +181,15 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object.. * @since 1.3.5 */ @SuppressWarnings("unchecked") - public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, SerializationProtocol preferedProtocol, Object... args) + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, SerializationProtocol preferedProtocol, Object... args) { - if (arg == null) + if (obj == null) return CONTINUE; - if (useBase64IfCan && arg instanceof Serializable) + if (useBase64IfCan && obj instanceof Serializable) return CONTINUE; - if (preferedProtocol != null || (preferedProtocol = (SerializationProtocol) getProtocolFor(arg, SerializationProtocol.MODE_SERIALIZE, args)) != null) + if (preferedProtocol != null || (preferedProtocol = (SerializationProtocol) getProtocolFor(obj, SerializationProtocol.MODE_SERIALIZE, args)) != null) { Class oldObjectClass = null; try @@ -200,10 +200,10 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Serializ if (args.length < 5) args = Arrays.copyOf(args, 5); oldObjectClass = (Class) args[4]; - args[4] = arg.getClass();; + args[4] = obj.getClass();; - Object[] objArgs = preferedProtocol.serialize(arg); - StringBuilder sb = new StringBuilder(ImportsProvider.getAliasFor(args.length > 0 ? args[0] : null, arg.getClass()) + (objArgs.length <= 0 ? "" : " ")); + Object[] objArgs = preferedProtocol.serialize(obj); + StringBuilder sb = new StringBuilder(ImportsProvider.getAliasFor(args.length > 0 ? args[0] : null, obj.getClass()) + (objArgs.length <= 0 ? "" : " ")); args = args.clone(); for (int i = 0, sizeEndl = 10000; i < objArgs.length; i++) @@ -229,7 +229,7 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Serializ } catch (Exception e) { - LogProvider.instance.logErr("Exception while serializing instance of \"" + arg.getClass().getName() + "\":", e); + LogProvider.instance.logErr("Exception while serializing instance of \"" + obj.getClass().getName() + "\":", e); e.printStackTrace(); } args[4] = oldObjectClass; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java index 835bcc7..968d64a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/ImportsProvider.java @@ -196,7 +196,7 @@ public Imports(Collection c) /** * Constructs an {@link Imports} with inserted imports. * - * @param parsers | Initial content of registry. + * @param imports | Initial content of registry. * * @since 1.3.5 */ diff --git a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java index 7a7a970..1c36d7b 100644 --- a/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java +++ b/SerialX-devtools/src/main/java/org/ugp/serialx/devtools/SerializationDebugger.java @@ -169,7 +169,7 @@ public static T debug(T serializer) /** * @param serializer | Serializer to debug! - * @param debuger | Specific debugger to use! + * @param debugger | Specific debugger to use! * * @return Serializer capable of debugging its serialization and deserialization! * diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java index 2209204..c3f2d74 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java @@ -229,7 +229,7 @@ public A SerializeAsSubscope(A source, Object... args) th } /** - * @param jsonSerializer | JsonSerializer to create {@link JussSerializer} from! + * @param jussSerializer | JussSerializer to create {@link JsonSerializer} from! * * @return JussSerializer created from JsonSerializer, all values and variables will remain intact! * diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index 16d8cbe..cb77270 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -388,7 +388,7 @@ public Appendable GenerateComment(Appendable source, ParserRegistry registry, Ob /** * @param reader | Reader to read from! - * @param formatingArgs | Additional arguments to use. In case of JussSerializer, this should be array of length 4 with 0. argument will being this pointer of this scope (it can be also boolean signifying if formating is required), 1. and 2. argument are null (they are used by JUSS parsers) and argument 3. will be {@link ProtocolRegistry} used by this {@link Serializer}, and additional argument 4. being of type {@link Class} containing information about class that is curently being serialized (used primarily by {@link ObjectConverter}). + * @param args | Additional arguments to use. In case of JussSerializer, this should be array of length 4 with 0. argument will being this pointer of this scope (it can be also boolean signifying if formating is required), 1. and 2. argument are null (they are used by JUSS parsers) and argument 3. will be {@link ProtocolRegistry} used by this {@link Serializer}, and additional argument 4. being of type {@link Class} containing information about class that is curently being serialized (used primarily by {@link ObjectConverter}). * * @return This scope after loading data from reader (you most likely want to return "this")! * @@ -673,7 +673,7 @@ protected Object parseObject(ParserRegistry registry, String str, Object... pars } /** - * @param variable | Variable to clone! + * @param variableKey | Variable to clone! * * @return Clone of value stored by variable with inserted name or null if there is no such a one! *

@@ -681,13 +681,13 @@ protected Object parseObject(ParserRegistry registry, String str, Object... pars * * @since 1.3.2 */ - public T cloneOf(String variableName) + public T cloneOf(String variableKey) { - return cloneOf(variableName, null); + return cloneOf(variableKey, null); } /** - * @param variable | Variable to clone! + * @param variableKey | Variable to clone! * @param defaultValue | Default value to return. * * @return Clone of value stored by variable with inserted name or defaultValue if there is no such a one or given key contains null! @@ -696,9 +696,9 @@ public T cloneOf(String variableName) * * @since 1.3.2 */ - public T cloneOf(String variableName, T defaultValue) + public T cloneOf(String variableKey, T defaultValue) { - T obj = get(variableName, defaultValue); + T obj = get(variableKey, defaultValue); if (obj == defaultValue) return defaultValue; return Clone(obj, getParsers(), new Object[] {-99999, 0, this, getProtocols(), isGenerateComments()}, this, null, null, getProtocols()); diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java index e666a2d..52e14c9 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java @@ -122,9 +122,9 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... compile } @Override - public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Object... args) { - return toString(myHomeRegistry, arg, null, args); + return toString(myHomeRegistry, obj, null, args); } /** @@ -139,17 +139,17 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object.. * @since 1.3.5 */ @SuppressWarnings("unchecked") - public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, SerializationProtocol preferedProtocol, Object... args) + public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, SerializationProtocol preferedProtocol, Object... args) { - if (arg instanceof Scope) + if (obj instanceof Scope) { Serializer serializer; try { - if (arg instanceof Serializer) - serializer = (Serializer) arg; + if (obj instanceof Serializer) + serializer = (Serializer) obj; else if (args.length > 0 && args[0] instanceof Serializer) - (serializer = ((Serializer) args[0]).emptyClone()).addAll((GenericScope) arg); + (serializer = ((Serializer) args[0]).emptyClone()).addAll((GenericScope) obj); else serializer = getPreferredSerializer(); } @@ -182,7 +182,7 @@ else if (args.length > 0 && args[0] instanceof Serializer) } } - return super.toString(myHomeRegistry, arg, preferedProtocol, args); + return super.toString(myHomeRegistry, obj, preferedProtocol, args); } @Override diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java index e888b44..55b3039 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ArithmeticOperators.java @@ -23,7 +23,7 @@ public class ArithmeticOperators implements DataParser { /** - * @deprecated DO NOT USE! USE {@link ArithmeticOperators#evalOperator(Object, String, Object)} AND {@link ArithmeticOperators#getOperatorPriority(String)} INSTEAD! + * @deprecated DO NOT USE! USE {@link ArithmeticOperators#operator(Object, String, Object)} AND {@link ArithmeticOperators#getOperatorPriority(String)} INSTEAD! */ @Deprecated protected String[] priority1Oprs = {"*", "*-", "/", "/-", "%"}, priority2Oprs = {"**", "**-"}; diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java index 0b2a761..a86a22c 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ConditionalAssignmentOperators.java @@ -58,7 +58,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) /** * @param str | Source string to search. * @param defaultCountOfConfitions | How many condition operators (tenraryTokens[0]) are expected. Should be 1 in most cases. - * @param tenraryTokens | Characters representing parts of ternary operator. Index 0 should be '?' and index 1 should be ':'. + * @param ternaryOperators | Characters representing parts of ternary operator. Index 0 should be '?' and index 1 should be ':'. * * @return Return index of else branch in ternary operator expression or -1 if there is no else branch! * diff --git a/pom.xml b/pom.xml index 1068d9c..85b0b8a 100644 --- a/pom.xml +++ b/pom.xml @@ -48,10 +48,12 @@ UTF-8 ${java.version} ${java.version} + + serialx-${project.artifactId}-${project.version} - serialx-${project.artifactId}-${project.version} + ${project.build.finalName} @@ -78,6 +80,36 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + 3.6.3 + + + -Xdoclint:none + -Xdoclint:none + + + + + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + + jar + + + + \ No newline at end of file From c57aececd4147e58b58aea225d8cf7995cdbb74e Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Fri, 16 Aug 2024 22:28:01 +0200 Subject: [PATCH 40/48] fixing jdocs --- .../main/java/org/ugp/serialx/GenericScope.java | 2 +- .../src/main/java/org/ugp/serialx/Scope.java | 8 ++++---- .../src/main/java/org/ugp/serialx/Serializer.java | 12 ++++++------ .../src/main/java/org/ugp/serialx/Utils.java | 14 +++++++------- .../org/ugp/serialx/converters/VariableParser.java | 2 +- .../java/org/ugp/serialx/json/JsonSerializer.java | 14 +++++++------- .../java/org/ugp/serialx/juss/JussSerializer.java | 14 +++++++------- .../serialx/juss/converters/VariableConverter.java | 2 +- .../ugp/serialx/juss/protocols/AutoProtocol.java | 9 ++++----- .../converters/operators/ComparisonOperators.java | 6 +++--- pom.xml | 2 +- 11 files changed, 42 insertions(+), 43 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index a47d582..5e9cdb9 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -553,7 +553,7 @@ public GenericScope getGenericScope(K... pathToScope) /** * @param type | Class of object to create (may or may not support other implementations of {@link Type}). * - * @return Object of type constructed from this scopes independent values using protocol for given class or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}! + * @return Object of type constructed from this scopes independent values using protocol for given class or null if there was no protocol found in {@link SerializationProtocol#REGISTRY}! * * @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java index ca2f71c..af25e9a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java @@ -702,7 +702,7 @@ public Scope getScope(String... pathToScope) * If independent value is {@link GenericScope} like it supposed to, then values of scope are parsed to {@link SerializationProtocol} of objClass. * Note: Scopes are searched via regular independent value index no scope index like {@link Scope#getScope(int)}. * - * @see Serializer#PROTOCOL_REGISTRY + * @see SerializationProtocol#REGISTRY * @see GenericScope#toObject(Class) * * @throws Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! @@ -725,7 +725,7 @@ public T toObjectOf(int scopesValueIndex, Class objClass) throws Exceptio * @return Value of variable with name or null if there is no such a one! If there is no Scope stored by variableWithScope this function behaves same as {@link Scope#get(String, Object)}! * If variableWithScope contains {@link GenericScope} like it supposed to, then values of scope are parsed to {@link SerializationProtocol} of objClass. * - * @see Serializer#PROTOCOL_REGISTRY + * @see SerializationProtocol#REGISTRY * @see GenericScope#toObject(Class) * * @throws Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! @@ -745,7 +745,7 @@ public T toObjectOf(String variableWithscope, Class objClass) throws Exce * @return Value of variable with name or defaultValue if there is no such a one or given key contains null! If there is no Scope stored by variableWithScope this function behaves same as {@link Scope#get(String, Object)}! * If variableWithScope contains {@link GenericScope} like it supposed to, then values of scope are parsed to {@link SerializationProtocol} of objClass. * - * @see Serializer#PROTOCOL_REGISTRY + * @see SerializationProtocol#REGISTRY * @see GenericScope#toObject(Class) * * @throws Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! @@ -766,7 +766,7 @@ public T toObjectOf(String variableWithscope, Class objClass, T defaultVa * @return Value of variable with name or defaultValue if there is no such a one or given key contains null! If there is no Scope stored by variableWithScope this function behaves same as {@link Scope#get(String, Object)}! * If variableWithScope contains {@link GenericScope} like it supposed to, then values of scope are parsed to {@link SerializationProtocol} of objClass. * - * @see Serializer#PROTOCOL_REGISTRY + * @see SerializationProtocol#REGISTRY * @see GenericScope#toObject(Class) * * @throws Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}! diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 95fd1d3..72d167a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -651,11 +651,11 @@ public T getParsed(String variableWithStringValue, Object... args) {@link Appendable} - {@link Serializer#SerializeTo(Appendable)} + {@link Serializer#SerializeTo(Appendable, Object...)} {@link OutputStream} - {@link Serializer#SerializeTo(OutputStream)} + {@link Serializer#SerializeTo(OutputStream, Object...)} {@link URL} @@ -755,7 +755,7 @@ public static T into(Object obj, Serializer fromSerializer, String... fieldN /** * @param newInstance | New instance of specific {@link Serializer} * @param fromObj | Object to create serializer from! - * @param fieldNamesToUse | Array of obj field names to map into scopes variables using getters (read method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link GenericScope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! + * @param fieldNamesToUse | Array of obj field names to map into scopes variables using getters (read method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link Scope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! * * @return {@link Serializer} created from given fromObj by mapping obj's fields into variables of created serializer via given fields (fieldNamesToUse) and conversion rules listed below!!

* Table of specific Object --> Serializer conversions: @@ -772,7 +772,7 @@ Obtained serializer content (return) {@link CharSequence} - {@link Serializer#LoadFrom(CharSequence)} + {@link Serializer#LoadFrom(CharSequence, Object...)} {@link CharSequence} (as http address) @@ -780,7 +780,7 @@ Obtained serializer content (return) {@link File} - {@link Serializer#LoadFrom(File)} + {@link Serializer#LoadFrom(File, Object...)} {@link Reader} @@ -788,7 +788,7 @@ Obtained serializer content (return) {@link InputStream} - {@link Serializer#LoadFrom(InputStream)} + {@link Serializer#LoadFrom(InputStream, Object...)} {@link URL} diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java index 674a38d..37b2d5b 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Utils.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Utils.java @@ -51,7 +51,7 @@ public static String LoadFileToString(File f) throws IOException /** * @param f | Source file. * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
- * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! + * Note: You almost always want endlMode on 1. So thats why you should use {@link #LoadFileToString(File)} which is doing this automatically! * * @return Content of file as string. * @throws IOException @@ -66,7 +66,7 @@ public static String LoadFileToString(File f, int endlMode) throws IOException /** * @param input | Input stream to read to string! * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
- * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! + * Note: You almost always want endlMode on 1. So thats why you should use {@link #LoadFileToString(File)} which is doing this automatically! * * @return Reader converted to string form! * @@ -82,7 +82,7 @@ public static String StreamToString(InputStream input, int endlMode) throws IOEx /** * @param input | Input reader! * @param endlMode | 0 = no line brakes, 1 = always line brakes, 2 = line break only when contains with "//"!
- * Note: You almost always want endlMode on 1. So thats why you should use {@link Serializer#LoadFileToString(File)} which is doing this automatically! + * Note: You almost always want endlMode on 1. So thats why you should use {@link #LoadFileToString(File)} which is doing this automatically! * * @return Reader converted to string form! * @@ -113,7 +113,7 @@ public static String StreamToString(Reader input, int endlMode) throws IOExcepti * @param name | Name of public static method to be called. * @param args | Arguments of method. Arguments should be certain if method is overloaded! * - * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * @return The returned result of called method or {@link #VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. * * @throws InvocationTargetException if called method throws and exception while calling! * @@ -129,7 +129,7 @@ public static Object InvokeStaticFunc(Class cls, String name, Object... args) * @param name | Name of public static method to be called. * @param args | Arguments of method. Arguments should be certain if method is overloaded! * - * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * @return The returned result of called method or {@link #VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. * * @throws InvocationTargetException if called method throws and exception while calling! * @@ -146,7 +146,7 @@ public static Object InvokeFunc(Object obj, String name, Object... args) throws * @param name | Name of public static method to be called. * @param args | Arguments of method. Arguments should be certain if method is overloaded! * - * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * @return The returned result of called method or {@link #VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. * * @throws InvocationTargetException if called method throws and exception while calling! * @@ -170,7 +170,7 @@ public static Object InvokeFunc(Object obj, Class objCls, String name, Object * @param argClasses | Classes of args. * @param args | Arguments of method. Arguments should be certain if method is overloaded! * - * @return The returned result of called method or {@link Serializer#VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. + * @return The returned result of called method or {@link #VOID} if return type of method is void. If something when wrong you will be notified and null will be returned. * * @throws InvocationTargetException if called method throws and exception while calling! * diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java index 1734435..9d82ce3 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/VariableParser.java @@ -36,7 +36,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) * @param source | Source object to get value of the member from (may or may not be null). Source should not be modified! * @param member | Name/key of the member to get. * - * @return The value of member from given source. You can think about this as ekvivalent to source.member in Java. If member with provided name/key is not present in the source or its value is not possible to get, {@link VOID} has to be returned! If source can't be accessed/dereferenced, null has to be returned!
+ * @return The value of member from given source. You can think about this as ekvivalent to source.member in Java. If member with provided name/key is not present in the source or its value is not possible to get, {@link #VOID} has to be returned! If source can't be accessed/dereferenced, null has to be returned!
* Note: This method is meant to be overridden in order to add support for accessing multiple sources because by default it supports only {@link GenericScope} * * @since 1.3.8 diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java index c3f2d74..5e022f3 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/JsonSerializer.java @@ -296,7 +296,7 @@ Obtained serializer content (return) {@link CharSequence} - {@link Serializer#LoadFrom(CharSequence)} + {@link Serializer#LoadFrom(CharSequence, Object...)} {@link CharSequence} (as http address) @@ -304,7 +304,7 @@ Obtained serializer content (return) {@link File} - {@link Serializer#LoadFrom(File)} + {@link Serializer#LoadFrom(File, Object...)} {@link Reader} @@ -312,7 +312,7 @@ Obtained serializer content (return) {@link InputStream} - {@link Serializer#LoadFrom(InputStream)} + {@link Serializer#LoadFrom(InputStream, Object...)} {@link URL} @@ -346,7 +346,7 @@ public static JsonSerializer from(Object fromObj) throws Exception /** * @param fromObj | Object to create serializer from! - * @param fieldNamesToUse | Array of obj field names to map into scopes variables using getters (read method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link GenericScope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! + * @param fieldNamesToUse | Array of obj field names to map into scopes variables using getters (read method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link Scope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! * * @return {@link JsonSerializer} created from given fromObj by mapping obj's fields into variables of created serializer via given fields (fieldNamesToUse) and conversion rules listed below!!

* Table of specific Object --> JsonSerializer conversions: @@ -363,7 +363,7 @@ Obtained serializer content (return) {@link CharSequence} - {@link Serializer#LoadFrom(CharSequence)} + {@link Serializer#LoadFrom(CharSequence, Object...)} {@link CharSequence} (as http address) @@ -371,7 +371,7 @@ Obtained serializer content (return) {@link File} - {@link Serializer#LoadFrom(File)} + {@link Serializer#LoadFrom(File, Object...)} {@link Reader} @@ -379,7 +379,7 @@ Obtained serializer content (return) {@link InputStream} - {@link Serializer#LoadFrom(InputStream)} + {@link Serializer#LoadFrom(InputStream, Object...)} {@link URL} diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index cb77270..d86c0bb 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -784,7 +784,7 @@ Obtained serializer content (return) {@link CharSequence} - {@link Serializer#LoadFrom(CharSequence)} + {@link Serializer#LoadFrom(CharSequence, Object...)} {@link CharSequence} (as http address) @@ -792,7 +792,7 @@ Obtained serializer content (return) {@link File} - {@link Serializer#LoadFrom(File)} + {@link Serializer#LoadFrom(File, Object...)} {@link Reader} @@ -800,7 +800,7 @@ Obtained serializer content (return) {@link InputStream} - {@link Serializer#LoadFrom(InputStream)} + {@link Serializer#LoadFrom(InputStream, Object...)} {@link URL} @@ -834,7 +834,7 @@ public static JussSerializer from(Object fromObj) throws Exception /** * @param fromObj | Object to create serializer from! - * @param fieldNamesToUse | Array of obj field names to map into scopes variables using getters (read method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link GenericScope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! + * @param fieldNamesToUse | Array of obj field names to map into scopes variables using getters (read method)! {@link PropertyDescriptor}s of these fields will be obtained using {@link Scope#getPropertyDescriptorsOf(Class, String...)}! This is used only as a last (default) option! * * @return {@link JussSerializer} created from given fromObj by mapping obj's fields into variables of created serializer via given fields (fieldNamesToUse) and conversion rules listed below!!

* Table of specific Object --> JussSerializer conversions: @@ -851,7 +851,7 @@ Obtained serializer content (return) {@link CharSequence} - {@link Serializer#LoadFrom(CharSequence)} + {@link Serializer#LoadFrom(CharSequence, Object...)} {@link CharSequence} (as http address) @@ -859,7 +859,7 @@ Obtained serializer content (return) {@link File} - {@link Serializer#LoadFrom(File)} + {@link Serializer#LoadFrom(File, Object...)} {@link Reader} @@ -867,7 +867,7 @@ Obtained serializer content (return) {@link InputStream} - {@link Serializer#LoadFrom(InputStream)} + {@link Serializer#LoadFrom(InputStream, Object...)} {@link URL} diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java index dbeaf18..065248a 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/VariableConverter.java @@ -159,7 +159,7 @@ public CharSequence getDescription(ParserRegistry myHomeRegistry, Object objToDe * @param genericVar | If true, member is expected be generic (not only string) and further parsing is required, may or may not be used... * @param args | Some additional args to be used in case of parsing that are provided by called, may or may not be used... * - * @return By default it returns the previous value of the member. If member with provided name/key is not present in the source or its value is not possible to set, {@link VOID} should be returned! + * @return By default it returns the previous value of the member. If member with provided name/key is not present in the source or its value is not possible to set, {@link #VOID} should be returned! * * @since 1.3.8 */ diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java index 5028812..9f72076 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/AutoProtocol.java @@ -1,6 +1,5 @@ package org.ugp.serialx.juss.protocols; -import static org.ugp.serialx.Utils.Instantiate; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; @@ -12,7 +11,7 @@ import org.ugp.serialx.GenericScope; import org.ugp.serialx.Scope; -import org.ugp.serialx.Serializer; +import org.ugp.serialx.Utils; import org.ugp.serialx.protocols.SerializationProtocol; /** @@ -126,7 +125,7 @@ public AutoProtocol(Class applicableFor, boolean useScope, List applicableFor, boolean useScope, List objectClass) throws Exception { - return Instantiate(objectClass); + return Utils.Instantiate(objectClass); } @Override @@ -168,7 +167,7 @@ public T unserialize(Class objectClass, Object... args) throws Exce return Scope.into(obj, (Scope) args[0], fieldDescriptors); } - for (int i = 0, size = fieldDescriptors.size(); i < size && i < args.length; i++) + for (int i = 0, size = Math.min(fieldDescriptors.size(), args.length); i < size; i++) { Method setter = fieldDescriptors.get(i).getWriteMethod(); Type expectedType = setter.getGenericParameterTypes()[0]; diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java index 39a34d7..796bd08 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java @@ -72,7 +72,7 @@ public Object parse(ParserRegistry myHomeRegistry, String str, Object... args) * @param obj2 | Object 2! * @param compareInstances | If true, this method will compare objects using == operator! * - * @return True supposed to be returned if obj1 equals to obj2 otherwise false similar to {@link Objects#deepEquals(Object)} but this one can handle OOP crosstype number compression such as {@link Integer} and {@link Double}! + * @return True supposed to be returned if obj1 equals to obj2 otherwise false similar to {@link Objects#deepEquals(Object, Object)} but this one can handle OOP crosstype number compression such as {@link Integer} and {@link Double}! * * @since 1.3.2 */ @@ -147,7 +147,7 @@ public static boolean numberComparator(double d1, double d2, boolean isGreater, * @param obj1 | Object 1! * @param obj2 | Object 2! * - * @return True if obj1 equals to obj2 otherwise false similar to {@link Objects#deepEquals(Object)} but this one can handle OOP crosstype number compression such as {@link Integer} and {@link Double}! + * @return True if obj1 equals to obj2 otherwise false similar to {@link Objects#deepEquals(Object, Object)} but this one can handle OOP crosstype number compression such as {@link Integer} and {@link Double}! * * @since 1.3.0 */ @@ -161,7 +161,7 @@ public static boolean equals(Object obj1, Object obj2) * @param obj2 | Object 2! * @param compareInstances | If true, this method will compare objects using == operator! * - * @return True if obj1 equals to obj2 otherwise false similar to {@link Objects#deepEquals(Object)} but this one can handle OOP crosstype number compression such as {@link Integer} and {@link Double}! + * @return True if obj1 equals to obj2 otherwise false similar to {@link Objects#deepEquals(Object, Object)} but this one can handle OOP crosstype number compression such as {@link Integer} and {@link Double}! * * @since 1.3.2 */ diff --git a/pom.xml b/pom.xml index 85b0b8a..2d3b4dd 100644 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.6.3 + 3.8.0 -Xdoclint:none From 02ecf7106642602a4c16f90647126886012f2775 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Thu, 22 Aug 2024 21:47:55 +0200 Subject: [PATCH 41/48] docs fix --- .../src/main/java/org/ugp/serialx/Scope.java | 2 +- .../main/java/org/ugp/serialx/Serializer.java | 25 ++++++++++++++----- .../org/ugp/serialx/juss/JussSerializer.java | 4 +-- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java index af25e9a..ff1108c 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Scope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Scope.java @@ -116,7 +116,7 @@ public Scope clone() } /** - * @param objClass | Class of object to create using protocols. + * @param objClass | Class of object to create using protocols (may or may not support other implementations of {@link Type}). * @param protocolsToUse | Registry of protocols to use. * * @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in protocolsToUse! diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 72d167a..80d0c19 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -19,6 +19,7 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.io.StringReader; +import java.io.Writer; import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.URL; @@ -160,7 +161,7 @@ public T toObjectOf(String variableWithscope, Class objClass, T defaultVa } /** - * @param type | Class of object to create. + * @param objClass | Class of object to create (may or may not support other implementations of {@link Type}). * * @return Object of type constructed from this scopes independent values using protocol for given class or null if there was no protocol found in this {@link Serializer#getProtocols()}! * @@ -283,11 +284,25 @@ public void SerializeTo(File f) throws IOException public void SerializeTo(boolean append, File f, Object... args) throws IOException { //double t0 = System.nanoTime(); - BufferedWriter writer = new BufferedWriter(new FileWriter(f, append)); + Writer writer = new BufferedWriter(new FileWriter(f, append)); writer.write(Stringify(args)); writer.close(); + +// String serialized = Stringify(args); +// +// RandomAccessFile fileOutputStream = new RandomAccessFile(f, "rw"); +// FileChannel channel = fileOutputStream.getChannel(); +// +//// channel.write(ByteBuffer.wrap(serialized.getBytes())); +// +// ByteBuffer buff = channel.map(FileChannel.MapMode.READ_WRITE, append ? channel.size() : 0, serialized.length()); +// buff.put(serialized.getBytes()); +// +// channel.force(true); +// channel.close(); +// fileOutputStream.close(); } /** @@ -305,7 +320,7 @@ public String Stringify(Object... args) throws IOException } /** - * @param source | Source {@link OutputStream} to serialize variables and objects into! + * @param outputStream | Source {@link OutputStream} to serialize variables and objects into! * @param args | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (they should not be serialized)! * * @return Source {@link OutputStream} with variables and objects serialized in specific format (may or may not be flushed). @@ -382,10 +397,8 @@ public S LoadFrom(InputStream stream, Object... parserArgs) /** * @param reader | Any {@link Reader} with serialized objects in specific format to load. - * @param parserArgs | Additional arguments to use, exact usage and behavior of them is based on specific implementation of this function (probably used for formating of incoming information)! * - * @return Unserialized objects and variables in {@link Scope} or empty {@link Scope} if string is empty. - * You can use negative indexes to get objects from back of this array since 1.1.0 (-1 = last element)! + * @return This scope after loading data from reader (you most likely want to return "this")! * * @since 1.2.5 */ diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index d86c0bb..eb0a905 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -500,11 +500,11 @@ else if (ch == '}' || ch == ']') } /** - * @return Formated content of reader ready to parse! + * @return Formated content of reader ready to parse! Should not modify this object in any way! * * @since 1.3.2 */ - protected StringBuilder readAndFormat(Reader reader, boolean format) + public StringBuilder readAndFormat(Reader reader, boolean format) { int quote = 0, multLineCom = -1; //int brackets = 0, lastIndex = 0, delChars = 0; From 8e430645e06c94f8555092c19ecac8917a285854 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sun, 25 Aug 2024 22:08:37 +0200 Subject: [PATCH 42/48] ... --- .../src/main/java/org/ugp/serialx/juss/JussSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java index eb0a905..fba97b1 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/JussSerializer.java @@ -408,7 +408,7 @@ public S LoadFrom(Reader reader, Object... args) if (args[3] == null) args[3] = getProtocols(); - StringBuilder str = readAndFormat(reader, formatRequired); + StringBuilder str = readAndFormat(reader, formatRequired); // TODO could be improved... List objs = splitAndParse(str, args); addAll(objs); From 50a08b3f67dae98b7d0ca6868679bc66ea07e6e2 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sun, 8 Sep 2024 23:05:14 +0200 Subject: [PATCH 43/48] prepairing for release and fixing tiny bug --- README.md | 2 +- SerialX-core/pom.xml | 2 +- SerialX-devtools/pom.xml | 4 ++-- SerialX-json/pom.xml | 4 ++-- .../serialx/json/converters/JsonObjectConverter.java | 11 ++++++++--- SerialX-juss/pom.xml | 6 +++--- SerialX-operators/pom.xml | 4 ++-- pom.xml | 2 +- 8 files changed, 20 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 8f0b6c0..918a497 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # Java-SerialX dev -This branch is used for testing and stuff! +This the main development branch! diff --git a/SerialX-core/pom.xml b/SerialX-core/pom.xml index 1d7592f..4be9914 100644 --- a/SerialX-core/pom.xml +++ b/SerialX-core/pom.xml @@ -7,7 +7,7 @@ org.ugp.serialx - core + serialx-core 1.3.8 SerialX core diff --git a/SerialX-devtools/pom.xml b/SerialX-devtools/pom.xml index 62408a9..8ea0304 100644 --- a/SerialX-devtools/pom.xml +++ b/SerialX-devtools/pom.xml @@ -7,7 +7,7 @@ org.ugp.serialx - devtools + serialx-devtools 1.3.8 SerialX devtools @@ -16,7 +16,7 @@ org.ugp.serialx - core + serialx-core ${revision} diff --git a/SerialX-json/pom.xml b/SerialX-json/pom.xml index 099d015..c400bb5 100644 --- a/SerialX-json/pom.xml +++ b/SerialX-json/pom.xml @@ -7,7 +7,7 @@ org.ugp.serialx - json + serialx-json 1.3.8 SerialX json @@ -16,7 +16,7 @@ org.ugp.serialx - juss + serialx-juss ${revision} diff --git a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java index 09091ec..585b4e6 100644 --- a/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java +++ b/SerialX-json/src/main/java/org/ugp/serialx/json/converters/JsonObjectConverter.java @@ -14,7 +14,7 @@ * * @author PETO * - * @since 1.3.5 + * @since 1.3.5 (separated from JsonSerializer since 1.3.8) */ public class JsonObjectConverter extends ObjectConverter { @@ -22,16 +22,21 @@ public class JsonObjectConverter extends ObjectConverter @Override public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object... args) { + if (arg == null) + return CONTINUE; + if (arg.getClass().isArray()) return super.toString(myHomeRegistry, new Scope(Utils.fromAmbiguousArray(arg)), args); if (arg instanceof Map) { Map map = (Map) arg; - if (map.isEmpty() || map.keySet().iterator().next() instanceof CharSequence) + if (map.isEmpty()) + return "{}"; + if (map.keySet().iterator().next() instanceof CharSequence) return super.toString(myHomeRegistry, new Scope((Map) map), args); } - + SerializationProtocol prot = (SerializationProtocol) getProtocolFor(arg, SerializationProtocol.MODE_SERIALIZE, args); if (prot != null && !(arg instanceof Scope)) try diff --git a/SerialX-juss/pom.xml b/SerialX-juss/pom.xml index a37638a..2a1d974 100644 --- a/SerialX-juss/pom.xml +++ b/SerialX-juss/pom.xml @@ -7,16 +7,16 @@ org.ugp.serialx - juss + serialx-juss 1.3.8 - SerialX-juss + SerialX juss SerialX support for Java Universal Serial Script data format, custom default format of SerialX! org.ugp.serialx - core + serialx-core ${revision} diff --git a/SerialX-operators/pom.xml b/SerialX-operators/pom.xml index cf840c6..073c8a0 100644 --- a/SerialX-operators/pom.xml +++ b/SerialX-operators/pom.xml @@ -7,7 +7,7 @@ org.ugp.serialx - operators + serialx-operators 1.3.8 SerialX operators @@ -16,7 +16,7 @@ org.ugp.serialx - core + serialx-core ${revision} diff --git a/pom.xml b/pom.xml index 2d3b4dd..b0fb715 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ SerialX root - Store Java objects into file via SerialX. SerialX is a powerful utility library to serialize objects in Java programmatically via recursive descent parser for custom domain-specific languages! + Store Java objects into JSON or any format you want! SerialX is a powerful lightweight utility library to serialize Java objects programmatically via tweakable recursive descent parser for custom domain-specific languages! https://github.com/SimplyProgrammer/Java-SerialX 2020 From e8104b7f334556132ca2898a80b0d2685e89731b Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sun, 8 Sep 2024 23:10:29 +0200 Subject: [PATCH 44/48] ... --- LICENSE | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 7212173..0000000 --- a/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Based on MIT License - -Copyright (c) USP 2019-2020 | Peto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated files, to deal -in the Software without restriction, including without limitation the rights -to use, copy or modify copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Permission to publish, distribute, sublicense or sell for example as content of some game or application is allowed -subject to the following conditions: Indication of the original source (https://github.com/PetoPetko/Java-SerialX/). - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software! - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. From 6023552e45dda8e230d9ae76bf9b08ab7042271e Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sat, 14 Sep 2024 00:25:02 +0200 Subject: [PATCH 45/48] Protocol "mode" is now bitwise based on bit-packing --- .../main/java/org/ugp/serialx/Registry.java | 8 +- .../serialx/converters/ProtocolConverter.java | 34 ++++++-- .../protocols/SerializationProtocol.java | 82 +++++++++---------- .../juss/converters/ObjectConverter.java | 4 +- .../protocols/SelfSerializableProtocol.java | 4 +- .../UniversalObjectInstantiationProtocol.java | 2 +- 6 files changed, 75 insertions(+), 59 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Registry.java b/SerialX-core/src/main/java/org/ugp/serialx/Registry.java index 0681b36..2531833 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Registry.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Registry.java @@ -334,10 +334,10 @@ public C get(Class cls, boolean includeChildrens) for (int i = 0, size = size(); i < size; i++) { C elm = (C) get(i); - Class objCls = elm.getClass(); - if (objCls == cls) + Class objCls; + if ((objCls = elm.getClass()) == cls) return elm; - else if (includeChildrens && cls.isAssignableFrom(objCls)) + if (includeChildrens && cls.isAssignableFrom(objCls)) obj = elm; } return obj; @@ -371,7 +371,7 @@ public int indexOf(Class cls, boolean includeChildrens) Class objCls = get(i).getClass(); if (objCls == cls) return i; - else if (includeChildrens && cls.isAssignableFrom(objCls)) + if (includeChildrens && cls.isAssignableFrom(objCls)) index = i; } return index; diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java index 2c7e923..b302814 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/ProtocolConverter.java @@ -73,6 +73,8 @@ public class ProtocolConverter implements DataConverter protected Set> invokableClasses = new HashSet<>(Arrays.asList(Math.class, Scope.class, Double.class, Float.class, String.class)); + protected long protocolType = 0; + @Override public Object parse(ParserRegistry myHomeRegistry, String str, Object... compilerArgs) { @@ -153,7 +155,7 @@ protected Object parse(ParserRegistry myHomeRegistry, Class objClass, String if (objArgs.length == 1 && objArgs[0] instanceof Scope && Scope.class.isAssignableFrom(objClass)) return objArgs[0]; compilerArgs[4] = oldObjectClass; - return SerializationProtocol.unserializeObj(compilerArgs.length > 3 && compilerArgs[3] instanceof ProtocolRegistry ? (ProtocolRegistry) compilerArgs[3] : SerializationProtocol.REGISTRY, objClass, objArgs); + return SerializationProtocol.unserializeObj(compilerArgs.length > 3 && compilerArgs[3] instanceof ProtocolRegistry ? (ProtocolRegistry) compilerArgs[3] : SerializationProtocol.REGISTRY, getProtocolType(), objClass, objArgs); } catch (Exception e) { @@ -189,7 +191,7 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Serializ if (useBase64IfCan && obj instanceof Serializable) return CONTINUE; - if (preferedProtocol != null || (preferedProtocol = (SerializationProtocol) getProtocolFor(obj, SerializationProtocol.MODE_SERIALIZE, args)) != null) + if (preferedProtocol != null || (preferedProtocol = (SerializationProtocol) getProtocolFor(obj, SerializationProtocol.MODE_SERIALIZE | getProtocolType(), args)) != null) { Class oldObjectClass = null; try @@ -240,11 +242,9 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object obj, Serializ @Override public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Object... argsUsedConvert) { - if (obj instanceof Scope && ((Scope) obj).isEmpty()) - return "Empty scope!"; - else if (obj instanceof CharSequence && indexOfNotInObj((CharSequence) obj, '\n', '\r') != -1) + if (obj instanceof CharSequence && indexOfNotInObj((CharSequence) obj, '\n', '\r') != -1) return "Multiline char sequence!"; - return new StringBuilder("Object of ").append(obj.getClass().getName()).append(": \"").append(obj.toString()).append("\" serialized using ").append(getProtocolFor(obj, SerializationProtocol.MODE_ALL, argsUsedConvert).toString()).append("!"); + return new StringBuilder("Object of ").append(obj.getClass().getName()).append(": \"").append(obj.toString()).append("\" serialized using ").append(getProtocolFor(obj, SerializationProtocol.MODE_SERIALIZE_DESERIALIZE | getProtocolType(), argsUsedConvert)).append("!"); } /** @@ -276,6 +276,26 @@ public void setUseBase64IfCan(boolean useBase64IfCan) { this.useBase64IfCan = useBase64IfCan; } + + /** + * @return The additional protocol type that will chained with {@link SerializationProtocol#MODE_SERIALIZE} and {@link SerializationProtocol#MODE_DESERIALIZE} (none (0) by default). + * + * @since 1.3.8 + */ + public long getProtocolType() + { + return protocolType; + } + + /** + * @param protocolType | Value of additional protocol type that will chained with {@link SerializationProtocol#MODE_SERIALIZE} and {@link SerializationProtocol#MODE_DESERIALIZE} (none (0) by default). + * + * @since 1.3.8 + */ + public void setProtocolType(long protocolType) + { + this.protocolType = protocolType; + } /** * @return Classes that are eligible for public static member invocation (:: operator)!
@@ -298,7 +318,7 @@ public Set> getInvokableClasses() * * @since 1.3.5 */ - public static SerializationProtocol getProtocolFor(Object obj, byte mode, Object[] args) + public static SerializationProtocol getProtocolFor(Object obj, long mode, Object[] args) { if (args.length > 3) { diff --git a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java index 20e98a3..7316d46 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/protocols/SerializationProtocol.java @@ -26,7 +26,7 @@ public abstract class SerializationProtocol /** * This is serialization protocol registry. This is place where your {@link SerializationProtocol} implementations should be registered in order to work properly! Do not add there two protocols applicable for exactly same classes! * Also I recommend to register protocols in generic order of object that are they applicable for! In other words If some object Foo has child classes, protocol of these classes should be registered after each other. - * Defaultly there are registered protocols from ugp.org.SerialX.protocols. + * Defaultly there are registered protocols from org.ugp.serialx.protocols. * * @since 1.3.0 */ @@ -37,30 +37,30 @@ public abstract class SerializationProtocol * * @since 1.3.5 */ - public static final byte MODE_SERIALIZE = 0; + public static final long MODE_SERIALIZE = 0b01; /** * This mode is for protocols that are used for deserialization only! * * @since 1.3.5 */ - public static final byte MODE_DESERIALIZE = 1; + public static final long MODE_DESERIALIZE = 0b10; /** - * This mode is for protocols that chat can both serialize and deserialize! + * This mode is for protocols that chat can both serialize and deserialize (MODE_SERIALIZE | MODE_DESERIALIZE)! * - * @since 1.3.5 + * @since 1.3.8 (originally known as MODE_ALL) */ - public static final byte MODE_ALL = 2; + public static final long MODE_SERIALIZE_DESERIALIZE = MODE_SERIALIZE | MODE_DESERIALIZE; protected boolean isActive = true; @Override - public boolean equals(Object obj) + public boolean equals(Object obj) { if (obj instanceof Class) return applicableFor().equals(obj); - else if (obj instanceof SerializationProtocol) + if (obj instanceof SerializationProtocol) return applicableFor().equals(((SerializationProtocol) obj).applicableFor()); return super.equals(obj); } @@ -128,17 +128,16 @@ public T unserialize(Class objectClass, Scope scope) throws Excepti public abstract Class applicableFor(); /** - * @return Mode of this protocol. Default is {@link SerializationProtocol#MODE_ALL}! + * @return Mode of this protocol, describing its type or operation mode. Can be one or more chained with binary or. Default is {@link SerializationProtocol#MODE_SERIALIZE_DESERIALIZE}! * - * @see SerializationProtocol#MODE_ALL * @see SerializationProtocol#MODE_DESERIALIZE * @see SerializationProtocol#MODE_SERIALIZE * * @since 1.3.5 */ - public byte getMode() + public long getMode() { - return MODE_ALL; + return MODE_SERIALIZE_DESERIALIZE; } /** @@ -174,11 +173,12 @@ public void setActive(boolean isActive) */ public static Object[] serializeObj(O object) throws Exception { - return serializeObj(REGISTRY, object); + return serializeObj(REGISTRY, 0, object); } /** * @param registry | Registry to use! + * @param aditionalType | Additional protocol mode that will be chained together with {@link SerializationProtocol#MODE_DESERIALIZE}. * @param object | The object. * * @return Array of objects to serialize created from given object. Object will be serialized via protocol picked from registry. @@ -186,9 +186,9 @@ public static Object[] serializeObj(O object) throws Exception * * @since 1.3.0 */ - public static Object[] serializeObj(ProtocolRegistry registry, O object) throws Exception + public static Object[] serializeObj(ProtocolRegistry registry, long aditionalType, O object) throws Exception { - SerializationProtocol prot = registry.GetProtocolFor(object, MODE_SERIALIZE); + SerializationProtocol prot = registry.GetProtocolFor(object, MODE_SERIALIZE | aditionalType); if (prot == null) { LogProvider.instance.logErr("Unable to serialize \"" + object + "\" because there is no registered and active protocol for serializing " + object.getClass() + "!", null); @@ -210,11 +210,12 @@ public static Object[] serializeObj(ProtocolRegistry registry, O object) thr */ public static O unserializeObj(Class objectClass, Object... args) throws Exception { - return unserializeObj(REGISTRY, objectClass, args); + return unserializeObj(REGISTRY, 0, objectClass, args); } /** * @param registry | Registry to use! + * @param aditionalType | Additional protocol mode that will be chained together with {@link SerializationProtocol#MODE_DESERIALIZE}. * @param objectClass | The class of object that should be created. This can be useful when object {@link O} has children classes with same constructors. You can use reflection to make protocol working also for these child classes! This class is also used to pick suitable protocol! * @param args | Args to create obj {@link T} from. * @@ -226,9 +227,9 @@ public static O unserializeObj(Class objectClass, Object... arg * @since 1.3.0 */ @SuppressWarnings("unchecked") - public static O unserializeObj(ProtocolRegistry registry, Class objectClass, Object... args) throws Exception + public static O unserializeObj(ProtocolRegistry registry, long aditionalType, Class objectClass, Object... args) throws Exception { - SerializationProtocol prot = (SerializationProtocol) registry.GetProtocolFor(objectClass, MODE_DESERIALIZE); + SerializationProtocol prot = (SerializationProtocol) registry.GetProtocolFor(objectClass, MODE_DESERIALIZE | aditionalType); if (prot == null) { LogProvider.instance.logErr("Unable to unserialize " + Arrays.toString(args) + " because there is no registered and active protocol for unserializing \"" + objectClass + "\"!", null); @@ -302,68 +303,65 @@ public void add(int index, SerializationProtocol element) /** * @param protocolsClass | Protocols class. * - * @return Protocol by its class. + * @return Protocol by its class. Pretty much equivalent with {@link Registry#get(Class)}. * * @since 1.0.0 */ public SerializationProtocol getProtocolByClass(Class> protocolsClass) { - for (SerializationProtocol p : this) - if (p.getClass().equals(protocolsClass)) - return p; - return null; + return get(protocolsClass); } /** - * @return Sublist of protocols that are active and can be used. + * @return Sublist of any protocols that are active and can be used. * * @since 1.0.0 */ public List> GetActiveProtocols() { - return GetActiveProtocols(MODE_ALL); + return GetActiveProtocols(-1); } /** - * @return Sublist of protocols that are not active and can't be used. + * @return Sublist of any protocols that are not active and can't be used. * * @since 1.0.0 */ public List> GetDeactivatedProtocols() { - return GetDeactivatedProtocols(MODE_ALL); + return GetDeactivatedProtocols(-1); } /** - * @param mode | Mode of protocol to find. + * @param mode | Mode of protocols to find, or -1 if mode does not matter. * * @return Sublist of protocols that are active and can be used according to mode. * * @since 1.3.5 */ - public List> GetActiveProtocols(byte mode) + public List> GetActiveProtocols(long mode) { List> resault = new ArrayList<>(); for (SerializationProtocol p : this) - if (p.isActive() && (p.getMode() == 2 || p.getMode() == mode)) + if (p.isActive() && (p.getMode() & mode) != 0) resault.add(p); return resault; } /** - * @param mode | Mode of protocol to find. + * @param mode | Mode of protocols to find, or -1 if mode does not matter. * * @return Sublist of protocols that are not active and can't be used according to mode. * * @since 1.3.5 */ - public List> GetDeactivatedProtocols(byte mode) + public List> GetDeactivatedProtocols(long mode) { List> resault = new ArrayList<>(); for (SerializationProtocol p : this) - if (!p.isActive() && (p.getMode() == 2 || p.getMode() == mode)) + if (!p.isActive() && (p.getMode() & mode) != 0) resault.add(p); return resault; } @@ -378,7 +376,7 @@ public List> GetDeactivatedProtocols(byte mode) */ public SerializationProtocol GetProtocolFor(O obj) { - return GetProtocolFor(obj, MODE_ALL); + return GetProtocolFor(obj, MODE_SERIALIZE_DESERIALIZE); } /** @@ -391,20 +389,20 @@ public SerializationProtocol GetProtocolFor(O obj) */ public SerializationProtocol GetProtocolFor(Class applicableFor) { - return GetProtocolFor(applicableFor, MODE_ALL); + return GetProtocolFor(applicableFor, MODE_SERIALIZE_DESERIALIZE); } /** * @param * @param obj | Object that is required protocol applicable for. - * @param mode | Mode of protocol to find. + * @param mode | Mode of protocols to find, or -1 if mode does not matter. * * @return Protocol applicable for required objects class according to mode or null if there is no such an active protocol! * * @since 1.3.5 */ @SuppressWarnings("unchecked") - public SerializationProtocol GetProtocolFor(O obj, byte mode) + public SerializationProtocol GetProtocolFor(O obj, long mode) { return (SerializationProtocol) GetProtocolFor(obj.getClass(), mode); } @@ -412,25 +410,25 @@ public SerializationProtocol GetProtocolFor(O obj, byte mode) /** * @param * @param applicableFor | Class of object that is protocol applicable for. - * @param mode | Mode of protocol to find. + * @param mode | Mode of protocols to find, or -1 if mode does not matter. * * @return Protocol applicable for required class according to mode or null if there is no such an active protocol! * * @since 1.3.5 */ @SuppressWarnings("unchecked") - public SerializationProtocol GetProtocolFor(Class applicableFor, byte mode) + public SerializationProtocol GetProtocolFor(Class applicableFor, long mode) { SerializationProtocol protocol = null; - for (int i = 0, len = size(), myMode = 0; i < len; i++) + for (int i = 0, len = size(); i < len; i++) { SerializationProtocol p = get(i); - if (p.isActive() && ((myMode = p.getMode()) == 2 || myMode == mode)) + if (p.isActive() && (p.getMode() & mode) != 0) { Class applicable = p.applicableFor(); if (applicable == applicableFor) return (SerializationProtocol) p; - else if (applicable.isAssignableFrom(applicableFor)) + if (applicable.isAssignableFrom(applicableFor)) protocol = (SerializationProtocol) p; } } diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java index 52e14c9..43d35f7 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/converters/ObjectConverter.java @@ -190,9 +190,7 @@ public CharSequence getDescription(ParserRegistry myHomeRegistry, Object obj, Ob { if (obj instanceof Scope && ((Scope) obj).isEmpty()) return "Empty scope!"; - else if (obj instanceof CharSequence && indexOfNotInObj((CharSequence) obj, '\n', '\r') != -1) - return "Multiline char sequence!"; - return new StringBuilder("Object of ").append(obj.getClass().getName()).append(": \"").append(obj.toString()).append("\" serialized using ").append(getProtocolFor(obj, SerializationProtocol.MODE_ALL, argsUsedConvert).toString()).append("!"); + return super.getDescription(myHomeRegistry, obj, argsUsedConvert); } /** diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java index 3afe55f..9247b8a 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/SelfSerializableProtocol.java @@ -29,9 +29,9 @@ public Object[] serialize(T object) } @Override - public byte getMode() + public long getMode() { - return MODE_ALL; + return MODE_SERIALIZE_DESERIALIZE; } } \ No newline at end of file diff --git a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java index cf60821..d8df934 100644 --- a/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java +++ b/SerialX-juss/src/main/java/org/ugp/serialx/juss/protocols/UniversalObjectInstantiationProtocol.java @@ -92,7 +92,7 @@ public Class applicableFor() } @Override - public byte getMode() + public long getMode() { return MODE_DESERIALIZE; } From 26fe8ec098e48648bdc3d64937e914047af29071 Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sat, 21 Sep 2024 00:44:53 +0200 Subject: [PATCH 46/48] final formating an committing --- SerialX-core/pom.xml | 30 +-- .../java/org/ugp/serialx/GenericScope.java | 6 +- .../serialx/converters/StringConverter.java | 8 +- .../serialx/converters/imports/Import.java | 4 +- SerialX-devtools/pom.xml | 46 ++-- SerialX-json/pom.xml | 46 ++-- SerialX-juss/pom.xml | 46 ++-- SerialX-operators/pom.xml | 46 ++-- .../operators/ComparisonOperators.java | 8 +- pom.xml | 221 +++++++++--------- 10 files changed, 240 insertions(+), 221 deletions(-) diff --git a/SerialX-core/pom.xml b/SerialX-core/pom.xml index 4be9914..db84da8 100644 --- a/SerialX-core/pom.xml +++ b/SerialX-core/pom.xml @@ -1,15 +1,17 @@ - - 4.0.0 - - org.ugp - serialx - ${revision} - - - org.ugp.serialx - serialx-core - 1.3.8 - - SerialX core - Core of SerialX. Contains core features and utilities shared across the library. + + 4.0.0 + + org.ugp + serialx + ${revision} + + + org.ugp.serialx + serialx-core + 1.3.8 + + SerialX core + Core of SerialX. Contains core features and utilities shared across the library. \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java index 5e9cdb9..1e4ef01 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java @@ -104,11 +104,11 @@ public boolean equals(Object obj) { if (obj instanceof GenericScope) return values().equals(((GenericScope) obj).values()) && variables().equals(((GenericScope) obj).variables()); - else if (obj instanceof Collection) + if (obj instanceof Collection) return variablesCount() <= 0 && values().equals(obj); - else if (obj instanceof Map) + if (obj instanceof Map) return valuesCount() <= 0 && variables().equals(obj); - else if (obj != null && obj.getClass().isArray()) + if (obj != null && obj.getClass().isArray()) return variablesCount() <= 0 && Objects.deepEquals(toArray(), Utils.fromAmbiguousArray(obj)); return super.equals(obj); } diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java index 2e61b8b..98dd99a 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/StringConverter.java @@ -79,12 +79,12 @@ public CharSequence toString(ParserRegistry myHomeRegistry, Object arg, Object.. str = "{"+str+"}"; return str; } - else if (serializeStringNormally) + + if (serializeStringNormally) { if (contains(str, '\"', '\n', '\r')) return CONTINUE; - else - return "\""+str+"\""; + return "\""+str+"\""; } } return CONTINUE; @@ -158,4 +158,4 @@ public static String DirectCode(Object obj) { return "${" + obj + "}"; } -} +} \ No newline at end of file diff --git a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java index e2a9662..b3a3e97 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/converters/imports/Import.java @@ -92,9 +92,9 @@ public boolean equals(Object obj) { if (obj instanceof String) return getClsAlias().equals(obj); - else if (obj instanceof Class) + if (obj instanceof Class) return getCls().equals(obj); - else if (obj instanceof Import) + if (obj instanceof Import) return getClsAlias().equals(((Import) obj).getClsAlias()) && getCls().equals(((Import) obj).getCls()); return super.equals(obj); } diff --git a/SerialX-devtools/pom.xml b/SerialX-devtools/pom.xml index 8ea0304..3b77dd3 100644 --- a/SerialX-devtools/pom.xml +++ b/SerialX-devtools/pom.xml @@ -1,23 +1,25 @@ - - 4.0.0 - - org.ugp - serialx - ${revision} - - - org.ugp.serialx - serialx-devtools - 1.3.8 - - SerialX devtools - Tools for debugging, mainly for Parser/Converter API. It is intended for DSL developers and people who want to add their own data formats. - - - - org.ugp.serialx - serialx-core - ${revision} - - + + 4.0.0 + + org.ugp + serialx + ${revision} + + + org.ugp.serialx + serialx-devtools + 1.3.8 + + SerialX devtools + Tools for debugging, mainly for Parser/Converter API. It is intended for DSL developers and people who want to add their own data formats. + + + + org.ugp.serialx + serialx-core + ${revision} + + \ No newline at end of file diff --git a/SerialX-json/pom.xml b/SerialX-json/pom.xml index c400bb5..047c32d 100644 --- a/SerialX-json/pom.xml +++ b/SerialX-json/pom.xml @@ -1,23 +1,25 @@ - - 4.0.0 - - org.ugp - serialx - ${revision} - - - org.ugp.serialx - serialx-json - 1.3.8 - - SerialX json - SerialX Json support - - - - org.ugp.serialx - serialx-juss - ${revision} - - + + 4.0.0 + + org.ugp + serialx + ${revision} + + + org.ugp.serialx + serialx-json + 1.3.8 + + SerialX json + SerialX Json support + + + + org.ugp.serialx + serialx-juss + ${revision} + + \ No newline at end of file diff --git a/SerialX-juss/pom.xml b/SerialX-juss/pom.xml index 2a1d974..9714d8d 100644 --- a/SerialX-juss/pom.xml +++ b/SerialX-juss/pom.xml @@ -1,23 +1,25 @@ - - 4.0.0 - - org.ugp - serialx - ${revision} - - - org.ugp.serialx - serialx-juss - 1.3.8 - - SerialX juss - SerialX support for Java Universal Serial Script data format, custom default format of SerialX! - - - - org.ugp.serialx - serialx-core - ${revision} - - + + 4.0.0 + + org.ugp + serialx + ${revision} + + + org.ugp.serialx + serialx-juss + 1.3.8 + + SerialX juss + SerialX support for Java Universal Serial Script data format, custom default format of SerialX! + + + + org.ugp.serialx + serialx-core + ${revision} + + \ No newline at end of file diff --git a/SerialX-operators/pom.xml b/SerialX-operators/pom.xml index 073c8a0..067d22a 100644 --- a/SerialX-operators/pom.xml +++ b/SerialX-operators/pom.xml @@ -1,23 +1,25 @@ - - 4.0.0 - - org.ugp - serialx - ${revision} - - - org.ugp.serialx - serialx-operators - 1.3.8 - - SerialX operators - This modul contains basic operators contained in almost every programing language... - - - - org.ugp.serialx - serialx-core - ${revision} - - + + 4.0.0 + + org.ugp + serialx + ${revision} + + + org.ugp.serialx + serialx-operators + 1.3.8 + + SerialX operators + This modul contains basic operators contained in almost every programing language... + + + + org.ugp.serialx + serialx-core + ${revision} + + \ No newline at end of file diff --git a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java index 796bd08..40d8e0b 100644 --- a/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java +++ b/SerialX-operators/src/main/java/org/ugp/serialx/converters/operators/ComparisonOperators.java @@ -117,13 +117,13 @@ public static Object toCompareFriendly(Object obj) { if (obj instanceof Map) return ((Map) obj).size(); - else if (obj instanceof Collection) + if (obj instanceof Collection) return ((Collection) obj).size(); - else if (obj instanceof Scope) + if (obj instanceof Scope) return ((Scope) obj).valuesCount() + ((Scope) obj).variablesCount(); - else if (obj instanceof CharSequence) + if (obj instanceof CharSequence) return ((CharSequence) obj).length(); - else if ((obj = ArithmeticOperators.toNum(obj)).getClass().isArray()) + if ((obj = ArithmeticOperators.toNum(obj)).getClass().isArray()) return Array.getLength(obj); return obj; } diff --git a/pom.xml b/pom.xml index b0fb715..28f89c6 100644 --- a/pom.xml +++ b/pom.xml @@ -1,115 +1,124 @@ - - 4.0.0 - - org.ugp - serialx - ${revision} - pom - - - SerialX-json - SerialX-core - SerialX-devtools - SerialX-operators - SerialX-juss - - - SerialX root - Store Java objects into JSON or any format you want! SerialX is a powerful lightweight utility library to serialize Java objects programmatically via tweakable recursive descent parser for custom domain-specific languages! - https://github.com/SimplyProgrammer/Java-SerialX - 2020 - - - - Custom license - https://github.com/SimplyProgrammer/Java-SerialX/blob/master/LICENSE - - - - - - SimplyProgrammer - petko.hupka@gmail.com - org.ugp - https://github.com/SimplyProgrammer/ - - - - - scm:git:git://github.com/SimplyProgrammer/Java-SerialX.git - scm:git:ssh://github.com:SimplyProgrammer/Java-SerialX.git - https://github.com/SimplyProgrammer/ - - - - 8 - 1.3.8 - + + 4.0.0 + + org.ugp + serialx + ${revision} + pom + + + SerialX-json + SerialX-core + SerialX-devtools + SerialX-operators + SerialX-juss + + + SerialX root + Store Java objects into JSON or any format you want! SerialX is a powerful lightweight utility library to serialize Java objects programmatically via tweakable recursive descent parser for custom domain-specific languages! + https://github.com/SimplyProgrammer/Java-SerialX + 2020 + + + + Custom license + https://github.com/SimplyProgrammer/Java-SerialX/blob/master/LICENSE + + + + + + SimplyProgrammer + petko.hupka@gmail.com + org.ugp + https://github.com/SimplyProgrammer/ + + + + + scm:git:git://github.com/SimplyProgrammer/Java-SerialX.git + scm:git:ssh://github.com:SimplyProgrammer/Java-SerialX.git + https://github.com/SimplyProgrammer/ + + + + + github + https://maven.pkg.github.com/SimplyProgrammer/Java-SerialX + + + + + 8 + 1.3.8 + UTF-8 - ${java.version} - ${java.version} - - serialx-${project.artifactId}-${project.version} + ${java.version} + ${java.version} + + serialx-${project.artifactId}-${project.version} ${project.build.finalName} - + - - org.apache.maven.plugins - maven-compiler-plugin - 3.10.1 - - - ${java.version} - ${java.version} - - eclipse - - - - org.codehaus.plexus - plexus-compiler-eclipse - 2.9.0 - - - org.eclipse.jdt - ecj - 3.25.0 - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.8.0 - - - -Xdoclint:none - -Xdoclint:none - - - - - - jar - - - - - - org.apache.maven.plugins - maven-source-plugin - 3.2.1 - - - - jar - - - - + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + + ${java.version} + ${java.version} + + eclipse + + + + org.codehaus.plexus + plexus-compiler-eclipse + 2.9.0 + + + org.eclipse.jdt + ecj + 3.25.0 + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.8.0 + + + -Xdoclint:none + -Xdoclint:none + + + + + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + + jar + + + + \ No newline at end of file From e32102f25c13556ce8168fe3079b697c23f35bfa Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sun, 22 Sep 2024 22:05:43 +0200 Subject: [PATCH 47/48] mvn flatten --- .gitignore | 1 + pom.xml | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 2957f58..e2e18c1 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ Thumbs.db UserInterfaceState.xcuserstate $RECYCLE.BIN/ +.flattened-* *.log log.txt npm-debug.log* diff --git a/pom.xml b/pom.xml index 28f89c6..7abb0bd 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,12 @@ SerialX root - Store Java objects into JSON or any format you want! SerialX is a powerful lightweight utility library to serialize Java objects programmatically via tweakable recursive descent parser for custom domain-specific languages! + + Store Java objects into JSON or any format you want! SerialX is + a powerful lightweight utility library to serialize Java objects + programmatically via tweakable recursive descent parser for custom + domain-specific languages! + https://github.com/SimplyProgrammer/Java-SerialX 2020 @@ -58,11 +63,11 @@ ${java.version} ${java.version} - serialx-${project.artifactId}-${project.version} + - ${project.build.finalName} + @@ -89,6 +94,7 @@ + org.apache.maven.plugins maven-javadoc-plugin @@ -119,6 +125,21 @@ + + org.codehaus.mojo + flatten-maven-plugin + 1.6.0 + + + + flatten + process-resources + + flatten + + + + \ No newline at end of file From db4d7a0fb027e117b7a71cca89ffe673bfd894fa Mon Sep 17 00:00:00 2001 From: Programmer001 Date: Sun, 22 Sep 2024 22:17:49 +0200 Subject: [PATCH 48/48] Java 21+ supported --- SerialX-core/src/main/java/org/ugp/serialx/Serializer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java index 80d0c19..f8dfda4 100644 --- a/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java +++ b/SerialX-core/src/main/java/org/ugp/serialx/Serializer.java @@ -22,6 +22,7 @@ import java.io.Writer; import java.lang.reflect.Type; import java.net.HttpURLConnection; +import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; @@ -740,7 +741,7 @@ public static T into(Object obj, Serializer fromSerializer, String... fieldN { if (indexOfNotInObj((CharSequence) obj, "http") == 0) { - URLConnection con = new URL(obj.toString()).openConnection(); + URLConnection con = new URI(obj.toString()).toURL().openConnection(); con.setDoOutput(true); if (con instanceof HttpURLConnection) post(fromSerializer, (HttpURLConnection) con); @@ -831,7 +832,7 @@ public static Serializer from(Serializer newInstance, Object fromObj, String... { String fromStr; if (indexOfNotInObj(fromStr = fromObj.toString(), "http") == 0) - return newInstance.LoadFrom(new URL(fromStr).openStream()); + return newInstance.LoadFrom(new URI(fromStr).toURL().openStream()); return newInstance.LoadFrom(new File(fromStr)); } catch (Exception e)