Deserialize Json Array that contin 2 objects with the same ID - JsonMappingException: Already had PO

4,891 views
Skip to first unread message

Luis Vargas

unread,
Jul 17, 2013, 4:28:50 PM7/17/13
to jackso...@googlegroups.com
How can I deserialize an Array with two objects that contains the same SubObject with the same Id?

For example this is the JSON of the array

[
    {
        "@id": 98,
        "age": 29,
        "name": "mkyong",
        "relatedPackage": {"@id":99, "receivedOn":1374012807237 }
    },
    {
        "@id": 101,
        "age": 25,
        "name": "luis",
        "relatedPackage": {"@id":99, "receivedOn":1374012807237 }
    }
]

As you can see both objects has the same related package. I want that the deserializer only parse the first relatedPackage and use it for the secon relatedPackage.

My Pojos are the next:

User Class:

package com.mkyong.core;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class,property="@id")
public class User {

    public int age;
    public String name;
    public RelatedPackage relatedPackage;

    //getter and setter methods

    @Override
    public String toString() {
        return "User [age=" + age + ", name=" + name + ", " +
                "messages=" + relatedPackage + "]";
    }
}

RelatedPackage Class:

package com.mkyong.core;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class,property="@id")
public class RelatedPackage {
    public long receivedOn;

    public String toString() {
        return "{ receivedOn: " + receivedOn + " }";
    }
}

And finaly the main Object wich realize the deserializtion:

package com.mkyong.core;

import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;


public class JacksonExample {
    public static void main(String[] args) {

    ObjectMapper mapper = new ObjectMapper();

    try {

        // read from file, convert it to user class
        File file = new File("/home/lvargas/user.json");
        User[] userList = mapper.readValue(file, User[].class);

        // display to console
        System.out.println(userList);

    } catch (JsonGenerationException e) {

        e.printStackTrace();

    } catch (JsonMappingException e) {

        e.printStackTrace();

    } catch (IOException e) {

        e.printStackTrace();

    }

  }

}

When both relatedPackage has the same Id it sends me the next error message

com.fasterxml.jackson.databind.JsonMappingException: Already had POJO for id (java.lang.Integer) [99] (through reference chain: com.mkyong.core.User["relatedPackage"]->com.mkyong.core.RelatedPackage["@id"])
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:232)
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:197)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1332)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:252)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:115)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:449)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:107)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:250)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:115)
    at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:151)
    at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:18)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1988)
    at com.mkyong.core.JacksonExample.main(JacksonExample.java:20)
Caused by: java.lang.IllegalStateException: Already had POJO for id (java.lang.Integer) [99]
    at com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.bindItem(ReadableObjectId.java:27)
    at com.fasterxml.jackson.databind.deser.impl.ObjectIdValueProperty.deserializeSetAndReturn(ObjectIdValueProperty.java:91)
    at com.fasterxml.jackson.databind.deser.impl.ObjectIdValueProperty.deserializeAndSet(ObjectIdValueProperty.java:80)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:250)
    ... 10 more

I understand that it is trying to create a second object with the same objectId.

How can I solve that problem?

Luis Vargas

unread,
Jul 18, 2013, 7:01:20 PM7/18/13
to jackso...@googlegroups.com
There are 2 solutions for this problem:

The first one is simply change the second related package for the respective ID number ie.

[
    {
        "@id": 98,
        "age": 29,
        "name": "mkyong",
        "relatedPackage": {"@id":99, "receivedOn":1374012807237 }
    },
    {
        "@id": 101,
        "age": 25,
        "name": "luis",
        "relatedPackage": 99
    }
]

The second solution is create a custom deserializer.

Guru raj

unread,
Oct 1, 2013, 12:56:34 PM10/1/13
to jackso...@googlegroups.com
I have also faced the same issue. Resolved it using the scope element in JsonIdentityInfo. The javadoc for the scope element is as below.

Scope is used to define applicability of an Object Id: all ids must be unique within their scope; where scope is defined as combination of this value and generator type. Comparison is simple equivalence, meaning that both type generator type and scope class must be the same.
Scope is used for determining how many generators are needed; more than one scope is typically only needed if external Object Ids have overlapping value domains (i.e. are only unique within some limited scope.

So, in the above case, restrict the scope of User and RelatedPackage to be within the same classes.
ie.
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class,property="@id", scope = User.class)
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class,property="@id", scope = RelatedPackage.class)
Reply all
Reply to author
Forward
Message has been deleted
Message has been deleted
0 new messages