I read about how Jackson assumes that Java Objects follow JavaBeans convention, and that JSON property names will be based on getter/setter methods (ie if theres a getName, it would look for a name property in JSON string, setName would write the name class field into a JSON string). Why does it not get decided by class variable name?
I looked at the Baeldung tutorials and tried looking for documentation on why or how Jackson works, but none of them explains why. It only shows how to use the annotations or how to resolve specific cases where you might want to read List, HashMap, ignore fields etc.
The tutorial did explain how to make fields serializable/deserializable using getter and setter methods, but when working with Java objects that do not follow JavaBeans convention, how do I determine what gets written into the JSON string? I used the following annotations to read a .json file containing an array of books:
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
public class Book implements Comparable<Book>{
private String title;
private String author;
//match a field in json string to pojo when names dont match
@JsonSetter("isbn-10")
// @JsonProperty("isbn")
// @JsonAlias("isbn-10")
private String isbn;
@JsonCreator
public Book(@JsonProperty("title") String title,@JsonProperty("author")
String author,@JsonProperty("isbn") String isbn) {
this.title = title;
this.author = author;
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
@JsonGetter("isbn")
public String getIsbn() {
return isbn;
}
public int compareTo(Book book) {
return this.getTitle().compareTo(book.getTitle());
}
}
sample json file contents:
[
{
"title":"Day Knight",
"author":"Pun R. Good",
"isbn-10":"830456394-2"
}
]
However if I do not specify the JsonGetter annotation with isbn, i get an error that:
java.lang.IllegalStateException: Conflicting/ambiguous property name definitions (implicit name 'isbn'): found multiple explicit names: [isbn-10, isbn], but also implicit accessor: [method com.fdmgroup.jacksonexercise.Book#getIsbn()][visible=true,ignore=false,explicitName=false]
But if I used the commented out JsonAlias
and JsonProperties
instead of getter and setter annotations, this issue does not happen at all. Why is it forcing me to specify the annotation of getter when the getter is a regular getter that follows convention and not a weird getter name like getTheIsbn()
.
Why does it not read isbn-10
into the class field isbn
using the JsonSetter
, and write out the property based on the variable name along with the value (using JsonGetter
or JsonProperties
if there is a need to further adjust the name)?
CodePudding user response:
However if I do not specify the JsonGetter annotation with isbn, i get an error that:
You've mixed everything together, there's a lot of redundancy.
First of all since you've defined a creator by annotating the constructor with @JsonCreator
Jackson would no longer be interested in setters (they are needed only a no-args constructor is used). Hence, you can get read of @JsonSetter
.
Because you need to specify multiple aliases of isbn
property, @JsonAlias
is the right way to go. These names would be considered only during deserialization from JSON and would have no impact on serialization.
@JsonAlias({"isbn", "isbn-10"})
And since you're happy with the field name isbn
in your POJO, which Jackson would infer from the getter-name getIsbn()
, using @JsonGetter("isbn")
is redundant. It would be useful if you would need to change it, e.g. @JsonGetter("ISBN")
*, or @JsonGetter("isbn-10")
(method name getIsbn-10()
would be illegal in Java).
That said, your class might look like this:
public class Book implements Comparable<Book> {
private String title;
private String author;
@JsonAlias({"isbn", "isbn-10"})
private String isbn;
@JsonCreator
public Book(@JsonProperty("title") String title,
@JsonProperty("author") String author,
@JsonProperty("isbn-10") String isbn) {
this.title = title;
this.author = author;
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
public String getIsbn() {
return isbn;
}
public int compareTo(Book book) {
return this.getTitle().compareTo(book.getTitle());
}
}