As a Java developer, I usually trust Jackson to map JSON to Java objects. But recently, I faced a very strange problem. The frontend sent correct JSON with the field "eInvoiceId"
, but in my Spring Boot backend the value in the DTO was always null
.
It felt like being a detective. I followed every step, checked the JSON again and again, and in the end I found the reason: a not-so-obvious naming rule from JavaBeans Introspector.
About the problem
- Frontend JSON:
{
"eInvoiceId": "E-12345"
}
- Java DTO:
private String eInvoiceId;
Looks like a perfect match, right?
But Jackson did not map them correctly.
Why It Happens
Jackson uses JavaBeans Introspector under the hood. This class has its own rules for property names (JDK docs):
- If a name starts with one lowercase letter and the second letter is uppercase (example:
eInvoiceId
), the Introspector treats the first part as an acronym. - That means it changes the property name from
eInvoiceId
→EInvoiceId
.
Result:
- Jackson looks for
"EInvoiceId"
in JSON. - JSON only has
"eInvoiceId"
. - No match → value is
null
.
Even worse: when serializing back to JSON, Jackson produced the wrong key name like "einvoiceId"
. That was the final proof that the issue was in name conversion.
Solutions
1. Local fix with @JsonProperty
The fastest solution is to use @JsonProperty
:
import com.fasterxml.jackson.annotation.JsonProperty;
public class MyDto {
@JsonProperty("eInvoiceId")
private String eInvoiceId;
// getters, setters...
}
This tells Jackson directly:
Always map this field to
"eInvoiceId"
in JSON.
📖 Docs: Jackson @JsonProperty
2. Global fix with MapperFeature.USE_STD_BEAN_NAMING
If the problem appears in many places in the project, a better option is to configure Jackson globally.
In Spring Boot add to application.yml
:
spring:
jackson:
mapper:
use-std-bean-naming: true
Or configure with a bean:
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper()
.configure(MapperFeature.USE_STD_BEAN_NAMING, true);
}
}
📖 Docs:
This makes Jackson always use the exact field names.
Lesson Learned
The "eInvoiceId"
story was a valuable lesson:
- Even simple names can create bugs when libraries use their own naming rules.
- The real problem was JavaBeans Introspector, not a typo or frontend mistake.
- The fix can be simple: either
@JsonProperty
for single fields, or a global Jackson config for the whole project.
Next time when Jackson “magically” ignores your fields, remember this trap.
The solution may be just one annotation or one line in your config.