简体   繁体   中英

Serialize two different POJO object with the same id with Jackson

I have these two classes:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id",scope = Rol.class)
public class Rol extends MyEntity implements Serializable {
    private Integer id;
    private String rolName;

    public Rol(Integer id, String rolName) {
        this.id = id;
        this.rolName = rolName;
    }

    ...
}

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id",scope = User.class)
public class User extends MyEntity implements Serializable {
    private Integer id;
    private String name;
    private List<Rol> rolList;

    public User(Integer id, String name, List<Rol> rolList) {
        this.id = id;
        this.name = name;
        this.rolList = rolList;
    }

    ...
}

and I try to serialize and deserialize the user object as following

Rol rol1 = new Rol(1, "MyRol");
Rol rol2 = new Rol(1, "MyRol");
List<Rol> rolList = new ArrayList();
rolList.add(rol1);
rolList.add(rol2);

user = new User(1, "MyUser", rolList);

ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(user);
User userJson = mappe.readValue(jsonString, User.class);

and the JsonMappingException: Already had POJO for id is produced. Why?

When I review the json result of the serialization I see that the result is

{"id": 1,"name": "MyName","rolList": [{"id": 1,"rolName": "MyRol"},{"id": 1,"rolName": "MyRol"}]}

when the result should be

{"id": 1,"name": "MyName","rolList": [{"id": 1,"rolName": "MyRol"},1]}

because rol1 and rol2 are different instances of the same POJO identifier with id 1.

How can I avoid the JsonMappingException? In my project I have some different instances of the same POJO. I can guarantee that if the id's are equal -> objects are equal.

Excuse me for my bad English.

For anyone returning to this question, it looks like there's option to do this with a custom ObjectIdResolver in Jackson. You can specify this on the @JsonIdentityInfo annotation, eg :

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name", 
    resolver = CustomObjectIdResolver.class)

Then perhaps wrap the normal SimpleObjectIdResolver class to get going and customise bindItem().

In my case I wanted to avoid overlapping objectIds, so cleared down the references when I started a new Something:

    public class CustomObjectIdResolver implements ObjectIdResolver {
        private ObjectIdResolver objectIdResolver;

        public CustomObjectIdResolver() {
            clearReferences();
        }

        @Override
        public void bindItem(IdKey id, Object pojo) {
            // Time to drop the references?
            if (pojo instanceof Something)
                clearReferences();

            objectIdResolver.bindItem(id, pojo);
        }

        @Override
        public Object resolveId(IdKey id) {
            return objectIdResolver.resolveId(id);
        }

        @Override
        public boolean canUseFor(ObjectIdResolver resolverType) {
            return resolverType.getClass() == getClass();
        }

        @Override
        public ObjectIdResolver newForDeserialization(Object context) {
            return new CustomObjectIdResolver();
        }

        private void clearReferences() {
            objectIdResolver = new SimpleObjectIdResolver();
        }
    }

Jackson expects in this case different id for different class instances. There has been a previous discussion at github here . Overriding hashCode and equals will not help. Object references must match for equal id .

Options

  1. Reuse Rol instances instead of making new ones with equal fields. As a bonus you will also save memory.
  2. Modify the application logic so that it doesn't depend on @JsonIdentityInfo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM