Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, он будет генерировать исключение 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 не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!
Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.
Типы ссылок (эти должны быть проверены):
Типы значений (вы можете просто игнорировать эти):
Можно ли представить двунаправленную связь в JSON? Некоторые форматы данных не подходят для некоторых типов моделирования данных.
Один метод обработки циклов при работе с обходными графами объектов - следить за тем, какие объекты вы видели до сих пор (используя сопоставления идентичности), чтобы препятствовать прохождению бесконечного цикла.
Если вы используете 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
, чтобы указать на фактический объект, если он использует именованную ссылку с @
, как в этом примере.
ответ номер 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"]
blockquote>
Джексон предоставляет аннотацию JsonIdentityInfo
для предотвращения циклических ссылок. Вы можете проверить учебник здесь .
Я полагаюсь на 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
Если вы используете Jackon для сериализации, просто примените @JsonBackReference к вашему двунаправленному отображению. Он решает проблему с круговой ссылкой.
Примечание: @JsonBackReference используется для решения бесконечной рекурсии (StackOverflowError)
@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 используется для указания того, что поле не должно быть сериализовано.
blockquote>
При решении этой проблемы я применил следующий подход (стандартизацию процесса в моем приложении, очищение кода и повторное использование):
Вот код:
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);
Используется решение, аналогичное Arthur, но вместо setExclusionStrategies
я использовал
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
и использовал аннотацию @Expose
gson для полей, которые мне нужны в json, другие поля исключены.
Например, ProductBean имеет serialBean. Отображение будет двунаправленным. Если мы теперь попытаемся использовать gson.toJson()
, это закончится круговой ссылкой. Чтобы избежать этой проблемы, вы можете выполнить следующие действия:
productBean.serialBean.productBean = null;
gson.toJson();
. Это должно решить проблему
Вот как я, наконец, решил это в моем случае. Это работает, по меньшей мере, с 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;
}
Jackson 1.6 (выпущен в сентябре 2010 г.) имеет определенную поддержку на основе аннотаций для обработки такой привязки parent / child, см. http://wiki.fasterxml.com/JacksonFeatureBiDirReferences , ( Удаленный снимок )
Вы, конечно, уже можете исключить сериализацию родительской ссылки, уже использующую большинство пакетов обработки JSON (по крайней мере, поддержка по умолчанию jsonon, gson и flex-json), но реальный трюк заключается в том, как десериализовать его обратно (воссоздать родительскую ссылку), а не просто обрабатывать сериализацию.
EDIT (апрель 2012): Jackson 2.0 теперь поддерживает истинные ссылки на идентификаторы ( Wayback Snapshot ), поэтому вы также можете решить эту проблему.