Как вывести отношение N-M как JSON? [Дубликат]

Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, он будет генерировать исключение NullReferenceException.

Пример:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

Вы можно просто избежать этого, проверив, является ли переменная не нулевой:

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

Чтобы полностью понять, почему выбрано исключение NullReferenceException, важно знать разницу между типами значений и ссылочные типы .

Итак, если вы имеете дело со типами значений, NullReferenceExceptions не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!

Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.

Типы ссылок (эти должны быть проверены):

  • динамический
  • объект
  • string

Типы значений (вы можете просто игнорировать эти):

  • Числовые типы
  • Интегральные типы
  • Типы с плавающей запятой
  • decimal
  • bool
  • Пользовательские структуры

67
задан WSK 27 July 2010 в 04:11
поделиться

12 ответов

Можно ли представить двунаправленную связь в JSON? Некоторые форматы данных не подходят для некоторых типов моделирования данных.

Один метод обработки циклов при работе с обходными графами объектов - следить за тем, какие объекты вы видели до сих пор (используя сопоставления идентичности), чтобы препятствовать прохождению бесконечного цикла.

10
ответ дан matt b 24 August 2018 в 20:10
поделиться
  • 1
    Я сделал то же самое, и он работает, но не уверен, что он будет работать во всех сценариях сопоставления. По крайней мере, на данный момент я хорошо настроен и буду продолжать думать о более элегантной идее – WSK 27 July 2010 в 15:22
  • 2
    Конечно, они могут - для этого просто нет типа или структуры данных. Но все может быть представлено в XML, JSON или большинстве других форматов данных. – StaxMan 29 July 2010 в 07:07
  • 3
    Мне интересно - как вы представляете круговую ссылку в JSON? – matt b 29 July 2010 в 13:05
  • 4
    Несколько способов: имейте в виду, что в целом это не просто JSON, а комбинация JSON и некоторых метаданных, чаще всего определений классов, которые вы используете для привязки к / из JSON. Для JSON это просто вопрос о том, использовать ли какой-либо тип объекта или воссоздать привязку (например, Jackson lib имеет конкретный способ представления связей между родителями и дочерними элементами). – StaxMan 27 September 2010 в 07:25

Если вы используете Javascript, это очень простое решение, использующее параметр replacer метода JSON.stringify(), где вы можете передать функцию, чтобы изменить поведение сериализации по умолчанию.

Вот как вы можете его использовать. Рассмотрим приведенный ниже пример с 4 узлами в циклическом графе.

// node constructor
function Node(key, value) {
    this.name = key;
    this.value = value;
    this.next = null;
}

//create some nodes
var n1 = new Node("A", 1);
var n2 = new Node("B", 2);
var n3 = new Node("C", 3);
var n4 = new Node("D", 4);

// setup some cyclic references
n1.next = n2;
n2.next = n3;
n3.next = n4;
n4.next = n1;

function normalStringify(jsonObject) {
    // this will generate an error when trying to serialize
    // an object with cyclic references
    console.log(JSON.stringify(jsonObject));
}

function cyclicStringify(jsonObject) {
    // this will successfully serialize objects with cyclic
    // references by supplying @name for an object already
    // serialized instead of passing the actual object again,
    // thus breaking the vicious circle :)
    var alreadyVisited = [];
    var serializedData = JSON.stringify(jsonObject, function(key, value) {
        if (typeof value == "object") {
            if (alreadyVisited.indexOf(value.name) >= 0) {
                // do something other that putting the reference, like 
                // putting some name that you can use to build the 
                // reference again later, for eg.
                return "@" + value.name;
            }
            alreadyVisited.push(value.name);
        }
        return value;
    });
    console.log(serializedData);
}

Позже вы можете легко воссоздать фактический объект с циклическими ссылками, проанализировав сериализованные данные и изменив свойство next, чтобы указать на фактический объект, если он использует именованную ссылку с @, как в этом примере.

1
ответ дан abhishekcghosh 24 August 2018 в 20:10
поделиться

ответ номер 8 лучше, я думаю, если вы знаете, какое поле бросает ошибку, вы только устанавливаете значение fild в null и решаете.

List<RequestMessage> requestMessages = lazyLoadPaginated(first, pageSize, sortField, sortOrder, filters, joinWith);
    for (RequestMessage requestMessage : requestMessages) {
        Hibernate.initialize(requestMessage.getService());
        Hibernate.initialize(requestMessage.getService().getGroupService());
        Hibernate.initialize(requestMessage.getRequestMessageProfessionals());
        for (RequestMessageProfessional rmp : requestMessage.getRequestMessageProfessionals()) {
            Hibernate.initialize(rmp.getProfessional());
            rmp.setRequestMessage(null); // **
        }
    }

Чтобы сделать прочитанный код, большой комментарий перемещается из комментария // ** до ниже.

java.lang.StackOverflowError [Ошибка обработки запроса; Вложенное исключение - org.springframework.http.converter.HttpMessageNotWritableException: Не удалось написать JSON: Бесконечная рекурсия (StackOverflowError) (через ссылочную цепочку: com.service.pegazo.bo.RequestMessageProfessional ["requestMessage"] -> com.service.pegazo. bo.RequestMessage ["requestMessageProfessionals"]

-3
ответ дан AdrianHHH 24 August 2018 в 20:10
поделиться
  • 1
    Нет ответа «номер ответа 8», вам лучше указать имя автора ответного ответа. Текст, который вы разместили здесь, не читается, пожалуйста, посмотрите, как публикуются ответы, и старайтесь их аккуратно выложить. Наконец, я не понимаю, как это отвечает на исходный вопрос. Пожалуйста, добавьте более подробную информацию, чтобы объяснить ответ. – AdrianHHH 20 November 2015 в 13:16

Джексон предоставляет аннотацию JsonIdentityInfo для предотвращения циклических ссылок. Вы можете проверить учебник здесь .

0
ответ дан Ankur Mahajan 24 August 2018 в 20:10
поделиться

Я полагаюсь на Google JSON Чтобы справиться с этой проблемой, используйте функцию

Исключение полей из сериализации и десериализации

Предположим двунаправленную связь между классами A и B следующим образом

public class A implements Serializable {

    private B b;

}

И B

public class B implements Serializable {

    private A a;

}

Теперь используйте GsonBuilder. Чтобы получить пользовательский объект Gson следующим образом (метод уведомления setExclusionStrategies)

Gson gson = new GsonBuilder()
    .setExclusionStrategies(new ExclusionStrategy() {

        public boolean shouldSkipClass(Class<?> clazz) {
            return (clazz == B.class);
        }

        /**
          * Custom field exclusion goes here
          */
        public boolean shouldSkipField(FieldAttributes f) {
            return false;
        }

     })
    /**
      * Use serializeNulls method if you want To serialize null values 
      * By default, Gson does not serialize null values
      */
    .serializeNulls()
    .create();

Теперь наша круговая ссылка

A a = new A();
B b = new B();

a.setB(b);
b.setA(a);

String json = gson.toJson(a);
System.out.println(json);

Взгляните на класс GsonBuilder

45
ответ дан Arthur Ronald 24 August 2018 в 20:10
поделиться
  • 1
    Спасибо Артур за ваше любезное предложение, но фактический вопрос - это лучший способ создать так называемый общий «shouldSkipClass». метод. Пока я работал над идеей мата и решил проблему, но все же скептически, в будущем это решение может нарушить сценарии certian. – WSK 27 July 2010 в 15:26
  • 2
    Это "решает" круговые ссылки, удаляя их. Невозможно восстановить исходную структуру данных из сгенерированного JSON. – Sotirios Delimanolis 17 February 2015 в 21:45

Если вы используете Jackon для сериализации, просто примените @JsonBackReference к вашему двунаправленному отображению. Он решает проблему с круговой ссылкой.

Примечание: @JsonBackReference используется для решения бесконечной рекурсии (StackOverflowError)

3
ответ дан CinCout 24 August 2018 в 20:10
поделиться
  • 1
    @JsonIgnore сделал мой JpaRepository неспособным отобразить свойство, но @JsonBackReference решил круговую ссылку и все еще допускал правильное отображение для проблемного атрибута – Bramastic 15 August 2017 в 23:54

Эта ошибка может быть добавлена, когда у вас есть два объекта:

class object1{
    private object2 o2;
}

class object2{
    private object1 o1;
}

С использованием GSon для сериализации я получил эту ошибку:

java.lang.IllegalStateException: circular reference error

Offending field: o1

Чтобы решить эту проблему, просто добавление ключевого слова transient:

class object1{
    private object2 o2;
}

class object2{
    transient private object1 o1;
}

Как вы можете видеть здесь: Почему Java имеет переходные поля?

Ключевое слово переходного процесса в Java используется для указания того, что поле не должно быть сериализовано.

0
ответ дан Community 24 August 2018 в 20:10
поделиться

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

  1. Создать класс аннотации, который будет использоваться в полях, d like excluded
  2. Определить класс, который реализует интерфейс ExclusionStrategy от Google
  3. . Создайте простой метод для создания объекта GSON с использованием GsonBuilder (аналогично объяснению Артура)
  4. Аннотировать поля, которые необходимо исключить по мере необходимости
  5. Применить правила сериализации к вашему объекту com.google.gson.Gson
  6. Сериализовать свой объект

Вот код:

1)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface GsonExclude {

}

2)

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

public class GsonExclusionStrategy implements ExclusionStrategy{

    private final Class<?> typeToExclude;

    public GsonExclusionStrategy(Class<?> clazz){
        this.typeToExclude = clazz;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return ( this.typeToExclude != null && this.typeToExclude == clazz )
                    || clazz.getAnnotation(GsonExclude.class) != null;
    }

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(GsonExclude.class) != null;
    }

}

3)

static Gson createGsonFromBuilder( ExclusionStrategy exs ){
    GsonBuilder gsonbuilder = new GsonBuilder();
    gsonbuilder.setExclusionStrategies(exs);
    return gsonbuilder.serializeNulls().create();
}

4)

public class MyObjectToBeSerialized implements Serializable{

    private static final long serialVersionID = 123L;

    Integer serializeThis;
    String serializeThisToo;
    Date optionalSerialize;

    @GsonExclude
    @ManyToOne(fetch=FetchType.LAZY, optional=false)
    @JoinColumn(name="refobj_id", insertable=false, updatable=false, nullable=false)
    private MyObjectThatGetsCircular dontSerializeMe;

    ...GETTERS AND SETTERS...
}

5)

В первом случае null передается конструктору, вы можете указать другой класс, который должен быть исключен, - обе опции добавляются ниже

Gson gsonObj = createGsonFromBuilder( new GsonExclusionStrategy(null) );
Gson _gsonObj = createGsonFromBuilder( new GsonExclusionStrategy(Date.class) );

6)

MyObjectToBeSerialized _myobject = someMethodThatGetsMyObject();
String jsonRepresentation = gsonObj.toJson(_myobject);

или, чтобы исключить объект Date

String jsonRepresentation = _gsonObj.toJson(_myobject);
12
ответ дан eugene 24 August 2018 в 20:10
поделиться
  • 1
    это предотвращает обработку дочернего объекта, можно включить дочерний json, а затем остановить цикличность – ir2pid 11 June 2014 в 13:51

Используется решение, аналогичное Arthur, но вместо setExclusionStrategies я использовал

Gson gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();

и использовал аннотацию @Expose gson для полей, которые мне нужны в json, другие поля исключены.

2
ответ дан gndp 24 August 2018 в 20:10
поделиться
  • 1
    Спасибо приятель. Это сработало для меня. После долгого исследования я наконец нашел способ избавиться от этой ошибки. – kepy97 5 March 2018 в 16:33

Например, ProductBean имеет serialBean. Отображение будет двунаправленным. Если мы теперь попытаемся использовать gson.toJson(), это закончится круговой ссылкой. Чтобы избежать этой проблемы, вы можете выполнить следующие действия:

  1. Получить результаты из источника данных.
  2. Итерировать список и убедиться, что serialBean не равен null, а затем
  3. Установите productBean.serialBean.productBean = null;
  4. Затем попробуйте использовать gson.toJson();

. Это должно решить проблему

-11
ответ дан KenHBS 24 August 2018 в 20:10
поделиться

Вот как я, наконец, решил это в моем случае. Это работает, по меньшей мере, с Gson & amp; Джексон.

private static final Gson gson = buildGson();

private static Gson buildGson() {
    return new GsonBuilder().addSerializationExclusionStrategy( getExclusionStrategy() ).create();  
}

private static ExclusionStrategy getExclusionStrategy() {
    ExclusionStrategy exlStrategy = new ExclusionStrategy() {
        @Override
        public boolean shouldSkipField(FieldAttributes fas) {
            return ( null != fas.getAnnotation(ManyToOne.class) );
        }
        @Override
        public boolean shouldSkipClass(Class<?> classO) {
            return ( null != classO.getAnnotation(ManyToOne.class) );
        }
    };
    return exlStrategy;
} 
1
ответ дан pirho 24 August 2018 в 20:10
поделиться

Jackson 1.6 (выпущен в сентябре 2010 г.) имеет определенную поддержку на основе аннотаций для обработки такой привязки parent / child, см. http://wiki.fasterxml.com/JacksonFeatureBiDirReferences , ( Удаленный снимок )

Вы, конечно, уже можете исключить сериализацию родительской ссылки, уже использующую большинство пакетов обработки JSON (по крайней мере, поддержка по умолчанию jsonon, gson и flex-json), но реальный трюк заключается в том, как десериализовать его обратно (воссоздать родительскую ссылку), а не просто обрабатывать сериализацию.

EDIT (апрель 2012): Jackson 2.0 теперь поддерживает истинные ссылки на идентификаторы ( Wayback Snapshot ), поэтому вы также можете решить эту проблему.

33
ответ дан SMUsamaShah 24 August 2018 в 20:10
поделиться
  • 1
    Ссылка не работает. – LOLKFC 18 May 2014 в 18:13
  • 2
    как заставить это работать, когда вы не всегда одинаковы. Я попытался поместить оба аннотации на оба поля, но это не сработало: Class A {@JsonBackReference (& quot; abc & quot;) @JsonManagedReference (& quot; xyz & quot; ;) частный B b; } Класс B {@JsonManagedReference («abc») @JsonBackReference («xyz») частный A a; } – azi 15 December 2014 в 14:32
  • 3
    Как указано выше, Object Id (@JsonIdentityInfo) - это способ заставить общие ссылки работать. Для управляемых / обратных ссылок требуются определенные указания, поэтому они не будут работать для вашего дела. – StaxMan 15 December 2014 в 18:27
Другие вопросы по тегам:

Похожие вопросы: