Десериализовать объект Джексона в JavaScript, содержащий JsonIdentityInfo

привет (извините за мой английский)

Я работаю над веб-сайтом angularjs, использующим веб-сервис, создающий json с помощью SPRING MVC. SPRING mvc использует параметр JsonIdentityInfo для серализации, поэтому каждый объект нажимается только один раз в json и каждый раз, когда используется ссылка, например, у нее есть 2 "компьютера" с использованием одного и того же объекта "компонент", поэтому SPRING поместите идентификатор в первый компонент ( "@componentID": 2), а для второго компонента juste id (2):

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

что я хочу:

[
  {
    "@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"
    }
  }
]

Я делаю много поиска кода, который это делает, но я не нашел anythink.

Я не могу отредактировать веб-службу, чтобы удалить это поведение. Могу ли я изменить json на стороне клиента с помощью javascript или jquery (или другого librairie), чтобы заменить ссылки на реальный ссылочный объект? (данные на самом деле более сложны и глубже, у меня есть 3 уровня субобъекта в объекте).

Большое спасибо.

Ответ 1

Разделите все элементы массива на новые массивы: те, у которых полный атрибут component (а не только число), и те, у кого нет. Прокрутите оставшиеся исходные элементы, которые должны иметь только числовые атрибуты component, затем найдите соответствующий @componentID из "хорошего" массива и сделайте некоторое копирование и перемещение.

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

Вы заметите, что я на самом деле сделал три массива, но только два в конечном итоге заселены: final имеет ваши хорошие новые объекты, а другой (bad) является объектом catch-all для объектов без атрибута компонента, или для номера компонента которого соответствующий @componentID не может быть найден.

Ответ 2

Недавно я натолкнулся на точный сценарий, описанный OP. Ниже было мое решение. Используйте JSOG (Javascript Object Graph) для решения этой проблемы.

Серверная сторона Использовать плагин Jackson-Jsog https://github.com/jsog/jsog-jackson и аннотировать каждый класс, используя нижеследующую аннотацию.

@JsonIdentityInfo(generator=JSOGGenerator.class)

вместо

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

это будет генерироваться в формате JSOG. (@id и @ref)

На стороне клиента используйте jsog.js

преобразует структуру JSOG в циклическую, используя следующий вызов

cyclicGraph = JSOG.decode(jsogStructure);