Transform JSON Seamlessly with Jolt: From Hard‑Coded Logic to Configurable Rules
This article introduces Jolt, an open‑source Java library for JSON‑to‑JSON transformation, explains its advantages over traditional hard‑coded conversion, demonstrates core operations and custom extensions with code examples, shows how to integrate it into Spring Boot, and outlines future plans for a visual drag‑and‑drop configuration tool.
Background
In the second‑hand luxury goods industry, a professional quality‑inspection report is the cornerstone of trust. Different stakeholders—B2B merchants, C2C sellers, and platform operators—value the same inspection data differently, and their needs evolve rapidly, making static code changes impractical.
Jolt Overview
What is Jolt?
Jolt is an open‑source Java library (by Bazaarvoice) that transforms JSON to JSON using JSON‑based specifications. It lets you describe conversion rules with JSON, turning data transformation into a configuration problem.
Why Jolt Stands Out?
Traditional conversion requires hard‑coded Java logic that must be recompiled for any change. Example of hard‑coded conversion:
<code>// Traditional way: painful hard‑coding, any data or position change needs redeployment
if (Objects.equals("B2B", userType)) {
merchantQualityReport.setAdditionalInfo(base.getAd());
merchantQualityReport.setBasicFunctionInfo(base.getBa());
// ... dozens or hundreds of lines of mapping logic
} else if (Objects.equals("B2C", userType)) {
qualityReport.setFinenessLevel(base.getFin());
qualityReport.setOtherDetailInfo(base.getOther());
// ... another large block of mapping logic
}</code>With Jolt the same logic becomes a concise JSON spec:
<code>{
"operation": "shift",
"spec": {
"ad": "additionalInfo",
"base": "basicFunctionInfo"
}
}</code>Core Advantages
1. Configurable Management
Transformation logic is stored in JSON files and can be placed in a configuration center.
No recompilation; rules can be adjusted at runtime.
2. Powerful Transformation Capability
Supports complex nested structures and custom operators.
Provides a rich set of built‑in operators.
Handles arrays, conditional transformations, and other advanced scenarios.
3. Chainable Operations
Multiple transformations can be chained.
Each step focuses on a single responsibility.
Complex logic is built by composing simple operations.
Core Concepts Overview
Jolt offers several basic operations that can be combined like building blocks:
shift : Move and reorganize data, e.g., rename fields.
default : Add default values for missing fields.
remove : Delete fields, useful for filtering sensitive information.
sort : Sort fields to normalize output.
cardinality : Convert between single values and arrays.
Typical Application Scenarios
API gateway – unify data formats across micro‑services.
Data migration – convert formats between legacy and new systems.
Reporting systems – satisfy flexible data presentation requirements.
Scenario‑Based Practice
Blueprint: Report Generation Process Based on Jolt
Problems with Traditional Architecture
Before Jolt, each report required a dedicated converter class, leading to hundreds of lines of mapping code:
<code>public class B2BReportConverter {
public B2BReport convert(InspectionData data) {
B2BReport report = new B2BReport();
report.setProductCode(data.getBasicInfo().getCode());
report.setAuthResult(data.getAuthentication().getResult());
// ... hundreds of lines of field mapping
}
}
public class B2CReportConverter {
public B2CReport convert(InspectionData data) {
// ... another completely different mapping logic
}
}</code>Pain points:
Adding a new report format means creating a new converter class with extensive logic.
Changing inspection items requires code changes, testing, and redeployment.
New Process Design Idea
Decouple transformation logic from code by defining business codes and storing Jolt specifications in a configuration center, enabling hot‑updates and version management.
Jolt Syntax Crash Course
Quickly master the core operations.
shift – Data Mover
Basic example: field renaming.
<code>// Original data
{
"productName": "LV Neverfull",
"productPrice": 8500
}
// Jolt spec
[
{
"operation": "shift",
"spec": {
"productName": "name", // move productName to name
"productPrice": "price" // move productPrice to price
}
}
]
// Result
{
"name": "LV Neverfull",
"price": 8500
}</code>Advanced example: data restructuring into nested objects.
<code>// Original data
{
"brand": "Hermès",
"model": "Birkin 30",
"color": "黑色",
"material": "Togo皮"
}
// Jolt spec – reorganize into nested structure
[
{
"operation": "shift",
"spec": {
"brand": "basicInfo.brand",
"model": "basicInfo.model",
"color": "appearance.color",
"material": "appearance.material"
}
}
]
// Result
{
"basicInfo": {
"brand": "Hermès",
"model": "Birkin 30"
},
"appearance": {
"color": "黑色",
"material": "Togo皮"
}
}</code>default – Default Value Filler
Add missing fields with default values.
<code>// Original data
{
"productId": "LX001",
"authenticity": "真品"
}
// Jolt spec – add defaults
[
{
"operation": "default",
"spec": {
"status": "待审核",
"priority": "normal",
"tags": ["二手奢侈品"],
"inspection": {
"required": true,
"level": "standard"
}
}
}
]
// Result
{
"productId": "LX001",
"authenticity": "真品",
"status": "待审核",
"priority": "normal",
"tags": ["二手奢侈品"],
"inspection": {
"required": true,
"level": "standard"
}
}</code>remove – Sensitive Information Filter
Delete fields that should not be exposed.
<code>// Original data
{
"orderId": "2024001",
"customerName": "张女士",
"customerPhone": "138****1234",
"internalCost": 5000,
"sellingPrice": 8500,
"profit": 3500
}
// Jolt spec – remove internal fields
[
{
"operation": "remove",
"spec": {
"internalCost": "",
"profit": ""
}
}
]
// Result
{
"orderId": "2024001",
"customerName": "张女士",
"customerPhone": "138****1234",
"sellingPrice": 8500
}</code>modify-overwrite-beta – Content Converter
Provides functions for formatting, type conversion, etc.
<code>private static final Map<String, Function> STOCK_FUNCTIONS = new HashMap<>();
static {
STOCK_FUNCTIONS.put("toLower", new Strings.toLowerCase());
STOCK_FUNCTIONS.put("toUpper", new Strings.toUpperCase());
STOCK_FUNCTIONS.put("concat", new Strings.concat());
// ... more functions
}
// Example Jolt spec using modify-overwrite-beta
[
{
"operation": "modify-overwrite-beta",
"spec": {
"brand": "=concat(@(1,brand), ' - 路易威登')",
"model": "=toUpper(@(1,model))",
"price": "=concat('¥', @(1,price), '.00')",
"authenticity": "=toString(@(1,authenticity))",
"condition": "=concat('成色:', @(1,condition), '级')"
}
}
]
// Result
{
"brand": "LV - 路易威登",
"model": "NEVERFULL MM",
"price": "¥12800.00",
"authenticity": "true",
"condition": "成色:A级"
}</code>Custom Operators
When built‑in functions are insufficient, you can implement custom functions and a custom transform class.
<code>public class EqualsFunction implements Function {
@Override
public Optional<Object> apply(Object... args) {
if (args == null || args.length < 2) {
return Optional.empty();
}
if (args[0] == null || args[1] == null) {
return Optional.of(false);
}
return Optional.of(Objects.equals(args[0], args[1]));
}
}</code> <code>public class CustomizeTransform implements SpecDriven, ContextualTransform {
private final ModifierCompositeSpec rootSpec;
public CustomizeTransform(Object spec) {
EqualsFunction equalsFunction = new EqualsFunction();
Map<String, Function> functionsMap = new HashMap<>();
functionsMap.put("equals", equalsFunction);
functionsMap = Collections.unmodifiableMap(functionsMap);
TemplatrSpecBuilder builder = new TemplatrSpecBuilder(OpMode.OVERWRITR, functionsMap);
rootSpec = new ModifierCompositeSpec(ROOT_KEY, (Map<String, Object>) spec, OpMode.OVERWRITR, builder);
}
@Override
public Object transform(Object input, Map<String, Object> context) {
Map<String, Object> contextWrapper = new HashMap<>();
contextWrapper.put(ROOT_KEY, context);
MatchedElement rootLpe = new MatchedElement(ROOT_KEY);
WalkedPath walkedPath = new WalkedPath();
walkedPath.add(input, rootLpe);
rootSpec.apply(ROOT_KEY, Optional.of(input), walkedPath, null, contextWrapper);
return input;
}
}</code>Using the custom operator in a Jolt spec:
<code>[
{
"operation": "com.luxuryqc.jolt.CustomizeTransform",
"spec": {
"assessment.overallRating": "=equals(@(1,assessment.authenticityConfirmed), true) && =equals(@(1,assessment.qualityGrade), true) ? 'S级精品' : 'A级优品'"
}
}
]</code>Integrating Jolt in Spring Boot
Add Maven Dependency
<code><dependency>
<groupId>com.bazaarvoice.jolt</groupId>
<artifactId>jolt-core</artifactId>
<version>0.1.6</version>
</dependency></code>Create Transformation Service
<code>@Service
public class JoltTransformService {
public <T> T transformData(QualityReportDo reportDo, String key, TypeReference<T> typeReference) {
try {
Chainr chainr = Chainr.fromSpec(getRuleInfo(key));
Object transform = chainr.transform(reportDo);
if (transform == null) {
throw new BusinessException("transform is null");
}
return JsonUtil.silentString2Object(JsonUtil.silentObject2String(transform), typeReference);
} catch (Exception e) {
log.error("transformData error key: {} ", key, e);
throw new BusinessException("数据规则转换异常");
}
}
public List<Object> getRuleInfo(String key) {
String rule = getRule(key); // fetch from config center or DB
return JsonUtils.jsonToList(rule);
}
}
</code>Controller Usage
<code>@RestController
@RequestMapping("/api/report")
public class ReportController {
@Autowired
private JoltTransformService transformService;
public MerchantReport generateMerchantReport(String reportId) {
QualityReportDo reportDo = getQualityReport(reportId);
MerchantReport merchantReport = transformService.transformData(
reportDo,
"MERCHANT_REPORT_RULE", // rule key in config center
new TypeReference<MerchantReport>() {});
postProcessMerchantReport(merchantReport);
return merchantReport;
}
}
</code>Future Planning
The current Jolt‑based solution meets most business needs, but the JSON configuration still requires technical knowledge, posing a barrier for non‑technical users. The next phase will deliver a visual drag‑and‑drop component library that provides WYSIWYG preview, lowers the entry threshold, accelerates configuration from days to minutes, reduces errors through intelligent hints, and empowers business teams to iterate quickly.
Zhuanzhuan Tech
A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.