Question

How to Fix Jackson Unrecognized field Error in Java JSON Mapping

javajsondata-bindingjackson

Question

I need to convert a JSON string into a Java object using Jackson. The JSON comes from a web service, so I cannot change its structure.

This is the JSON input:

{"wrapper":[{"id":"13","name":"Fred"}]}

Here is a simplified version of my code:

private void tryReading() {
    String jsonStr = "{\"wrapper\":[{\"id\":\"13\",\"name\":\"Fred\"}]}";
    ObjectMapper mapper = new ObjectMapper();
    Wrapper wrapper = null;

    try {
        wrapper = mapper.readValue(jsonStr, Wrapper.class);
    } catch (Exception e) {
        e.printStackTrace();
    }

    System.out.println("wrapper = " + wrapper);
}

My Student class is:

public class Student {
    private String name;
    private String id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

My Wrapper class is intended to contain the list of students:

public class Wrapper {
    private List<Student> students;

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }
}

However, Jackson throws this exception:

org.codehaus.jackson.map.exc.UnrecognizedPropertyException:
Unrecognized field "wrapper" (Class Wrapper), not marked as ignorable

Why does this happen, and how should I structure my Java classes or annotations so Jackson can map this JSON correctly?

Short Answer

By the end of this page, you will understand why Jackson throws an UnrecognizedPropertyException, how JSON field names must match Java properties, and how to fix mismatches using proper class design or @JsonProperty. You will also learn common patterns for mapping nested JSON objects in Java.

Concept

Jackson converts JSON into Java objects by matching JSON property names to Java fields or setter/getter names.

In the JSON:

{
  "wrapper": [
    {"id": "13", "name": "Fred"}
  ]
}

The top-level object has one property named wrapper.

But your Java class looks like this:

public class Wrapper {
    private List<Student> students;
}

Jackson tries to map the JSON property wrapper to a Java property named wrapper, but your class only has a property named students. Since there is no matching field, Jackson raises:

Unrecognized field "wrapper"

This matters because JSON-to-object mapping depends on structure and naming. If the JSON shape and Java class shape do not match, deserialization fails.

There are two common ways to fix this:

  1. Rename the Java property to match the JSON field
  2. Keep the Java property name and use @JsonProperty("wrapper")

The key rule is:

  • JSON key wrapper must map to a Java property named wrapper, or
  • You must explicitly tell Jackson that students corresponds to JSON key wrapper

Also, your top-level JSON is not a Student. It is an object that contains a list of students under the wrapper key. So your Java model must reflect that nested structure.

Mental Model

Think of Jackson like a mail sorter reading labels on boxes.

  • JSON keys are the labels on the boxes.
  • Java fields are the slots where those boxes should go.

If the sorter sees a box labeled wrapper, it looks for a slot named wrapper.

If your class only has a slot named students, the sorter does not know where to put the wrapper box, so it throws an error.

You can fix this in two ways:

  • Rename the slot to wrapper
  • Add a note saying: "When you see wrapper, put it in students" using @JsonProperty("wrapper")

Jackson is strict by default because it assumes unexpected fields may indicate a bug.

Take Quiz

Syntax and Examples

Jackson maps JSON properties to Java properties using field names, setters, getters, or annotations.

Option 1: Match the JSON field name directly

import java.util.List;

public class Wrapper {
    private List<Student> wrapper;

    public List<Student> getWrapper() {
        return wrapper;
    }

    public void setWrapper(List<Student> wrapper) {
        this.wrapper = wrapper;
    }
}

This works because the JSON contains:

{"wrapper":[...]}

So Jackson finds a matching Java property named wrapper.

Option 2: Keep your preferred Java name with @JsonProperty

import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Wrapper {
    @JsonProperty("wrapper")
    private List<Student> students;

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }
}

This tells Jackson:

  • JSON field wrapper
  • should be mapped to Java field students

Full working example

import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Demo {
    public static void main(String[] args) {
        String jsonStr = "{\"wrapper\":[{\"id\":\"13\",\"name\":\"Fred\"}]}";
        ObjectMapper mapper = new ObjectMapper();

        try {
            Wrapper wrapper = mapper.readValue(jsonStr, Wrapper.class);
            System.out.println(wrapper.getStudents().get(0).getName());
            System.out.println(wrapper.getStudents().get(0).getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Student {
    private String name;
    private String id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

class Wrapper {
    @JsonProperty("wrapper")
    private List<Student> students;

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }
}

In this example, the JSON field is still named wrapper, but your Java code can use the more meaningful name students.

Step by Step Execution

Consider this code:

String jsonStr = "{\"wrapper\":[{\"id\":\"13\",\"name\":\"Fred\"}]}";
ObjectMapper mapper = new ObjectMapper();
Wrapper result = mapper.readValue(jsonStr, Wrapper.class);

And this class:

public class Wrapper {
    @JsonProperty("wrapper")
    private List<Student> students;

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }
}

What happens step by step

  1. Jackson reads the JSON string.
  2. It sees a top-level JSON object.
  3. Inside that object, it finds a property named wrapper.
  4. It looks at the Wrapper class for a matching property.
  5. Because of @JsonProperty("wrapper"), Jackson knows that JSON wrapper maps to Java students.
  6. Jackson sees that wrapper contains an array.
  7. It checks the Java type of students, which is List<Student>.
  8. For each object in the array, Jackson creates a Student instance.
  9. It maps:
    • JSON id -> Java id
    • JSON name -> Java name
  10. The Wrapper object is returned with one Student in the list.

Resulting object state

result.getStudents().size();   // 1
result.getStudents().get(0).getId();   // "13"
result.getStudents().get(0).getName(); // "Fred"

What caused the original error

In your original class:

public class Wrapper {
    private List<Student> students;
}

Jackson found JSON field wrapper, but there was no Java property called wrapper. Since it could not match the field, it threw an exception instead of guessing.

Real World Use Cases

This kind of mapping is common whenever Java applications consume external JSON.

Common real-world scenarios

  • Calling REST APIs where the response wraps data inside keys like data, results, items, or wrapper
  • Reading third-party web service responses that use names you cannot control
  • Importing data feeds from vendors or partners
  • Parsing configuration files where JSON keys do not match your preferred Java naming
  • Backend services that deserialize request bodies into domain objects

Example API response patterns

{"data":[{"id":1,"name":"Alice"}]}
{"results":[{"id":1,"name":"Alice"}]}
{"users":[{"id":1,"name":"Alice"}]}

In all of these cases, the Java class must either:

  • use matching property names, or
  • use annotations to map JSON names to Java names

This is especially useful when you want Java code to stay expressive, even if the API uses poor or inconsistent field names.

Take Quiz

Real Codebase Usage

In real projects, developers usually combine matching models, annotations, and defensive configuration.

Common patterns

1. Use DTOs that mirror external JSON

When consuming an API, it is common to create a DTO class specifically for the API response.

public class StudentResponse {
    @JsonProperty("wrapper")
    private List<Student> students;
}

This keeps external API structure separate from internal business models.

2. Use @JsonProperty for naming mismatches

This is the most direct and readable fix when the JSON name and Java name differ.

@JsonProperty("wrapper")
private List<Student> students;

3. Ignore unknown fields when APIs evolve

Some APIs add extra fields over time. To avoid breaking your code, developers often ignore fields they do not use.

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Wrapper {
    @JsonProperty("wrapper")
    private List<Student> students;
}

This does not fix a wrong field mapping, but it helps when the JSON contains extra properties.

4. Validate after deserialization

After mapping, developers often check for null or empty data.

if (wrapper == null || wrapper.getStudents() == null || wrapper.getStudents().isEmpty()) {
    throw new IllegalStateException("No students found");
}

5. Use clear response model names

Instead of naming everything Wrapper, many codebases use names such as:

  • StudentResponse
  • StudentListResponse
  • ApiStudentsResponse

These names explain what the object represents.

Common Mistakes

1. Java field name does not match JSON field name

Broken example:

public class Wrapper {
    private List<Student> students;
}

JSON:

{"wrapper":[{"id":"13","name":"Fred"}]}

Problem:

  • JSON has wrapper
  • Java has students
  • Jackson cannot match them automatically

Fix:

@JsonProperty("wrapper")
private List<Student> students;

2. Modeling the JSON structure incorrectly

Broken idea:

Trying to deserialize the JSON directly into List<Student>

List<Student> students = mapper.readValue(jsonStr, List.class);

Problem:

The JSON is not an array at the top level. It is an object containing an array.

Fix:

Create a top-level container class.

3. Forgetting getters and setters

Jackson often relies on getters/setters or accessible fields.

Broken example:

public class Student {
    private String id;
    private String name;
}

If fields are not accessible and no setters are available, mapping may fail depending on configuration.

Fix:

Add proper getters and setters, or configure field visibility.

4. Ignoring the exact JSON shape

Broken assumption:

Thinking this JSON:

{"wrapper":[...]}

matches this Java class:

public class Student {
    private String id;
    private String name;
}

Problem:

A Student is inside the array, not at the top level.

5. Using ignoreUnknown = true as the wrong fix

@JsonIgnoreProperties(ignoreUnknown = true)
public class Wrapper {
    private List<Student> students;
}

Problem:

This may suppress the error, but it will not map wrapper into students. You may end up with students == null.

Use @JsonProperty or rename the field instead.

6. Mixing old and new Jackson packages

Your stack trace shows:

org.codehaus.jackson...

Many modern examples use:

com.fasterxml.jackson...

Be careful not to mix imports from different Jackson versions in the same project.

Comparisons

ApproachWhen to use itExampleProsCons
Rename Java field to match JSONWhen you are fine using the API's field name in Javaprivate List<Student> wrapper;Simple, no annotation neededJava code may be less expressive
Use @JsonPropertyWhen you want a cleaner Java name@JsonProperty("wrapper") private List<Student> students;Clear mapping, readable Java codeRequires annotation
Ignore unknown fieldsWhen the JSON has extra fields you do not care about@JsonIgnoreProperties(ignoreUnknown = true)Makes code more tolerantDoes not solve wrong field-name mapping
Parse into JsonNode manuallyWhen JSON is dynamic or irregularJsonNode root = mapper.readTree(json)FlexibleMore manual code

@JsonProperty vs renaming the field

  • Renaming the field is simplest when the JSON name is acceptable in Java.
  • @JsonProperty is better when you want Java code to stay meaningful.

Strongly typed mapping vs manual parsing

StyleBest forTradeoff
Strongly typed POJOsStable API responsesCleaner and safer
JsonNode tree parsingUnpredictable JSONMore flexible but more verbose
Take Quiz

Cheat Sheet

Quick fix

If your JSON is:

{"wrapper":[{"id":"13","name":"Fred"}]}

and your Java field is named students, use:

@JsonProperty("wrapper")
private List<Student> students;

Core rule

Jackson maps JSON keys to Java properties by name.

  • JSON key wrapper -> Java property wrapper
  • or JSON key wrapper -> Java property students with @JsonProperty("wrapper")

Minimal working classes

public class Student {
    private String id;
    private String name;

    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}
public class Wrapper {
    @JsonProperty("wrapper")
    private List<Student> students;

    public List<Student> getStudents() { return students; }
    public void setStudents(List<Student> students) { this.students = students; }
}

Common annotations

  • @JsonProperty("name") -> map a JSON key to a Java field
  • @JsonIgnoreProperties(ignoreUnknown = true) -> ignore extra JSON fields

Common error meaning

Unrecognized field "wrapper"

Usually means:

  • JSON contains a key your class does not define
  • or the property name does not match

Important reminder

Ignoring unknown fields is not the same as mapping them correctly.

FAQ

Why does Jackson say Unrecognized field "wrapper"?

Because the JSON contains a property named wrapper, but your Java class does not have a matching property with that name.

How do I map a JSON field to a differently named Java field?

Use @JsonProperty:

@JsonProperty("wrapper")
private List<Student> students;

Can I just rename the Java field instead of using an annotation?

Yes. If you rename students to wrapper, Jackson can map it automatically.

Why can’t I deserialize this directly into List<Student>?

Because the top-level JSON is an object, not an array. The array is inside the wrapper property.

Does @JsonIgnoreProperties(ignoreUnknown = true) fix this problem?

No. It only ignores extra fields. It does not map wrapper to students.

Do I need getters and setters for Jackson?

Usually yes, unless you configure Jackson to use fields directly or use supported constructors/records.

What if the API response changes and adds more fields?

You can use @JsonIgnoreProperties(ignoreUnknown = true) to make your class tolerate additional unused fields.

Why do some examples use org.codehaus.jackson and others use com.fasterxml.jackson?

They are different Jackson package generations. Modern projects usually use com.fasterxml.jackson.

Take Quiz

Mini Project

Description

Build a small Java program that reads a JSON API response containing a wrapped list of students and converts it into Java objects using Jackson. This project demonstrates how to model top-level wrapper objects correctly and how to use @JsonProperty when the JSON field name does not match your preferred Java field name.

Goal

Create a working Java program that deserializes a wrapped JSON response into a Wrapper object and prints each student's ID and name.

Requirements

Create a Student class with id and name properties. Create a wrapper class that maps the JSON field wrapper to a Java List<Student>. Deserialize the JSON string using ObjectMapper. Print all students from the parsed result. Handle deserialization errors safely.

Take Quiz

Keep learning

Related questions

View more