Ошибка Spring Data & mongodb Converter: java.lang.StackOverflowError

Я использую данные Spring для подключения к mongodb. Пожалуйста, смотрите мои проблемы ниже:

Теперь у меня есть две модели данных (пользовательская и черновая):

@Document

public class User implements Serializable {
@Id
private String id;
private String showName;
private String password;
//..... (other attributes)

@DBRef
private List<Draft> createdDraft = new ArrayList<Draft>();

//constructors
public User() {
super();
}

public User(String id, String showName, String password, //....other attributes
List<Draft> createdDraft) {
super();
this.id = id;
this.showName = showName;
this.password = password;
//....
}

//getters and setters
}

а также

@Document

public class Draft {
@Id
private String id;
private String title;
private Date createTime;
private Date lastEditTime;
@DBRef
private User lastEditor;
@DBRef
private User mainAuthor;
@DBRef
private List<User> coAuthors = new ArrayList<User>();
private String externalURL;

//constructors..
public Draft() {
super();
}

public Draft(String id, String title, Date createTime, Date lastEditTime,
User lastEditor, User mainAuthor, String externalURL) {
super();
this.id = id;
this.title = title;
this.createTime = createTime;
this.lastEditTime = lastEditTime;
this.lastEditor = lastEditor;
this.mainAuthor = mainAuthor;
this.externalURL = externalURL;
}

//getters and setters...

}

В моем проекте я успешно создал пользователя, поэтому я хотел бы добавить черновик к существующему пользователю.

public String CreateNewDraft(User mainAuthor)
{
Draft draft = new Draft();

draft.setMainAuthor(mainAuthor); 

Date now = new Date(System.currentTimeMillis());
 
draft.setCreateTime(now);

mainAuthor.getCreatedDraft().add(draft); 

//insert the draft --> Successful (1)

mongoOps.insert(draft);

//update the user --> Successful (2)

mongoOps.save(mainAuthor);

//find the last inserted draft. --> Errors.

Draft d = mongoOps.findOne(query(where("createTime").is(now) ), Draft.class);

return d.getId()
}

В (1) я нашел новый проект документа, созданный в mongoDB, который имеет _id = 52a1591597d738f7b397be96.

В (2) я обнаружил, что в существующем документе пользователя (mainAuhtor) в поле createdDraft добавлена ​​одна запись, например [ { $ref : draft , $id : { $oid : 52a1591597d738f7b397be96}}]

Исключение и журнал:

processing failed; nested exception is java.lang.StackOverflowError

org.springframework.web.servlet.DispatcherServlet.
doDispatch(DispatcherServlet.java:972)
org.springframework.web.servlet.DispatcherServlet.
doService(DispatcherServlet.java:852)
org.springframework.web.servlet.FrameworkServlet.p
rocessRequest(FrameworkServlet.java:882)
org.springframework.web.servlet.FrameworkServlet.d
oGet(FrameworkServlet.java:778)
javax.servlet.http.HttpServlet.service(HttpServlet .java:621)
javax.servlet.http.HttpServlet.service(HttpServlet .java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilt
er(WsFilter.java:51)

основная причина

java.lang.StackOverflowError 

java.net.SocketInputStream.socketRead0(Native Method)
java.net.SocketInputStream.read(Unknown Source)
java.net.SocketInputStream.read(Unknown Source)
java.io.BufferedInputStream.fill(Unknown Source)
java.io.BufferedInputStream.read1(Unknown Source)
java.io.BufferedInputStream.read(Unknown Source)
org.bson.io.Bits.readFully(Bits.java:46)
org.bson.io.Bits.readFully(Bits.java:33)
org.bson.io.Bits.readFully(Bits.java:28)
com.mongodb.Response.<init>(Response.java:40)
com.mongodb.DBPort.go(DBPort.java:124)
com.mongodb.DBPort.call(DBPort.java:74)
com.mongodb.DBTCPConnector.innerCall(DBTCPConnecto r.java:286)
com.mongodb.DBTCPConnector.call(DBTCPConnector.jav a:257)
com.mongodb.DBApiLayer$MyCollection.__find(DBApiLa yer.java:310)
com.mongodb.DBApiLayer$MyCollection.__find(DBApiLa yer.java:295)
com.mongodb.DBCollection.findOne(DBCollection.java :346)
com.mongodb.DBCollection.findOne(DBCollection.java :331)
com.mongodb.DBRefBase.fetch(DBRefBase.java:53)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter.readValue(MappingMongoConverter. java:1046)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter.access$100(MappingMongoConverter .java:77)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter$MongoDbPropertyValueProvider.get
PropertyValue(MappingMongoConverter.java:999)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter.getValueInternal(MappingMongoCon verter.java:755)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter$2.doWithAssociation(MappingMongo Converter.java:265)
org.springframework.data.mapping.model.BasicPersis
tentEntity.doWithAssociations(BasicPersistentEntit y.java:269)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter.read(MappingMongoConverter.java: 262)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter.read(MappingMongoConverter.java: 223)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter.readCollectionOrArray(MappingMon
goConverter.java:788)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter.readValue(MappingMongoConverter. java:1048)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter.access$100(MappingMongoConverter .java:77)
org.springframework.data.mongodb.core.convert.Mapp
ingMongoConverter$MongoDbPropertyValueProvider.get
PropertyValue(MappingMon```

Может ли кто-нибудь помочь мне взглянуть? Большое спасибо!


person user3076701    schedule 07.12.2013    source источник


Ответы (2)


Это ошибка (или ожидаемое поведение?) Spring data mongodb (я получаю это в версии 1.3.x, не пробовал 1.4.x).

Проблема в том, что User ссылается на Draft и Draft на один и тот же экземпляр пользователя, поэтому конвертер попадает в бесконечный цикл.

@Document
public class User implements Serializable {
...

@DBRef
private List<Draft> createdDraft = new ArrayList<Draft>();

а также

@Document
public class Draft {
...

@DBRef
private User lastEditor;
@DBRef
private User mainAuthor;
@DBRef
private List<User> coAuthors = new ArrayList<User>();

Вероятно, вам следует использовать простые ссылки на идентификаторы, а не DBRef (это даже предлагается здесь http://docs.mongodb.org/manual/reference/database-references/ как подходящий для большинства случаев использования)

Если вы обнаружите, что часто используете DBRef, вам следует подумать об использовании базы данных другого типа, например. графическая база данных.

person František Hartman    schedule 08.12.2013

вы должны сопоставить полученный объект (документ) из базы данных mongo..

используйте Springs Интерфейс конвертера

например:

public class ProfileReadConverter implements Converter<DBObject, Profile> {
@Override
public Profile convert(DBObject source) {
    @SuppressWarnings("unchecked")
    Profile p = new Profile((ObjectId) source.get("_id"), (boolean) source.get("active"), (String) source.get("name"),
            (String) source.get("shortName"), (List<Person>) source.get("person"));
    return p;
    }
}

Profile.java

@Document(collection = "profile")
public class Profile {

@Id
private ObjectId id;
private boolean active;
@Indexed(unique = true)
@Field("ProfileName")
private String name;
private String shortName;
@DBRef
private List<Person> person = new ArrayList<Person>();

public Profile() {

}

@PersistenceConstructor
public Profile(ObjectId id, boolean active, String name, String shortName, List<Person> person,) {
    this.id = id;
    this.active = active;
    this.name = name;
    this.shortName = shortName;
    this.person = person;
}
//getter and setter

Person.java

@Document(collection = "person")
public class Person extends Ressource {

@Indexed
private String firstname;
private String lastname;
@Field("email")
@Indexed(unique = true)
private String eMailAddress;
private String login;
@DBRef
private List<Profile> profiles = new ArrayList<Profile>();

public Person(ObjectId id, String firstname, String lastname, String eMailAddress, String login) {
    this.setId(id);
    this.firstname = firstname;
    this.lastname = lastname;
    this.eMailAddress = eMailAddress;
    this.login = login;
}

@PersistenceConstructor
public Person(ObjectId id, String firstname, String lastname, String eMailAddress, String login,
        List<Profile> profiles) {
    this.firstname = firstname;
    this.lastname = lastname;
    this.eMailAddress = eMailAddress;
    this.login = login;
    this.profiles = profiles;
}

основной или тестовый класс

    ...
    Profile profileFind = mongoOps.findOne(new Query(where("shortName").is("SE")), Profile.class, "profile");
person Kanuni89    schedule 06.11.2015
comment
я обнаружил, что этот сценарий неверен, поэтому я загружаю ссылки лениво, вот так -> @DBRef(lazy=true).. так что вы не попадете в бесконечный цикл, поэтому вы также можете опустить конвертеры - person Kanuni89; 20.11.2015