Jackson default conversion behavior (java json library spring uses)

So I complain. I think it could be done better but I didn’t do any research as why this is the default behavior of Jackson so you can educate me the whole reason behind this design. Since Jackson is the json library SpringMVC has picked, I’m using it.

By default, Jackson will convert any

  • public method
  • starts with “get”
  • takes no arguments
  • returns a value

from a POJO to json.

Is it not smart enough to figure out how many of those method are actually truly getters? And how many of them may be convenience methods?

Here’s an example:

public class Foo {
	private List<String> messsages = new ArrayList<String>();

	public List<String> getMesssages() {
		return messsages;
	}

	public void setMesssages(List<String> messsages) {
		this.messsages = messsages;
	}
	
	public String getLastMessage() {
		if(getMesssages().isEmpty()) {
			return "";
		} else {
			return getMesssages().get(getMesssages().size()-1);
		}
	}
}
@Test
public void test() throws JsonGenerationException, JsonMappingException, IOException {
	ObjectMapper mapper = new ObjectMapper();
	Foo foo = new Foo();
	String jsonFoo = mapper.writeValueAsString(foo);
	System.out.println(jsonFoo);
	
	Foo convertedFoo = mapper.readValue(jsonFoo, Foo.class);
}

This test fails because

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "lastMessage" (Class net.pureessence.Foo), not marked as ignorable

You have some options to get around this issue of course.

Exclude the convenience method so Jackson will NOT convert it

@JsonIgnoreProperties({
    "lastMessage"
})
public class Foo {
...

or

...
@JsonIgnore
public String getLastMessage() {
...

Pick which properties Jackson should INCLUDE in its conversion

@JsonPropertyOrder({
	"messages"
})
@JsonAutoDetect(value=JsonMethod.FIELD)
public class Foo {
	@JsonProperty private List<String> messsages = new ArrayList<String>();
...

I’m sure there are other options I have not mentioned that you may use to get around the issue.

Either way it requires your close attention and care and most likely tests of your exact json conversion to help you pay attention to how your changes on the POJO will affect your json conversion. I wish the default behavior of Jackson would just convert real properties only. Such as something that have both getters & setters. More here and here.

my github repo for the test

Jackson Ignore Property/Convenience Method

Here’s something I learned about Jackson and you may run into it.

What gets serialized by default?

Properties of an object are initially determined by process called auto-detection: all member methods and fields are checked to find:

  • “Getter” methods: all no-argument public member methods which return a value, and conform to naming convention of “getXxx” (or “isXxx”, if return type is boolean; called “is-getter”) are considered to infer existence of property with name “xxx” (where property name is inferred using bean convention, i.e. the leading capitali letter(s) is changed to lower case
  • field properties: all public member fields are considered to represent properties, using field name as is.

This means Jackson will map any convenience methods you create on the POJO that’s public and starts with “get” and returns a value. This may NOT be the behavior you want.

@JsonIgnoreProperties can be used at a class level and it works for me.

But in order to prevent me from tediously adding all of convenience methods on my POJO to the list, I started to use “return” as the keyword instead of “get” so Jackson will ignore those methods by default. Of course if you want JSTL to be able to show the convenience method output on the screen, the convenience method has to begin with “get”. So I’m using a mix of solutions to this problem.