【问题标题】:springdatarepository ElasticSearch works on save but fails on update with java.lang.StackOverflowError: nullspringdatarepository ElasticSearch 在保存时工作,但在更新时失败 java.lang.StackOverflowError: null
【发布时间】:2021-10-10 20:15:37
【问题描述】:

通过springdataelasticsearch 更新我的数据时,我收到java.lang.StackOverflowError: null。该应用程序是使用Jhipster 7.0.1 生成的。 Spring Boot 版本为2.4.4.。创建新对象时它可以正常工作,但更新会导致错误。这是CountryAdminUnitTypeService.java的相关部分。

     * Save a countryAdminUnitType.
     *
     * @param countryAdminUnitType the entity to save.
     * @return the persisted entity.
     */
    public CountryAdminUnitType save(CountryAdminUnitType countryAdminUnitType) {
        log.debug("Request to save CountryAdminUnitType : {}", countryAdminUnitType);
        CountryAdminUnitType result = countryAdminUnitTypeRepository.save(countryAdminUnitType);
        countryAdminUnitTypeSearchRepository.save(result);
        return result;
    }

创建时,对象在调用countryAdminUntiTypeSearchRepository.save(result); 时的外观如下。

result = {CountryAdminUnitType@23268} "CountryAdminUnitType{id=200102, name='Province'}"
   id = {Long@23292} 200102
   name = "Province"
   parent = null
   country = {Country@23275} "Country{id=183778, name='Turkey', isoCode='TR'}"
    id = {Long@23281} 183778
    name = "Turkey"
    isoCode = "TR"
    countryAdminUnitTypes = null

这是 更新时的样子。

result = {CountryAdminUnitType@24746} "CountryAdminUnitType{id=200102, name='Province'}"
 id = {Long@24752} 200102
 name = "Province"
 parent = null
 country = {Country@24754} "Country{id=183778, name='Turkey', isoCode='TR'}"
  id = {Long@24756} 183778
  name = "Turkey"
  isoCode = "TR"
  countryAdminUnitTypes = {PersistentSet@24761}  size = 1
   0 = {CountryAdminUnitType@24746} "CountryAdminUnitType{id=200102, name='Province'}"
    id = {Long@24752} 200102
    name = "Province"
    parent = null
    country = {Country@24754} "Country{id=183778, name='Turkey', isoCode='TR'}"

我看到的唯一区别是countryAdminUnitTypes 在第二种情况下不为空。但是,这应该由下面 Country.java 中给出的JsonIgnoreProperties 处理。

这是一个很长的日志文件的开头。

ERROR 91444 --- [  XNIO-5 task-1] c.s.c.s.CountryAdminUnitTypeService      : Exception in save() with cause = 'NULL' and exception = 'null'

java.lang.StackOverflowError: null
    at org.springframework.data.util.Streamable.stream(Streamable.java:87)
    at org.springframework.data.util.Streamable.lambda$map$1(Streamable.java:101)
    at org.springframework.data.util.LazyStreamable.stream(LazyStreamable.java:55)
    at org.springframework.data.util.LazyStreamable.iterator(LazyStreamable.java:46)
    at java.base/java.lang.Iterable.forEach(Iterable.java:74)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeCollectionValue(MappingElasticsearchConverter.java:710)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.getWriteComplexValue(MappingElasticsearchConverter.java:620)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeProperty(MappingElasticsearchConverter.java:601)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeProperties(MappingElasticsearchConverter.java:553)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeEntity(MappingElasticsearchConverter.java:511)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeEntity(MappingElasticsearchConverter.java:636)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.getWriteComplexValue(MappingElasticsearchConverter.java:627)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeProperty(MappingElasticsearchConverter.java:601)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeProperties(MappingElasticsearchConverter.java:553)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeEntity(MappingElasticsearchConverter.java:511)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeEntity(MappingElasticsearchConverter.java:636)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.getWriteComplexValue(MappingElasticsearchConverter.java:627)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.lambda$writeCollectionValue$7(MappingElasticsearchConverter.java:709)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1812)
    at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.lambda$initPartialTraversalState$0(StreamSpliterators.java:294)
    at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.fillBuffer(StreamSpliterators.java:206)
    at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.doAdvance(StreamSpliterators.java:161)
    at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.tryAdvance(StreamSpliterators.java:300)
    at java.base/java.util.Spliterators$1Adapter.hasNext(Spliterators.java:681)
    at java.base/java.lang.Iterable.forEach(Iterable.java:74)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeCollectionValue(MappingElasticsearchConverter.java:710)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.getWriteComplexValue(MappingElasticsearchConverter.java:620)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeProperty(MappingElasticsearchConverter.java:601)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeProperties(MappingElasticsearchConverter.java:553)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeEntity(MappingElasticsearchConverter.java:511)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeEntity(MappingElasticsearchConverter.java:636)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.getWriteComplexValue(MappingElasticsearchConverter.java:627)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeProperty(MappingElasticsearchConverter.java:601)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeProperties(MappingElasticsearchConverter.java:553)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeEntity(MappingElasticsearchConverter.java:511)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.writeEntity(MappingElasticsearchConverter.java:636)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.getWriteComplexValue(MappingElasticsearchConverter.java:627)
    at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter.lambda$writeCollectionValue$7(MappingElasticsearchConverter.java:709)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1812)
    at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.lambda$initPartialTraversalState$0(StreamSpliterators.java:294)
    at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.fillBuffer(StreamSpliterators.java:206)
    at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.doAdvance(StreamSpliterators.java:161)
    at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.tryAdvance(StreamSpliterators.java:300)
    at java.base/java.util.Spliterators$1Adapter.hasNext(Spliterators.java:681)
    at java.base/java.lang.Iterable.forEach(Iterable.java:74)

这里是模型类。

CountryAdminUnitType.java

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.io.Serializable;
import javax.persistence.*;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * A CountryAdminUnitType.
 */
@Entity
@Table(name = "country_admin_unit_type")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@org.springframework.data.elasticsearch.annotations.Document(indexName = "countryadminunittype")
public class CountryAdminUnitType implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;

    @Column(name = "name")
    private String name;

    @ManyToOne
    @JsonIgnoreProperties(value = { "parent", "country" }, allowSetters = true)
    private CountryAdminUnitType parent;

    @ManyToOne
    @JsonIgnoreProperties(
        value = { "defaultResidenceMeasurementUnit", "countryAdminUnitTypes", "preferences", "personNationalities" },
        allowSetters = true
    )
    private Country country;

    // jhipster-needle-entity-add-field - JHipster will add fields here
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public CountryAdminUnitType id(Long id) {
        this.id = id;
        return this;
    }

    public String getName() {
        return this.name;
    }

    public CountryAdminUnitType name(String name) {
        this.name = name;
        return this;
    }

    public void setName(String name) {
        this.name = name;
    }

    public CountryAdminUnitType getParent() {
        return this.parent;
    }

    public CountryAdminUnitType parent(CountryAdminUnitType countryAdminUnitType) {
        this.setParent(countryAdminUnitType);
        return this;
    }

    public void setParent(CountryAdminUnitType countryAdminUnitType) {
        this.parent = countryAdminUnitType;
    }

    public Country getCountry() {
        return this.country;
    }

    public CountryAdminUnitType country(Country country) {
        this.setCountry(country);
        return this;
    }

    public void setCountry(Country country) {
        this.country = country;
    }

    // jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof CountryAdminUnitType)) {
            return false;
        }
        return id != null && id.equals(((CountryAdminUnitType) o).id);
    }

    @Override
    public int hashCode() {
        // see https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
        return getClass().hashCode();
    }

    // prettier-ignore
    @Override
    public String toString() {
        return "CountryAdminUnitType{" +
            "id=" + getId() +
            ", name='" + getName() + "'" +
            "}";
    }
}

Country.java

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * A Country.
 */
@Entity
@Table(name = "country")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@org.springframework.data.elasticsearch.annotations.Document(indexName = "country")
public class Country implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "iso_code")
    private String isoCode;

    @OneToMany(mappedBy = "country")
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    @JsonIgnoreProperties(value = { "parent", "country" })
    private Set<CountryAdminUnitType> countryAdminUnitTypes = new HashSet<>();

    // jhipster-needle-entity-add-field - JHipster will add fields here
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Country id(Long id) {
        this.id = id;
        return this;
    }

    public String getName() {
        return this.name;
    }

    public Country name(String name) {
        this.name = name;
        return this;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIsoCode() {
        return this.isoCode;
    }

    public Country isoCode(String isoCode) {
        this.isoCode = isoCode;
        return this;
    }

    public void setIsoCode(String isoCode) {
        this.isoCode = isoCode;
    }

    public Set<CountryAdminUnitType> getCountryAdminUnitTypes() {
        return this.countryAdminUnitTypes;
    }

    public Country countryAdminUnitTypes(Set<CountryAdminUnitType> countryAdminUnitTypes) {
        this.setCountryAdminUnitTypes(countryAdminUnitTypes);
        return this;
    }

    public Country addCountryAdminUnitType(CountryAdminUnitType countryAdminUnitType) {
        this.countryAdminUnitTypes.add(countryAdminUnitType);
        countryAdminUnitType.setCountry(this);
        return this;
    }

    public Country removeCountryAdminUnitType(CountryAdminUnitType countryAdminUnitType) {
        this.countryAdminUnitTypes.remove(countryAdminUnitType);
        countryAdminUnitType.setCountry(null);
        return this;
    }

    public void setCountryAdminUnitTypes(Set<CountryAdminUnitType> countryAdminUnitTypes) {
        if (this.countryAdminUnitTypes != null) {
            this.countryAdminUnitTypes.forEach(i -> i.setCountry(null));
        }
        if (countryAdminUnitTypes != null) {
            countryAdminUnitTypes.forEach(i -> i.setCountry(this));
        }
        this.countryAdminUnitTypes = countryAdminUnitTypes;
    }


    // jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Country)) {
            return false;
        }
        return id != null && id.equals(((Country) o).id);
    }

    @Override
    public int hashCode() {
        // see https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
        return getClass().hashCode();
    }

    // prettier-ignore
    @Override
    public String toString() {
        return "Country{" +
            "id=" + getId() +
            ", name='" + getName() + "'" +
            ", isoCode='" + getIsoCode() + "'" +
            "}";
    }
}

【问题讨论】:

  • 您好,我也遇到了同样的问题,请问您解决了吗?

标签: spring-boot elasticsearch spring-data-jpa jackson jhipster


【解决方案1】:

这是因为 JHipster 如何设置save。它只发生在更新具有双向关系的对象时。

    * Save a countryAdminUnitType.
    *
    * @param countryAdminUnitType the entity to save.
    * @return the persisted entity.
    */
    public CountryAdminUnitType save(CountryAdminUnitType countryAdminUnitType) {
        log.debug("Request to save CountryAdminUnitType : {}", countryAdminUnitType);
        CountryAdminUnitType result = countryAdminUnitTypeRepository.save(countryAdminUnitType);
        countryAdminUnitTypeSearchRepository.save(result);
        return result;
    }

要更新的对象在传递给jpa repository countryAdminUnitTypeRepository.save(countryAdminUnitType); 时设置正确。但是返回的result对象存在循环依赖,直接转发给elasticsearch repository countryAdminUnitTypeSearchRepository.save(result);进行更新。我只使用对象的id 解决了它。

线

CountryAdminUnitType result = countryAdminUnitTypeRepository.save(countryAdminUnitType);
countryAdminUnitTypeSearchRepository.save(result);

已改为

CountryAdminUnitType result = countryAdminUnitTypeRepository.save(countryAdminUnitType);
countryAdminUnitType.setId(result.getId());
countryAdminUnitTypeSearchRepository.save(countryAdminUnitType);
return result;

【讨论】:

  • 很好的解决方案,谢谢。您对如何使用实体中的注释有任何想法吗?我想这是因为对于双向多对一或单对多关系,此时忽略 JsonIgnoreProperties。这个错误实际上破坏了最初生成的使用弹性搜索的 jhipster 应用程序,应该提升到我想的项目的主线程。我自己可能会很快解决这个问题,但也许你已经有了解决方案?问候
  • 这里是官方线程问题的更通用解决方案:github.com/jhipster/generator-jhipster/issues/…
猜你喜欢
  • 2016-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-11
相关资源
最近更新 更多