How to Implement Data Desensitization with YAML and Java Maps

This article explains a step‑by‑step approach to mask sensitive fields in API responses by defining desensitization rules in YAML, loading them into Java Maps, and applying recursive logic to traverse nested structures and replace data using regular expressions.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
How to Implement Data Desensitization with YAML and Java Maps

Introduction

When a project requires masking specific fields in a transaction interface response without using AOP annotations, a straightforward method is to store field‑to‑rule mappings in a Map, iterate over the result, and apply the appropriate rule.

Understanding YAML Format Specification

Because the returned result may contain nested Map s, we store desensitization rules in a YAML file to ensure consistent maintenance and avoid errors.

YAML (YAML Ain’t Markup Language) is a lightweight data‑serialization format designed for human readability and easy parsing, compared with JSON, XML, and Properties files.

Compared with JSON: YAML syntax is more flexible and concise.

Compared with XML: YAML avoids verbose tags and angle brackets.

Compared with Properties: YAML supports complex structures like nested key‑value pairs and lists.

1. Basic Syntax

Use indentation to represent hierarchy (spaces or tabs, but not mixed).

Use a colon : to denote key‑value pairs.

Use a dash - to denote list items.

# Using indentation to represent hierarchy
server:
  port: 8080

# Using colon for key‑value
name: John Smith
age: 30

# Using dash for list items
hobbies:
  - reading
  - hiking
  - swimming

2. Comments

Use # for comments, which can appear at the beginning or end of a line.

# This is a comment
name: John Smith  # Inline comment

3. Strings

Strings can be single‑quoted, double‑quoted, or unquoted.

Double quotes allow escape sequences such as \n for newlines and \u for Unicode.

# Double‑quoted string
name: "John Smith"
# Single‑quoted string
nickname: 'Johnny'

4. Key‑Value Pairs

Key and value are separated by a colon and a space.

Keys can be strings or scalars; values can be strings, scalars, lists, or nested maps.

name: John Smith
age: 30
address:
  city: San Francisco
  state: California
  zip: 94107

5. Lists

Use a dash - to denote list items, which can be strings, scalars, or nested structures.

hobbies:
  - reading
  - hiking
  - swimming
people:
  - name: John Smith
    age: 30
  - name: Jane Doe
    age: 25

6. References

Use & to define an anchor and * to reference it.

address: &myaddress
  city: San Francisco
  state: California
shippingAddress: *myaddress

7. Multi‑Line Text Blocks

Use | to preserve line breaks.

Use > to fold line breaks into a single line.

# Preserving line breaks
description: |
  This is a
  multi‑line
  string.
# Folding line breaks
summary: >
  This is a summary
  that may contain
  line breaks.

8. Data Types

YAML supports strings, integers, floats, booleans, dates, etc.

Special tags like !!str, !!int can explicitly specify types.

age: !!int 30
weight: !!float 65.5
isMale: !!bool true
created: !!timestamp '2022-01-01 12:00:00'

9. Multi‑File

Use --- to separate multiple YAML documents.

# First file
name: John Smith
age: 30
---
# Second file
hobbies:
  - reading
  - hiking
  - swimming

Defining Desensitization Rule Format

For simple structures, the rule format is TransactionID->Field->Rule:

TransactionID:
  fieldName:
    rule: '/^(1[3-9][0-9])\d{4}(\d{4}$)/'

For nested lists, the format becomes TransactionID->Field(List)->Field->Rule:

TransactionID:
  listField:
    subField:
      rule: '/^(1[3-9][0-9])\d{4}(\d{4}$)/'

Using this hierarchy, we can retrieve a rule with Map.get("Key").

Desensitization Logic Implementation

Reading YAML Configuration

1. Create desensitize.yml with rules, e.g.:

Y3800:
  phone:
    rule: "(\\d{3})\\d{4}(\\d{4})"
    format: "$1****$2"
  idCard:
    rule: "(?<=\\w{6})\\w(?=\\w{4})"
    format: "*"
Y3801:
  idCard:
    rule: "(?<=\\w{3})\\w(?=\\w{4})"
    format: "+"
  list:
    phone:
      rule: "(\\d{3})\\d{4}(\\d{4})"
      format: "$1++++$2"

2. Define a utility class DataDesensitizationUtils and implement a method to load the YAML file into a Map<String, Object>:

public static Map<String, Object> loadYaml(String yamlFile) {
    Yaml yaml = new Yaml();
    try (InputStream in = DataDesensitizationUtils.class.getResourceAsStream(yamlFile)) {
        return yaml.loadAs(in, Map.class);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

Retrieving Nested Rules by Key Path

Recursive method getNestedMapValues(Map, String... keys) traverses nested maps until the innermost map is found.

public static Map<String, Object> getNestedMapValues(Map<String, Object> map, String... keys) {
    if (keys.length == 0 || !map.containsKey(keys[0])) return null;
    Object nested = map.get(keys[0]);
    if (keys.length == 1) {
        return nested instanceof Map ? (Map<String, Object>) nested : null;
    }
    return nested instanceof Map ? getNestedMapValues((Map<String, Object>) nested, Arrays.copyOfRange(keys, 1, keys.length)) : null;
}

Applying Desensitization

Method desensitizeLogic(String data, Map<String, Object> map) uses the rule’s regex and format to mask the data.

private static String desensitizeLogic(String data, Map<String, Object> map) {
    if (map.containsKey("rule")) {
        String rule = (String) map.get("rule");
        String sign = map.getOrDefault("format", "*").toString();
        return data.replaceAll(rule, sign);
    }
    return data;
}

Recursive Traversal of Entity Data

The core method parseData(Object entity, String servNo, String path) walks through maps and lists, builds the current key path, fetches the corresponding rule via getNestedMap, and replaces the value while logging the process.

public static void parseData(Object entity, String servNo, String path) {
    if (entity instanceof Map) {
        for (Map.Entry<String, Object> entry : ((Map<String, Object>) entity).entrySet()) {
            String currentPath = path.isEmpty() ? entry.getKey() : path + "," + entry.getKey();
            if (entry.getValue() instanceof Map) {
                parseData(entry.getValue(), servNo, currentPath);
            } else if (entry.getValue() instanceof List) {
                for (Object item : (List) entry.getValue()) {
                    if (item instanceof Map) parseData(item, servNo, currentPath);
                }
            } else {
                String[] keyPaths = (servNo + "," + currentPath).split(",");
                Map<String, Object> ruleMap = getNestedMap(keyPaths);
                if (ruleMap != null) {
                    log.info("--- Transaction [{}], Field [{}] start desensitization ---", servNo, currentPath.replace(",", "->"));
                    log.info("Original: [{}:{}]", entry.getKey(), entry.getValue());
                    log.info("Rule: {}", ruleMap);
                    String desensitized = desensitizeLogic(entry.getValue().toString(), ruleMap);
                    entry.setValue(desensitized);
                    log.info("Desensitized: [{}:{}]", entry.getKey(), entry.getValue());
                    log.info("--- Transaction [{}], Field [{}] desensitization end ---", servNo, currentPath.replace(",", "->"));
                }
            }
        }
    }
}

Testing

A Demo class builds sample data, loads the YAML rules, and calls parseData. Console output shows the original and masked values for fields like idCard and phone.

-----------------交易【Y3801】,字段【idCard】开始脱敏-----------------
原始值:【idCard:130428197001180384】
脱敏规则:{rule=(?<=\w{3})\w(?=\w{4}), format=+}
脱敏值:【idCard:130+++++++++++0384】
-----------------交易【Y3801】,字段【idCard】脱敏结束-----------------
...

Complete Utility Class

The final DataDesensitizationUtils class combines YAML loading, nested map retrieval, recursive traversal, and masking logic into a reusable component for data privacy handling in backend services.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

loggingmapYAMLdata desensitizationRegex
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

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.