Backend Development 17 min read

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.

Zhuanzhuan Tech
Zhuanzhuan Tech
Zhuanzhuan Tech
Transform JSON Seamlessly with Jolt: From Hard‑Coded Logic to Configurable Rules

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&lt;String, Function&gt; STOCK_FUNCTIONS = new HashMap&lt;&gt();
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&lt;Object&gt; 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&lt;String, Function&gt; functionsMap = new HashMap&lt;&gt;();
        functionsMap.put("equals", equalsFunction);
        functionsMap = Collections.unmodifiableMap(functionsMap);
        TemplatrSpecBuilder builder = new TemplatrSpecBuilder(OpMode.OVERWRITR, functionsMap);
        rootSpec = new ModifierCompositeSpec(ROOT_KEY, (Map&lt;String, Object&gt;) spec, OpMode.OVERWRITR, builder);
    }
    @Override
    public Object transform(Object input, Map&lt;String, Object&gt; context) {
        Map&lt;String, Object&gt; contextWrapper = new HashMap&lt;&gt;();
        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>&lt;dependency&gt;
    &lt;groupId&gt;com.bazaarvoice.jolt&lt;/groupId&gt;
    &lt;artifactId&gt;jolt-core&lt;/artifactId&gt;
    &lt;version&gt;0.1.6&lt;/version&gt;
&lt;/dependency&gt;</code>

Create Transformation Service

<code>@Service
public class JoltTransformService {
    public &lt;T&gt; T transformData(QualityReportDo reportDo, String key, TypeReference&lt;T&gt; 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&lt;Object&gt; 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&lt;MerchantReport&gt;() {});
        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.

Javaconfiguration managementSpring BootData mappingJoltJSON transformation
Zhuanzhuan Tech
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.