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:
- Rename the Java property to match the JSON field
- Keep the Java property name and use
@JsonProperty("wrapper")
The key rule is:
- JSON key
wrappermust map to a Java property namedwrapper, or - You must explicitly tell Jackson that
studentscorresponds to JSON keywrapper
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 instudents" using@JsonProperty("wrapper")
Jackson is strict by default because it assumes unexpected fields may indicate a bug.
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
- Jackson reads the JSON string.
- It sees a top-level JSON object.
- Inside that object, it finds a property named
wrapper. - It looks at the
Wrapperclass for a matching property. - Because of
@JsonProperty("wrapper"), Jackson knows that JSONwrappermaps to Javastudents. - Jackson sees that
wrappercontains an array. - It checks the Java type of
students, which isList<Student>. - For each object in the array, Jackson creates a
Studentinstance. - It maps:
- JSON
id-> Javaid - JSON
name-> Javaname
- JSON
- The
Wrapperobject is returned with oneStudentin 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, orwrapper - 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.
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:
StudentResponseStudentListResponseApiStudentsResponse
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
| Approach | When to use it | Example | Pros | Cons |
|---|---|---|---|---|
| Rename Java field to match JSON | When you are fine using the API's field name in Java | private List<Student> wrapper; | Simple, no annotation needed | Java code may be less expressive |
Use @JsonProperty | When you want a cleaner Java name | @JsonProperty("wrapper") private List<Student> students; | Clear mapping, readable Java code | Requires annotation |
| Ignore unknown fields | When the JSON has extra fields you do not care about | @JsonIgnoreProperties(ignoreUnknown = true) | Makes code more tolerant | Does not solve wrong field-name mapping |
Parse into JsonNode manually | When JSON is dynamic or irregular | JsonNode root = mapper.readTree(json) | Flexible | More manual code |
@JsonProperty vs renaming the field
- Renaming the field is simplest when the JSON name is acceptable in Java.
@JsonPropertyis better when you want Java code to stay meaningful.
Strongly typed mapping vs manual parsing
| Style | Best for | Tradeoff |
|---|---|---|
| Strongly typed POJOs | Stable API responses | Cleaner and safer |
JsonNode tree parsing | Unpredictable JSON | More flexible but more verbose |
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 propertywrapper - or JSON key
wrapper-> Java propertystudentswith@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.
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.
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.