Jackson with Spring MVC duplicate nested objects not deserializing
jackson, java, json, rest, spring-mvc
Solution
This is how jackson designed JsonIdentityInfo annotation logic.
* Annotation used for indicating that values of annotated type
* or property should be serializing so that instances either
* contain additional object identifier (in addition actual object
* properties), or as a reference that consists of an object id
* that refers to a full serialization. In practice this is done
* by serializing the first instance as full object and object
* identity, and other references to the object as reference values.
Jackson will run the full serialization first time and only id will be serialized when it find that object second time.
So, there is two ways how you can fix it:
1) you can simple remove the @JsonIdentityInfo annotation and Jackson will serialize object as you expected but it will remove the @id field from the response. This is probably fine because you still will have 'id' property.
2) I feel like you can simply restructure your objects and delete some references. I would say it is good to do these changes anyway. First of all you can delete reference to the State from UserLocation. I would say that it is not necessary to have the State in userLocation class because of the State is attached to the City. By doing this you will access State from the City and your problem is solved. Also I would delete the reference to the list of userLocations from the City class as well as from State class.
It will look like:
UserLocation has City and doesn't have State.
City has State and doesn't have userLocations
State doesn't have userLocations as well as cities.
Hope this helps
Problem
I am trying to Convert following POJO to a JSON in `@RestController`: ``` @Entity @Table(name="user_location") @NamedQuery(name="UserLocation.findAll", query="SELECT u FROM UserLocation u") public class UserLocation implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int id; private String addr1; private String addr2; private String landmark; private BigDecimal lat; private BigDecimal lng; private String zipcode; //bi-directional many-to-one association to City @ManyToOne private City city; //bi-directional many-to-one association to State @ManyToOne private State state; public UserLocation() { } //Getter - Setters } ``` Nested City.java is as follow: ``` @Entity @NamedQuery(name="City.findAll", query="SELECT c FROM City c") @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property="@id", scope = City.class) public class City implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int id; private String name; //bi-directional many-to-one association to State @ManyToOne @JsonIgnore private State state; //bi-directional many-to-one association to UserLocation @OneToMany(mappedBy="city") @JsonIgnore private List<UserLocation> userLocations; public City() { } public int getId() { return this.id; } public void setId(int id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } @JsonProperty("state") public State getState() { return this.state; } public void setState(State state) { this.state = state; } public List<UserLocation> getUserLocations() { return this.userLocations; } public void setUserLocations(List<UserLocation> userLocations) { this.userLocations = userLocations; } public UserLocation addUserLocation(UserLocation userLocation) { getUserLocations().add(userLocation); userLocation.setCity(this); return userLocation; } public UserLocation removeUserLocation(UserLocation userLocation) { getUserLocations().remove(userLocation); userLocation.setCity(null); return userLocation; } } ``` Another nested class State.java is as follow: ``` @Entity @NamedQuery(name="State.findAll", query="SELECT s FROM State s") @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property="@id", scope = State.class) public class State implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int id; private String name; //bi-directional many-to-one association to City @OneToMany(mappedBy="state") @JsonIgnore private List<City> cities; //bi-directional many-to-one association to UserLocation @OneToMany(mappedBy="state") @JsonIgnore private List<UserLocation> userLocations; public State() { } public int getId() { return this.id; } public void setId(int id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public List<City> getCities() { return this.cities; } public void setCities(List<City> cities) { this.cities = cities; } public City addCity(City city) { getCities().add(city); city.setState(this); return city; } public City removeCity(City city) { getCities().remove(city); city.setState(null); return city; } public List<UserLocation> getUserLocations() { return this.userLocations; } public void setUserLocations(List<UserLocation> userLocations) { this.userLocations = userLocations; } public UserLocation addUserLocation(UserLocation userLocation) { getUserLocations().add(userLocation); userLocation.setState(this); return userLocation; } public UserLocation removeUserLocation(UserLocation userLocation) { getUserLocations().remove(userLocation); userLocation.setState(null); return userLocation; } } ``` The JSON converted from UserLocation.java is as follow: ``` { id: 1, addr1: "11905 Technology", addr2: "Eden Prairie", landmark: null, lat: null, lng: null, zipcode: "55344", city: { @id: 1, id: 2, name: "Westborough", state: { @id: 1, id: 2, name: "MA" } }, state: 1 } ``` As you can see, the `State` object is coming as a whole object inside `city`. But outer `state` (property of 'UserLocation`is showing just an id of`State`object. I need to have a same`state`object as that of`city` instead of just id. I am relatively new to JackSon api. Please advice which approach I should follow to achieve this requirement. Thanks