- Introduction
- Creating Context
- Adding Variables
- Data Types
- POJO Conversion
- Variable Scope
- Best Practices
The Context object is the bridge between your Java code and JHP templates. It holds all the data that will be available to your templates during rendering.
Create a new context instance:
Context ctx = new Context();Add variables to the context using the add() method:
ctx.add("variableName", value);Context ctx = new Context();
ctx.add("title", "My Page");
ctx.add("count", 42);
ctx.add("active", true);Template:
<h1>{{ title }}</h1>
<p>Count: {{ count }}</p>
<p>Active: {{ active }}</p>Context supports all common Java data types.
ctx.add("name", "Alice");
ctx.add("email", "alice@example.com");ctx.add("age", 25); // Integer
ctx.add("price", 19.99); // Double
ctx.add("count", 100L); // Long
ctx.add("rating", 4.5f); // Floatctx.add("isActive", true);
ctx.add("verified", false);ctx.add("optional", null);Template:
{{ optional }}
<!-- Renders as empty string -->List<String> fruits = Arrays.asList("Apple", "Banana", "Cherry");
ctx.add("fruits", fruits);
Set<Integer> numbers = new HashSet<>(Arrays.asList(1, 2, 3));
ctx.add("numbers", numbers);Template:
{% foreach (fruit in fruits) %}
<li>{{ fruit }}</li>
{% endforeach %}String[] colors = {"Red", "Green", "Blue"};
ctx.add("colors", colors);
int[] scores = {85, 90, 78, 92};
ctx.add("scores", scores);Template:
{{ colors[0] }}
{{ scores[1] }}Map<String, Object> user = new HashMap<>();
user.put("name", "Bob");
user.put("age", 30);
user.put("email", "bob@example.com");
ctx.add("user", user);Template:
{{ user.name }}
{{ user.age }}
{{ user["email"] }}Context automatically converts Plain Old Java Objects (POJOs) to Maps.
class User {
public String name;
public int age;
public String email;
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
}
User user = new User("Alice", 25, "alice@example.com");
ctx.add("user", user);Template:
<h2>{{ user.name }}</h2>
<p>Age: {{ user.age }}</p>
<p>Email: {{ user.email }}</p>- Only public fields are converted
- Nested POJOs are skipped (only primitives, strings, collections, and arrays)
- Collections and arrays within POJOs are converted recursively
class Product {
public String name;
public double price;
public List<String> tags;
public Product(String name, double price, List<String> tags) {
this.name = name;
this.price = price;
this.tags = tags;
}
}
Product product = new Product("Laptop", 999.99, Arrays.asList("electronics", "computers"));
ctx.add("product", product);Template:
<h3>{{ product.name }}</h3>
<p>${{ product.price }}</p>
<ul>
{% foreach (tag in product.tags) %}
<li>{{ tag }}</li>
{% endforeach %}
</ul>class Address {
public String city;
public String country;
}
class User {
public String name;
public Address address; // This will be skipped
}Workaround: Convert nested objects to Maps manually:
User user = new User();
user.name = "Alice";
Map<String, Object> userMap = new HashMap<>();
userMap.put("name", user.name);
Map<String, String> addressMap = new HashMap<>();
addressMap.put("city", user.address.city);
addressMap.put("country", user.address.country);
userMap.put("address", addressMap);
ctx.add("user", userMap);Variables added to the context are available throughout the template:
ctx.add("siteName", "My Website");Template:
<header>{{ siteName }}</header>
<main>{{ siteName }}</main>
<footer>{{ siteName }}</footer>Loop variables are scoped to the loop:
{% for (i = 0; i < 5; i++) %}
{{ i }} <!-- i is available here -->
{% endfor %}
{{ i }} <!-- i is NOT available here -->Included templates have access to the parent context:
main.jhp:
{% include 'header.jhp' %}header.jhp:
<h1>{{ title }}</h1> <!-- Can access title from main context -->// Good
ctx.add("userName", "Alice");
ctx.add("productList", products);
// Avoid
ctx.add("x", "Alice");
ctx.add("data", products);// Better for templates
Map<String, Object> user = new HashMap<>();
user.put("name", "Alice");
user.put("profile", profileMap);
ctx.add("user", user);// Good - calculate in Java
int total = items.stream().mapToInt(Item::getPrice).sum();
ctx.add("total", total);
// Avoid - complex logic in template
ctx.add("items", items);
// Then doing: {{ items[0].price + items[1].price + ... }}ctx.add("title", title != null ? title : "Untitled");
ctx.add("items", items != null ? items : Collections.emptyList());Map<String, Object> page = new HashMap<>();
page.put("title", "Home");
page.put("description", "Welcome");
page.put("keywords", Arrays.asList("home", "welcome"));
ctx.add("page", page);Template:
<title>{{ page.title }}</title>
<meta name="description" content="{{ page.description }}">// Create a base context with common variables
Context baseContext = new Context();
baseContext.add("siteName", "My Site");
baseContext.add("year", 2025);
// For each page, create a new context with page-specific data
Context pageContext = new Context();
// Copy base context data
pageContext.getContext().putAll(baseContext.getContext());
pageContext.add("title", "Page Title");Access the underlying map if needed:
Context ctx = new Context();
ctx.add("name", "Alice");
Map<String, Object> data = ctx.getContext();
System.out.println(data.get("name")); // AliceThe Context class doesn't enforce immutability. Variables can be modified during rendering (e.g., in loops). If you need immutable data, consider using immutable collections:
List<String> items = List.of("A", "B", "C"); // Immutable list
ctx.add("items", items);- Learn about Configuration
- Explore Advanced Usage
- Review API Reference