Gson.toJson() выбрасывает StackOverflowError в сервлете
У меня есть список объектов клиентов
List<Client> clientsList=new ArrayList<Client>();
clientsList=clientDao.GetAllClients();
Клиент Entity имеет другие списки в качестве атрибутов:
@ManyToOne(optional=false)
private User createdBy;
@ManyToMany(mappedBy = "Clients")
private Set<ClientType> Types=new HashSet();
@ManyToOne(optional=false)
private LeadSource id_LeadSource;
@ManyToOne(optional=false)
private Agencie id_Agencie;
@OneToMany(cascade=CascadeType.ALL,mappedBy="Owner")
private Set<Propertie> properties=new HashSet();
@OneToMany(cascade=CascadeType.ALL,mappedBy="buyer")
private Set<Sale> sales=new HashSet();
@OneToMany(cascade=CascadeType.ALL,mappedBy = "client")
private Set<Rent> Rents=new HashSet();
@OneToMany(cascade=CascadeType.ALL,mappedBy = "clientDoc")
private Set<Document> Docuements=new HashSet();
и когда я пытаюсь преобразовать список клиентов в формат json
out.write(new Gson().toJson(clientsList));
Я получаю эту ошибку:
java.lang.StackOverflowError
at com.google.gson.stream.JsonWriter.beforeName(JsonWriter.java:603)
at com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:401)
at com.google.gson.stream.JsonWriter.value(JsonWriter.java:512)
at com.google.gson.internal.bind.TypeAdapters$8.write(TypeAdapters.java:270)
at com.google.gson.internal.bind.TypeAdapters$8.write(TypeAdapters.java:255)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:113)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:240)
Ответы
Ответ 1
Это потому, что ваши объекты имеют двунаправленные соединения. Так, например, Client
имеет набор Rent
, и каждая рента имеет ссылку на Client
. Когда вы пытаетесь выполнить сериализацию Client
, вы сериализуете его Rents
, а затем вы должны сериализовать каждый Client
в Rent
и так далее. Вот что вызывает StackOverflowError
.
Чтобы решить эту проблему, вам нужно будет пометить некоторые свойства как transient
(или использовать некоторую аналогичную анотацию), например использовать transient Client
в Rent
. Тогда любая marshalling lib просто проигнорирует это свойство.
В случае Gson вы можете сделать другой способ пометить это поле: сделать хотите включить в json с помощью @Expose
и создать объект gson с помощью
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
P.S. Кроме того, я хотел бы упомянуть, что преобразование вашего объекта JPA в json и отправка его где-то, как правило, не очень хорошая идея. Я бы рекомендовал создать класс DTO (Data Transfer Object), в котором вы включаете только необходимую информацию и в идеале используете только простые типы, такие как int
, Date
, String
и т.д. Если у вас есть вопросы об этом подходе, вы можете google для DTO
, Data Transfer Object
или по этой ссылке: https://www.tutorialspoint.com/design_pattern/transfer_object_pattern.htm