deserialize Jackson object in JavaScript containing JsonIdentityInfo

9.6k views Asked by At

hello (sorry for my english)

I'm working on angularjs front end website consuming web service producing json with SPRING MVC. The spring mvc use JsonIdentityInfo option for seralization so each object are writed only one time in the json and each other time a reference is used, example her there is 2 "computer" using the same object "component", so spring put an id to the first component ("@componentID": 2) and for the second component juste the id ( 2 ) :

[
  {
    "@computerID": 1,
    "component": {
      "@componentID": 2,
      "processor": 2,
      "ram": "8g",
      "harddrive": "wd"
    }
  },
  {
    "@computerID": 3,
    "component": 2
  }
]

what i want :

[
  {
    "@computerID": 1,
    "owner" : "Mister B",
    "component": {
      "@componentID": 2,
      "processor": 2,
      "ram": "8g",
      "harddrive": "wd"
    }
  },
  {
    "@computerID": 3,
    "owner" : "Mister A",
    "component": {
      "@componentID": 2,
      "processor": 2,
      "ram": "8g",
      "harddrive": "wd"
    }
  }
]

I make many search for a code who do this but i didn't find anythink.

I can't edit the web service for removing this behavor. Can i edit the json on client side with javascript or jquery (or another librairie) to replace references with the real referenced object ? ( the data are in fact more complex and deeper, i have 3 level of sub object in object).

thanks a lot.

2

There are 2 answers

2
Rodney G On BEST ANSWER

Split all the array members into new arrays: those with a full component attribute (not just a number) and those without. Loop through the remaining original members which should have just numerical component attributes, then look up the corresponding @componentID from the "good" array, and do some copying and moving.

// initialize some vars
var final = [], temp = [], bad = [],
    c = {},
    computers = [
      {
        "@computerID": 1,
        "component": {
          "@componentID": 2,
          "processor": 2,
          "ram": "8g",
          "harddrive": "wd"
        }
      },
      {
        "@computerID": 3,
        "component": 2
      }
    ];

// split original array into 3: final, bad, & temp
while(computers.length > 0) {
    c = computers.pop();
    if (c.hasOwnProperty("component")) {
        if (typeof c.component === "number") {
            temp.push(c);
        } else {
            final.push(c);
        }
    } else {
        bad.push(c);
    }
}

// loop through temp & look up @componentID within final
while (temp.length > 0) {
    c = temp.pop();
    // should @componentID be 1-of-a-kind?
    var found = getObjects(final, "@componentID", c.component);
    if (found.length) {
        c.component = found[0];
        final.push(c);
    } else {
        bad.push(c);
    }
}


// SOURCE: http://stackoverflow.com/a/4992429/1072176
function getObjects(obj, key, val) {
    var objects = [];
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            objects = objects.concat(getObjects(obj[i], key, val));
        } else if (i == key && obj[key] == val) {
            objects.push(obj);
        }
    }
    return objects;
}

// should result in just one or two populated arrays: final and/or bad
alert(JSON.stringify(final));

You'll note I actually made THREE arrays, but only two end up populated: final has your good new objects, and the other one (bad) is a catch-all for objects without a component attribute, or for whose component number a corresponding @componentID cannot be found.

5
Joseph Ninan On

I recently came across an exact scenario that OP has described here. Below was my solution. Use JSOG (Javascript Object Graph) format to solve this.

Server Side Use Jackson-Jsog plugin https://github.com/jsog/jsog-jackson and annotate each class using below annotation.

@JsonIdentityInfo(generator=JSOGGenerator.class)

instead of the

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

this would generate in JSOG format. (@id and @ref)

On the Client Side, use the jsog.js

convert the JSOG structure to the cyclic one using the below call

cyclicGraph = JSOG.decode(jsogStructure);