JSON
Jackson JSON
Java Programming
Data Conversion
Map<String
String>

How to convert a JSON string to a Map<String, String> with Jackson JSON

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If your JSON payload is a simple object whose keys and values are both strings, Jackson can deserialize it directly into a Map<String, String>. The important part is using the right target type and recognizing when the JSON is too complex for that type to be correct.

The Straightforward Case

For JSON like this:

json
1{
2  "env": "prod",
3  "region": "ca-central-1"
4}

you can read directly into a string-to-string map with ObjectMapper and TypeReference.

java
1import com.fasterxml.jackson.core.type.TypeReference;
2import com.fasterxml.jackson.databind.ObjectMapper;
3
4import java.util.Map;
5
6public class JsonToMapDemo {
7    public static void main(String[] args) throws Exception {
8        String json = "{\"env\":\"prod\",\"region\":\"ca-central-1\"}";
9
10        ObjectMapper mapper = new ObjectMapper();
11        Map<String, String> values = mapper.readValue(
12            json,
13            new TypeReference<Map<String, String>>() {}
14        );
15
16        System.out.println(values.get("env"));
17        System.out.println(values);
18    }
19}

The TypeReference matters because Java erases generic type information at runtime. Without it, Jackson only sees a raw Map.

Why a Raw Map.class Is Not Enough

You will often see code like:

java
Map<?, ?> values = mapper.readValue(json, Map.class);

That works for quick inspection, but it gives you a loosely typed map. If you actually want a Map<String, String>, use TypeReference<Map<String, String>> so Jackson can enforce the target shape more accurately.

Typed code is easier to validate, document, and refactor.

Know When Map<String, String> Is the Wrong Type

The map type only works when every JSON value can be represented as a Java String. If your payload contains numbers, arrays, booleans, nulls, or nested objects, Map<String, String> is not the honest model.

For example, this JSON is not a string-to-string map:

json
1{
2  "name": "build-job",
3  "retries": 3,
4  "labels": ["ci", "nightly"]
5}

In that case, use Map<String, Object> or parse into JsonNode.

java
1import com.fasterxml.jackson.core.type.TypeReference;
2import com.fasterxml.jackson.databind.ObjectMapper;
3
4import java.util.Map;
5
6public class MixedJsonDemo {
7    public static void main(String[] args) throws Exception {
8        String json = "{\"name\":\"build-job\",\"retries\":3,\"labels\":[\"ci\",\"nightly\"]}";
9
10        ObjectMapper mapper = new ObjectMapper();
11        Map<String, Object> values = mapper.readValue(
12            json,
13            new TypeReference<Map<String, Object>>() {}
14        );
15
16        System.out.println(values);
17    }
18}

Trying to force that payload into Map<String, String> usually creates conversion failures or misleading stringified values.

If You Really Need Strings for Every Value

Sometimes the requirement is to flatten everything to strings for logging, headers, or form-style data. In that case, deserialize to JsonNode first and convert deliberately.

java
1import com.fasterxml.jackson.databind.JsonNode;
2import com.fasterxml.jackson.databind.ObjectMapper;
3
4import java.util.HashMap;
5import java.util.Iterator;
6import java.util.Map;
7
8public class StringifyValuesDemo {
9    public static void main(String[] args) throws Exception {
10        String json = "{\"name\":\"build-job\",\"retries\":3}";
11
12        ObjectMapper mapper = new ObjectMapper();
13        JsonNode node = mapper.readTree(json);
14
15        Map<String, String> values = new HashMap<>();
16        Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
17
18        while (fields.hasNext()) {
19            Map.Entry<String, JsonNode> field = fields.next();
20            values.put(field.getKey(), field.getValue().asText());
21        }
22
23        System.out.println(values);
24    }
25}

This is explicit about the conversion rule. It also makes it obvious that numeric and boolean values are being coerced into strings intentionally.

Error Handling and Validation

If the JSON comes from an external system, wrap deserialization in validation rather than assuming the payload is always a flat object.

For example, you may want to reject nested values instead of silently stringifying them. That is a business rule, not just a parsing detail.

One good pattern is:

  1. Parse with Jackson.
  2. Validate the shape you expect.
  3. Convert only after the shape is confirmed.

That keeps data errors visible instead of quietly normalizing them into misleading strings.

Common Pitfalls

The biggest mistake is using Map<String, String> for JSON that contains non-string values. The Java type should reflect the actual payload shape.

Another issue is relying on Map.class and then casting the result later. That defers type problems instead of solving them.

Developers also sometimes stringify nested objects accidentally and then treat those strings as if they were ordinary scalar values. If the JSON is nested, model it honestly with JsonNode, Map<String, Object>, or a dedicated DTO.

Finally, remember that deserialization is only half the problem. If downstream code assumes the map is complete or sanitized, validate inputs before using them.

Summary

  • Use ObjectMapper.readValue with TypeReference<Map<String, String>> for flat string-to-string JSON objects.
  • Use TypeReference because generics are erased at runtime.
  • Do not force mixed or nested JSON into Map<String, String> unless you intentionally convert values to strings.
  • Prefer Map<String, Object> or JsonNode for more complex payloads.
  • Validate the JSON shape before assuming a string-only map is appropriate.

Course illustration
Course illustration

All Rights Reserved.