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.

7
  • Did you try my solution yet? Here is the code from my answer in a Fiddle: jsfiddle.net/rodgolpe/5e7Vn/2 Commented Jun 13, 2014 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 : 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. Commented Jun 16, 2014 at 9: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! Commented Jun 17, 2014 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. Commented Jun 17, 2014 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. Commented Jun 17, 2014 at 16:52

2 Answers 2

32

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

Sign up to request clarification or add additional context in comments.

5 Comments

JSOG is really cool. But AFAIK deserialization still does not work (?) due to the way jackson deserializer works...
simple, smoothly integrated on both Spring server side (via Maven) and AngularJS client side(via bower)!
Yep, deserialization is still an issue... serialization works beautifully.
This works beautifully. I apply the JsonIdentityInfo annotation only for serialization with a mixin.
Seems like the deserializer should now work, but when is the appropriate time to serialize/deserialize in the client? For example if I want to get object from server, modify it, then POST that object back to server. When should client serialize/deserialize?
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.

2 Comments

I see this is the straight forward solution. Still it is stupid to add 200 Lines of code for reach single endpoint.
Ha, @SimonFakir -- excluding the sample component data, I count 48 lines. And 14 of THAT is the getObjects() utility.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.