10

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.

AlainIb
  • 4,544
  • 4
  • 38
  • 64
  • Did you try my solution yet? Here is the code from my answer in a Fiddle: http://jsfiddle.net/rodgolpe/5e7Vn/2/ – Rodney G Jun 13 '14 at 20:22
  • [EDIT] hello. thanks very much for the help. i try it and works for the first example ;) but i'm trying to adapt your solution for my real use case. I got more complexe data like this : http://pastebin.com/Jk2eNbLK I referenced object can be specimen,mediasSet,determinations,taxon,recolte,localisation,stratigraphie. I try to compare the name of current object with the previous list and if it's a reference i use getObjects to return the good content and then replace the reference by the good content. – AlainIb Jun 16 '14 at 09:11
  • -1 for posting the wrong sample data, allowing me to solve that elegantly, and continue working with you to a resolution, and then giving me no points! – Rodney G Jun 17 '14 at 14:46
  • You're right that i should post the good data in first time, sorry for that. Thank you for all your time. I don't know how points work. – AlainIb Jun 17 '14 at 14:56
  • If my answer solves your original question, you mark my answer as "ACCEPTED" and I will get points for it. MORE IMPORTANTLY, other people trying to solve a similar problem will see that it has been ANSWERED already and might find my answer (and our discussion) useful. – Rodney G Jun 17 '14 at 16:52
  • Cannot believe, that this is not solved yet.. – Simon Fakir Sep 06 '16 at 09:58
  • you say that ? there is one accepted answer and another more recent one with many +1 – AlainIb Sep 06 '16 at 17:58

2 Answers2

31

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);

Praveen Gowda I V
  • 9,569
  • 4
  • 41
  • 49
Joseph Ninan
  • 311
  • 2
  • 2
2

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.

Rodney G
  • 4,746
  • 1
  • 16
  • 15
  • I see this is the straight forward solution. Still it is stupid to add 200 Lines of code for reach single endpoint. – Simon Fakir Sep 06 '16 at 10:00
  • Ha, @SimonFakir -- excluding the sample `component` data, I count 48 lines. And 14 of THAT is the `getObjects()` utility. – Rodney G Sep 14 '16 at 13:53