英文:
Adding to a list which is an element in a Java Spring class
问题
以下是翻译后的代码部分:
@PostMapping("/education/{id}")
void newAccount(@RequestBody Education newEducation, @PathVariable Long id) {
Account a = repository.findById(id).orElseThrow(() -> new AccountNotFoundException(id));
a.addEducation(newEducation);
}
import java.util.LinkedList;
import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Account {
// ... (略去其余代码)
public void addEducation(Education e) {
education.add(e);
}
// ... (略去其余代码)
}
@Configuration
public class LoadDatabase {
private static final Logger log =
LoggerFactory.getLogger(LoadDatabase.class);
@Bean
CommandLineRunner initDatabase(AccountRepository repository) {
return args -> {
log.info("Preloading " + repository.save(new Account("Alex", "ax@b.com", "214")));
Account a = new Account("Bob", "bob@n.com", "972");
//a.addEducation(new Education("B.S.", "Uni", 3.64));
//log.info("Preloading " + repository.save(a));
};
}
}
public class Education {
// ... (略去其余代码)
}
如果您对代码的解释或问题的原因有疑问,请随时提问。
英文:
I have an Account class for a job search application I am building which contains a Linked List of Education instances (just university name, gpa, etc). I would like to have an HTTP Post request to add an element to that list:
@PostMapping("/education/{id}")
void newAccount(@RequestBody Education newEducation, @PathVariable Long id) {
Account a = repository.findById(id).orElseThrow(() -> new AccountNotFoundException(id));
a.addEducation(newEducation);
}
This is the account class:
import java.util.LinkedList;
import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Account {
private @Id @GeneratedValue Long id;
private String name;
private String email;
private String phone;
private LinkedList<Education> education;
Account() {}
Account(String name, String email, String phone) {
education = new LinkedList<>();
this.setName(name);
this.setEmail(email);
this.setPhone(phone);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id=id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public LinkedList<Education> getEducation() {
return education;
}
public void addEducation(Education e) {
education.add(e);
}
@Override
public boolean equals(Object o) {
if (this==o)
return true;
if (!(o instanceof Account))
return false;
Account acc = (Account)o;
return name.equals(acc.name);
}
@Override
public int hashCode() {
return Objects.hash(this.id, this.name);
}
@Override
public String toString() {
String edu="";
if (!this.education.isEmpty())
{
edu+=", \"Education: [";
for (Education e: this.education)
{
edu+=e.toString();
}
edu+="]";
}
String s = "Account{";
s += String.format("\"id\": \"%s\", ", this.id);
s += String.format("\"name\": \"%s\", ", this.name);
s += String.format("\"email\": \"%s\", ", this.email);
s += String.format("\"phone\": \"%s\"", this.phone);
s += edu;
s += "}";
return s;
}
}
However, when I actually send a post request with education data (for an already existing user), it does not post it. It does print the Account a properly (with the added education) but does not actually update the database.
Additionally, this is another class I have:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LoadDatabase {
private static final Logger log =
LoggerFactory.getLogger(LoadDatabase.class);
@Bean
CommandLineRunner initDatabase(AccountRepository repository) {
return args -> {
log.info("Preloading " + repository.save(new Account("Alex", "ax@b.com", "214")));
Account a= new Account("Bob", "bob@n.com", "972");
//a.addEducation(new Education("B.S.", "Uni", 3.64));
//log.info("Preloading " + repository.save(a));
};
}
}
Uncommenting a.addEducation and log.info causes a runtime error (keeping either one of them would not trigger that):
> java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:779) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at com.project933.Project933Application.main(Project933Application.java:10) ~[classes/:na]
Caused by: org.springframework.orm.jpa.JpaSystemException: could not serialize; nested exception is org.hibernate.type.SerializationException: could not serialize
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:353) ~[spring-orm-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255) ~[spring-orm-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) ~[spring-orm-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) ~[spring-tx-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:154) ~[spring-tx-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:178) ~[spring-data-jpa-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at com.sun.proxy.$Proxy90.save(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at com.sun.proxy.$Proxy64.save(Unknown Source) ~[na:na]
at com.project933.LoadDatabase.lambda$0(LoadDatabase.java:19) ~[classes/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:795) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
... 5 common frames omitted
Caused by: org.hibernate.type.SerializationException: could not serialize
at org.hibernate.internal.util.SerializationHelper.serialize(SerializationHelper.java:119) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.internal.util.SerializationHelper.serialize(SerializationHelper.java:144) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.internal.util.SerializationHelper.clone(SerializationHelper.java:75) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.type.descriptor.java.SerializableTypeDescriptor$SerializableMutabilityPlan.deepCopyNotNull(SerializableTypeDescriptor.java:41) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.type.descriptor.java.SerializableTypeDescriptor$SerializableMutabilityPlan.deepCopyNotNull(SerializableTypeDescriptor.java:32) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.type.descriptor.java.MutableMutabilityPlan.deepCopy(MutableMutabilityPlan.java:35) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.type.AbstractStandardBasicType.deepCopy(AbstractStandardBasicType.java:308) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.type.AbstractStandardBasicType.deepCopy(AbstractStandardBasicType.java:304) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.type.TypeHelper.deepCopy(TypeHelper.java:55) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:279) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:135) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:185) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:128) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:55) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:721) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:707) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:314) ~[spring-orm-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at com.sun.proxy.$Proxy87.persist(Unknown Source) ~[na:na]
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:554) ~[spring-data-jpa-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.data.repository.core.support.ImplementationInvocationMetadata.invoke(ImplementationInvocationMetadata.java:72) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:382) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:205) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:549) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:155) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:130) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367) ~[spring-tx-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118) ~[spring-tx-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.2.9.RELEASE.jar:5.2.9.RELEASE]
... 21 common frames omitted
Caused by: java.io.NotSerializableException: com.project933.Education
at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1185) ~[na:na]
at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:349) ~[na:na]
at java.base/java.util.LinkedList.writeObject(LinkedList.java:1135) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at java.base/java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1145) ~[na:na]
at java.base/java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1497) ~[na:na]
at java.base/java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1433) ~[na:na]
at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1179) ~[na:na]
at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:349) ~[na:na]
at org.hibernate.internal.util.SerializationHelper.serialize(SerializationHelper.java:115) ~[hibernate-core-5.4.21.Final.jar:5.4.21.Final]
... 63 common frames omitted
Could anyone please explain why I am having problems with inserting the Education instances into the Account database? I am using JpaRepository.
Thanks!
edit: This is the Education class:
public class Education {
private String degree;
private String institute;
private double gpa;
Education(String degree, String institute, double gpa) {
this.setDegree(degree);
this.setInstitute(institute);
this.setGpa(gpa);
}
public String getDegree() {
return degree;
}
public void setDegree(String degree) {
this.degree = degree;
}
public String getInstitute() {
return institute;
}
public void setInstitute(String institute) {
this.institute = institute;
}
public double getGpa() {
return gpa;
}
public void setGpa(double gpa) {
this.gpa = gpa;
}
@Override
public String toString() {
String s = "{";
s += s += String.format("\"degree\": \"%s\"", this.degree);
s += String.format("\"institute\": \"%s\"", this.institute);
s += String.format("\"gpa\": %.2f", this.gpa);
s += "}";
return s;
}
}
答案1
得分: 1
问题是,只要您的列表是动态的,它就无法进行序列化,但是它需要序列化才能传输到数据库。因此,您必须确保您的列表是可序列化的。这可以通过_"List.of 和 List.copyOf 静态工厂方法提供了一种便捷的方式来创建不可修改的列表。"实现。因此这意味着,在将您的对象发送到数据库之前,您必须确保您的列表对象是"不可修改的/非动态的"_。
英文:
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html
The problem is, as long as your list is dynamic, it can't be serialized, but it needs to be serialized to be able to transmit to the database. So you have to make sure that your list is serializable. This is achieved by "The List.of and List.copyOf static factory methods provide a convenient way to create unmodifiable lists." So it means, before you send your object to the database, you've to make sure that your list objects are unmodifable/not dynamic.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论