Я столкнулся с проблемой базовых объектов Spring Data JPA.Если объект существует и вызывает его метод установки, и если параметром может быть сущность, возвращаемая JpaRepository, он генерирует исключение NullPointerException.
Entity Cheat
@Entity
@Table(name = "cheat")
@DynamicInsert
@DynamicUpdate
@Getter
@Setter
@EqualsAndHashCode(exclude={"vote"})
@NoArgsConstructor
@RequiredArgsConstructor(staticName="of")
public class Cheat implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cheat_seq", length = 10)
private Long cheatSeq;
@Column(name = "question", unique = true, nullable = false)
@NonNull
private String question;
@Column(name = "answer", unique = true, nullable = false)
@NonNull
private String answer;
@Column(name = "writer_ip", nullable = false)
@NonNull
private String writerIP;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "reg_date", nullable = false)
@NonNull
private Date regDate;
@Transient
@NonNull
private String regDateText;
@OneToMany(mappedBy = "cheat", fetch=FetchType.EAGER)
private Set<CheatVote> vote = new HashSet<CheatVote>();
@Override
public String toString() {
return "Cheat [cheatSeq=" + cheatSeq + "]";
}
}
И Entity CheatVote , представляющая собой коллекцию @ManyToOne из Cheat , ниже:
@Entity
@Table(name="cheat_vote")
@DynamicInsert
@DynamicUpdate
@Getter
@Setter
@RequiredArgsConstructor(staticName="of")
@NoArgsConstructor
public class CheatVote implements Serializable{
private static final long serialVersionUID = 1L;
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Id
@Column(name="seq", nullable=false)
private Long seq;
@Column(name="val", nullable=false)
@NonNull
private Integer value;
@Column(name="ip_address", nullable=false)
@NonNull
private String ipAddress;
@JoinColumn(name="cheat_fk", referencedColumnName="cheat_seq")
@ManyToOne(cascade=CascadeType.ALL)
@NonNull
private Cheat cheat;
@Override
public String toString() {
return "CheatVote [seq=" + seq + "]";
}
}
Уровень обслуживания находится ниже:
@Transactional
@Service
public class CheatVoteServiceImpl implements CheatVoteService{
@Autowired
private CheatVoteRepository repository;
@Autowired
private CheatService cheatService;
@Override
public void addGoodVote(Long cheatSeq, String ipAddress) throws NotFoundEntityException {
Cheat cheat = cheatService.findOne(cheatSeq);
CheatVote vote = new CheatVote();
vote.setCheat(cheat);
vote.setValue(CheatVoteRepository.VOTE_TYPE_GOOD);
vote.setIpAddress(ipAddress);
Set<CheatVote> votes = new HashSet<CheatVote>();
votes.add(vote);
cheat.setVote(votes);
cheatService.addCheat(cheat);
repository.save(vote);
}
}
Уровень репозитория находится ниже:
public interface CheatVoteRepository extends JpaRepository<CheatVote, Long>{
Integer VOTE_TYPE_GOOD = 1;
}
Код теста приведен ниже:
@Test
public void voteTest() throws Exception{
cheatService.addCheat(addDTO1);
Cheat cheat = cheatService.findAll().get(0);
assertEquals(0, cheat.getVote().size());
cheatVoteService.addGoodVote(cheat.getCheatSeq(), "127.0.0.1");
}
Два объекта DTO находятся ниже.Один из них:
@NoArgsConstructor
@Data
public class CheatAddNewDTO {
private String ipAddress;
private List<CheatUnit> unitList;
}
А другой:
@RequiredArgsConstructor(staticName="of")
@NoArgsConstructor
@Data
public class CheatUnit {
@NotNull
@NonNull
@Mapping("question")
private String question;
@NotNull
@NonNull
@Mapping("answer")
private String answer;
}
Выдает NullPointerException :
java.lang.NullPointerException: cheat
at com.ddedderu.moonBladeQuiz.data.entity.CheatVote.setCheat(CheatVote.java:29)
at com.ddedderu.moonBladeQuiz.data.service.CheatVoteServiceImpl.addGoodVote(CheatVoteServiceImpl.java:31)
at com.ddedderu.moonBladeQuiz.data.service.CheatVoteServiceImpl$$FastClassBySpringCGLIB$$d089e475.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:736)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:671)
at com.ddedderu.moonBladeQuiz.data.service.CheatVoteServiceImpl$$EnhancerBySpringCGLIB$$b1f41534.addGoodVote(<generated>)
at com.ddedderu.moonBladeQuiz.MoonBladeQuizApplicationTests.voteTest(MoonBladeQuizApplicationTests.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
После просмотра этой ошибкиСтеки, я подумал, что когда сущность задается в методе установки объекта, ее прокси-объект (может быть, используется с навыком AOP) делает что-то для работы с внутренней системой JPA.
Но почему я должен даже учитывать эту основную часть JPA?Или этот стек ошибок происходит из-за моей неправильной структуры сущностей?Что пошло не так?
И я сожалею, что не могу быстро отреагировать на ваш комментарий!
Не стесняйтесь запрашивать любой код, связанный с этим вопросом!
Спасибо.