# Serialization & Deserialization

## SerializationUtils class

mXparser delivers a SerializationUtils utility class for simplifying serialization and deserialization of parser (and not only) objects. Serialization can be very useful if you are creating a complex structure of expressions, functions and arguments and want to keep their exact state (an exact copy) for later reuse (e.g. after restarting the application).

Important – using binary serialization you confirm that you understand the security risks.

## Binary serialization SECURITY WARNING

WARNING: Deserializing data from an untrusted source can introduce security vulnerabilities to your application. Depending on the settings used during deserialization, untrusted data may be able to execute arbitrary code or cause a denial of service attack. Untrusted data can come from over the network from an untrusted source (e.g. any network client), or it can be manipulated/tampered by an intermediary while in transit over an unauthenticated connection, or from local storage where it may have been compromised/tampered, or from many other sources. MathParser.org-mXparser does not provide any means to authenticate data or secure it from tampering. Use an appropriate data authentication method before deserializing. Be very mindful of these attack scenarios; many projects and companies and users of serialization libraries in general have been bitten by untrusted deserialization of user data in the past.

## Case 1: Enabling / Disabling binary serialization

Binary serialization is disabled by default. You can enable it if you are aware of security risks.

import org.mariuszgromada.math.mxparser.*;
...
// By default, binary serialization / deserialization by SerializationUtils is disabled.
SerializationUtils.enableBinarySerializationIamAwareOfSecurityRisks();
mXparser.consolePrintln("Was the last operation successful = " + SerializationUtils.checkLastOperationWasSuccessful());
mXparser.consolePrintln("The last operation message = " + SerializationUtils.getLastOperationMessage());
mXparser.consolePrintln("-----------------------------------");
// Now you can serialize and deserialize objects via SerializationUtils
SerializationUtils.disableBinarySerialization();
mXparser.consolePrintln("Was the last operation successful = " + SerializationUtils.checkLastOperationWasSuccessful());
mXparser.consolePrintln("The last operation message = " + SerializationUtils.getLastOperationMessage());
// Now executing the SerializationUtils API will return an error

[mXparser-v.5.1.0] Was the last operation successful = true
[mXparser-v.5.1.0] The last operation message = Binary serialization is enabled. Use it only in a conscious and limited way.
[mXparser-v.5.1.0] -----------------------------------
[mXparser-v.5.1.0] Was the last operation successful = true
[mXparser-v.5.1.0] The last operation message = Binary serialization is disabled. You can enable it if you are aware of security risks.


## Case 2: Expression serialization / deserialization from / to byte[]

import org.mariuszgromada.math.mxparser.*;
...
Expression e = new Expression("2+3/sin(pi/2)");
SerializationUtils.enableBinarySerializationIamAwareOfSecurityRisks();
// This is where the entire object is serialized
mXparser.consolePrintln("This is where the entire object is serialized");
byte data[] = SerializationUtils.serializeToBytes(e);
mXparser.consolePrintln("Last operation = " + SerializationUtils.checkLastOperationWasSuccessful());
mXparser.consolePrintln("Message = " + SerializationUtils.getLastOperationMessage());
// This is where the entire object is deserialized
mXparser.consolePrintln("This is where the entire object is deserialized");
Expression eCopy = SerializationUtils.deserializeFromBytes(data);
mXparser.consolePrintln("Last operation = " + SerializationUtils.checkLastOperationWasSuccessful());
mXparser.consolePrintln("Message = " + SerializationUtils.getLastOperationMessage());
SerializationUtils.disableBinarySerialization();
// And here we check if the copy of the Expression "works"
mXparser.consolePrintln("And here we check if the copy of the Expression \"works\"");
mXparser.consolePrintln("eCopy.calculate() = " + eCopy.calculate());

[mXparser-v.5.1.0] This is where the entire object is serialized
[mXparser-v.5.1.0] Last operation = true
[mXparser-v.5.1.0] Message = Serialization has been performed: Expression
[mXparser-v.5.1.0] This is where the entire object is deserialized
[mXparser-v.5.1.0] Last operation = true
[mXparser-v.5.1.0] Message = Deserialization has been performed: Expression
[mXparser-v.5.1.0] And here we check if the copy of the Expression "works"
[mXparser-v.5.1.0] eCopy.calculate() = 5.0


## Case 3: Expression serialization / deserialization from / to String

import org.mariuszgromada.math.mxparser.*;
...
Expression e = new Expression("2+3/sin(pi/2)");
SerializationUtils.enableBinarySerializationIamAwareOfSecurityRisks();
// This is where the entire object is serialized
mXparser.consolePrintln("This is where the entire object is serialized");
String data = SerializationUtils.serializeToString(e);
mXparser.consolePrintln("Last operation = " + SerializationUtils.checkLastOperationWasSuccessful());
mXparser.consolePrintln("Message = " + SerializationUtils.getLastOperationMessage());
// This is where the entire object is deserialized
mXparser.consolePrintln("This is where the entire object is deserialized");
Expression eCopy = SerializationUtils.deserializeFromString(data);
mXparser.consolePrintln("Last operation = " + SerializationUtils.checkLastOperationWasSuccessful());
mXparser.consolePrintln("Message = " + SerializationUtils.getLastOperationMessage());
SerializationUtils.disableBinarySerialization();
// And here we check if the copy of the Expression "works"
mXparser.consolePrintln("And here we check if the copy of the Expression \"works\"");
mXparser.consolePrintln("eCopy.calculate() = " + eCopy.calculate());

[mXparser-v.5.1.0] This is where the entire object is serialized
[mXparser-v.5.1.0] Last operation = true
[mXparser-v.5.1.0] Message = Serialization has been performed: Expression
[mXparser-v.5.1.0] This is where the entire object is deserialized
[mXparser-v.5.1.0] Last operation = true
[mXparser-v.5.1.0] Message = Deserialization has been performed: Expression
[mXparser-v.5.1.0] And here we check if the copy of the Expression "works"
[mXparser-v.5.1.0] eCopy.calculate() = 5.0


## Case 4: Expression serialization / deserialization from / to File

import org.mariuszgromada.math.mxparser.*;
...
Expression e = new Expression("2+3/sin(pi/2)");
SerializationUtils.enableBinarySerializationIamAwareOfSecurityRisks();
// This is where the entire object is serialized
mXparser.consolePrintln("This is where the entire object is serialized");
boolean toFileStatus = SerializationUtils.serializeToFile(e, "d:\\tmp\\exp.ser");
mXparser.consolePrintln("Last operation = " + SerializationUtils.checkLastOperationWasSuccessful());
mXparser.consolePrintln("Message = " + SerializationUtils.getLastOperationMessage());
// This is where the entire object is deserialized
mXparser.consolePrintln("This is where the entire object is deserialized");
Expression eCopy = SerializationUtils.deserializeFromFile("d:\\tmp\\exp.ser");
mXparser.consolePrintln("Last operation = " + SerializationUtils.checkLastOperationWasSuccessful());
mXparser.consolePrintln("Message = " + SerializationUtils.getLastOperationMessage());
SerializationUtils.disableBinarySerialization();
// And here we check if the copy of the Expression "works"
mXparser.consolePrintln("And here we check if the copy of the Expression \"works\"");
mXparser.consolePrintln("eCopy.calculate() = " + eCopy.calculate());

[mXparser-v.5.1.0] This is where the entire object is serialized
[mXparser-v.5.1.0] Last operation = true
[mXparser-v.5.1.0] Message = Serialization has been performed: Expression, d:\tmp\exp.ser
[mXparser-v.5.1.0] This is where the entire object is deserialized
[mXparser-v.5.1.0] Last operation = true
[mXparser-v.5.1.0] Message = Deserialization has been performed: Expression, d:\tmp\exp.ser
[mXparser-v.5.1.0] And here we check if the copy of the Expression "works"
[mXparser-v.5.1.0] eCopy.calculate() = 5.0


## Case 5: Serialization / Deserialization of complex objects

import org.mariuszgromada.math.mxparser.*;
...
// We create objects that contain other objects
Function f = new Function("f(x) = x^2");
Function g = new Function("g(x,y) = sqrt(f(x) + f(y))", f);
Argument a = new Argument("a = 3");
Argument b = new Argument("b = 4");
Expression e = new Expression("g(a,b)", g, a, b);
mXparser.consolePrintln("Syntax status before pre-compilation: " + e.getSyntaxStatus());
mXparser.consolePrintln("Message before pre-compilation: " + e.getErrorMessage());
mXparser.consolePrintln("----------------------------------");
mXparser.consolePrintln("Calculated value = " + e.calculate());
mXparser.consolePrintln("Syntax status before serialization: " + e.getSyntaxStatus());
mXparser.consolePrintln("Message after before serialization: " + e.getErrorMessage());
mXparser.consolePrintln("----------------------------------");
SerializationUtils.enableBinarySerializationIamAwareOfSecurityRisks();
// We serialize everything by calling one function
byte[] data = SerializationUtils.serializeToBytes(e);
mXparser.consolePrintln("Last operation = " + SerializationUtils.checkLastOperationWasSuccessful());
mXparser.consolePrintln("Message = " + SerializationUtils.getLastOperationMessage());
Expression eCopy = SerializationUtils.deserializeFromBytes(data);
SerializationUtils.disableBinarySerialization();
mXparser.consolePrintln("----------------------------------");
mXparser.consolePrintln("Syntax status after deserialization: " + eCopy.getSyntaxStatus());
mXparser.consolePrintln("Message after deserialization: " + eCopy.getErrorMessage());
mXparser.consolePrintln("Calculated value after deserialization = " + eCopy.calculate());
mXparser.consolePrintln("----------------------------------");
// If necessary, we can find copies of the components.
Argument aCopy = eCopy.getArgument("a");
Argument bCopy = eCopy.getArgument("b");
Function gCopy = eCopy.getFunction("g");
Function fCopy = gCopy.getFunction("f");
aCopy.setArgumentValue(5);
bCopy.setArgumentValue(12);
mXparser.consolePrintln("Calculated value after arguments values modification = " + eCopy.calculate());

[mXparser-v.5.1.0] Syntax status before pre-compilation: false
[mXparser-v.5.1.0] Message before pre-compilation: Syntax status unknown.
[mXparser-v.5.1.0] ----------------------------------
[mXparser-v.5.1.0] Calculated value = 5.0
[mXparser-v.5.1.0] Syntax status before serialization: true
[mXparser-v.5.1.0] Message after before serialization: [g(a,b)] checking ...
[g(a,b)] (g, 0) checking user defined function ...
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] checking ...
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] (f, 2) checking user defined function ...
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] -> [f] = [ x^2] checking ...
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] -> [f] = [ x^2] no errors.
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] (f, 7) checking user defined function ...
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] -> [f] = [ x^2] already checked - no errors!
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] no errors.
[g(a,b)] no errors.
[mXparser-v.5.1.0] ----------------------------------
[mXparser-v.5.1.0] Last operation = true
[mXparser-v.5.1.0] Message = Serialization has been performed: Expression
[mXparser-v.5.1.0] ----------------------------------
[mXparser-v.5.1.0] Syntax status after deserialization: true
[mXparser-v.5.1.0] Message after deserialization: [g(a,b)] checking ...
[g(a,b)] (g, 0) checking user defined function ...
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] checking ...
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] (f, 2) checking user defined function ...
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] -> [f] = [ x^2] checking ...
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] -> [f] = [ x^2] no errors.
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] (f, 7) checking user defined function ...
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] -> [f] = [ x^2] already checked - no errors!
[g(a,b)] -> [g] = [ sqrt(f(x) + f(y))] no errors.
[g(a,b)] no errors.
[mXparser-v.5.1.0] Calculated value after deserialization = 5.0
[mXparser-v.5.1.0] ----------------------------------
[mXparser-v.5.1.0] Calculated value after arguments values modification = 13.0

###### Nuget – Package Manager

Install-Package MathParser.org-mXparser -Version 5.1.0

Nuget – .NET CLI

dotnet add package MathParser.org-mXparser --version 5.1.0

Nuget – Package Reference

<PackageReference Include="MathParser.org-mXparser" Version="5.1.0"/>

###### Maven – Dependency

<dependency><groupid>org.mariuszgromada.math</groupid><artifactid>MathParser.org-mXparser</artifactid><version>5.1.0</version></dependency>

implementation 'org.mariuszgromada.math:MathParser.org-mXparser:5.1.0'

implementation("org.mariuszgromada.math:MathParser.org-mXparser:5.1.0")
git clone https://github.com/mariuszgromada/MathParser.org-mXparser