Skip to main content

Getting Started with Expresso

Key Features

  • Simple Syntax: Easy to learn and use
  • Type-Safe: Evaluate expressions with proper type checking
  • Variable Support: Inject variables into expressions
  • Property Access: Access object properties and array elements
  • Null Safety: Null-safe property access and array access with the ?. and ?[] operators
  • Default Values: Provide default values for null results with the ?? operator
  • Built-in Functions: String, math, and logic functions included
  • Custom Functions: Define your own functions easily
  • Error Handling: Comprehensive error reporting
  • Lightweight: Zero external dependencies

Installation

Add Expresso to your project using Maven:

<dependency>
<groupId>work.ghassen</groupId>
<artifactId>expresso</artifactId>
<version>1.0.0</version>
</dependency>

Basic Usage

Here's how to use Expresso in your Java code:

// Import the necessary classes
import com.expresso.ExpressionEvaluator;
import com.expresso.context.Context;

// Create an evaluator
ExpressionEvaluator evaluator = new ExpressionEvaluator();

// Create a context and add variables
Context context = new Context();
context.setVariable("name", "Alice");
context.setVariable("age", 25);

// Evaluate expressions
String result1 = (String) evaluator.evaluate("$name", context);
// result1 = "Alice"

int result2 = (Integer) evaluator.evaluate("$age", context);
// result2 = 25

// String functions
String result3 = (String) evaluator.evaluate("upperCase($name)", context);
// result3 = "ALICE"

// Math operations
int result4 = (Integer) evaluator.evaluate("$age + 5", context);
// result4 = 30

// Complex objects
context.setVariable("person", Map.of(
"name", "Bob",
"address", Map.of(
"city", "New York",
"zip", 10001
)
));

// Access object properties
String result5 = (String) evaluator.evaluate("$person.name", context);
// result5 = "Bob"

String result6 = (String) evaluator.evaluate("$person.address.city", context);
// result6 = "New York"

// Null-safe property access
Object result7 = evaluator.evaluate("$person?.nonExistent?.property", context);
// result7 = null (instead of throwing an exception)

// Null coalescing operator for default values
String result8 = (String) evaluator.evaluate("$person?.nonExistent?.property ?? 'Default'", context);
// result8 = "Default"

Custom Functions

You can extend Expresso with your own custom functions:

// Register a custom function
evaluator.registerFunction("add", (args) -> {
double x = ((Number) args[0]).doubleValue();
double y = ((Number) args[1]).doubleValue();
return x + y;
});

// Use the custom function
Double result = (Double) evaluator.evaluate("add(5, 3)", context);
// result = 8.0

// Custom string function
evaluator.registerFunction("greet", (args) -> {
String name = (String) args[0];
return "Hello, " + name + "!";
});

String greeting = (String) evaluator.evaluate("greet($name)", context);
// greeting = "Hello, Alice!"

// Function with variable number of arguments
evaluator.registerFunction("sum", (args) -> {
double sum = 0;
for (Object arg : args) {
sum += ((Number) arg).doubleValue();
}
return sum;
});

Double total = (Double) evaluator.evaluate("sum(1, 2, 3, 4, 5)", context);
// total = 15.0

Error Handling

Expresso provides comprehensive error handling:

try {
evaluator.evaluate("$nonExistentVariable", context);
} catch (PropertyNotFoundException e) {
// Handle property not found
}

try {
evaluator.evaluate("$person.address.city", context); // If address is null
} catch (PropertyNotFoundException e) {
// Handle property not found
}

// Alternative: Use null-safe access to avoid exceptions
String city = (String) evaluator.evaluate(
"$person?.address?.city ?? 'Unknown'",
context
);
// city will be "Unknown" if person or address is null

Supported Data Types

Expresso supports various data types:

  • Primitive types (int, long, double, boolean)
  • String
  • Arrays and Collections
  • Custom Objects
// Numbers
String numExpr = "$x + $y";
Map<String, Object> numVars = Map.of(
"x", 10,
"y", 20
);
Integer numResult = evaluator.evaluate(numExpr, numVars);
// Result: 30

// Booleans
String boolExpr = "$isActive && $hasPermission";
Map<String, Object> boolVars = Map.of(
"isActive", true,
"hasPermission", true
);
Boolean boolResult = evaluator.evaluate(boolExpr, boolVars);
// Result: true

Fluent Context API

Expresso provides a fluent API for creating and populating the evaluation context:

// Traditional approach
Context context = new Context();
context.setVariable("name", "Alice");
context.setVariable("age", 25);

// Fluent approach with method chaining
Context context = new Context()
.with("name", "Alice")
.with("age", 25)
.with("isStudent", true);

// Using static factory methods
Context context = Context.of("name", "Alice");

// Using a map of variables
Map<String, Object> variables = Map.of(
"name", "Bob",
"age", 30,
"city", "New York"
);
Context context = Context.of(variables);

// Adding multiple variables from a map
Context context = new Context()
.with("name", "Alice")
.withAll(Map.of("age", 25, "city", "London"));

This fluent API makes your code more concise and readable when setting up evaluation contexts.