JPA 在 Spring Boot 中导致 java.lang.NullPointerException
Posted
技术标签:
【中文标题】JPA 在 Spring Boot 中导致 java.lang.NullPointerException【英文标题】:JPA Causing java.lang.NullPointerException in Spring Boot 【发布时间】:2018-05-29 09:04:13 【问题描述】:我正在尝试在我的 Spring Boot 应用程序中运行一些单元测试并收到以下错误:
我不知道这是因为它无法连接到我在 Heroku (ClearDB) 中的数据库,还是我的代码中有一些注释错误。
我在运行时将环境变量加载到我的application-dev.properties
文件中,所有这些信息都可以在底部看到。
错误
java.lang.NullPointerException
at com.algoq.algoq.services.AlgorithmService.getSubscribers(AlgorithmService.java:26)
at com.algoq.algoq.ExampleTest.subscriberListNull(ExampleTest.java:42)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
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.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.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
测试类
package com.algoq.algoq;
import com.algoq.algoq.models.Subscriber;
import com.algoq.algoq.respositories.SubscriberRepository;
import com.algoq.algoq.services.AlgorithmService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@TestConfiguration
@SpringBootTest(classes =
AlgoQApplication.class,
)
public class ExampleTest extends AlgoQApplicationTests
@Autowired
private AlgorithmService aService;
@MockBean
private SubscriberRepository employeeRepository;
@Bean
public AlgorithmService aService()
return new AlgorithmService();
@Test
public void subscriberListNull() throws Exception
ArrayList<Subscriber> subs = aService.getSubscribers();
assertThat(subs).isEmpty();
服务类
package com.algoq.algoq.services;
import com.algoq.algoq.models.Subscriber;
import com.algoq.algoq.respositories.SubscriberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
@Service
public class AlgorithmService
@Autowired
private SubscriberRepository subRep;
/**
* Gets a list of subscribers to return to the API
* @return
*/
public ArrayList<Subscriber> getSubscribers()
ArrayList<Subscriber> subscribers = new ArrayList<>();
subRep.findAll()
.forEach(subscribers::add);
return subscribers;
/**
* Adds a new subscriber to the database
* @param sub
* @return
*/
public void addSubscriber(Subscriber sub)
subRep.save(sub);
/**
* Finds a single user id
* @param email
* @return
*/
public List<Subscriber> getSubscriber(String email)
return subRep.findByEmailAddress(email);
POM
http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0
<groupId>com.algoQ</groupId>
<artifactId>algo-q</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>algo-q</name>
<description>An algorithm a day keeps the brain up to date</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.9</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.12</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-standalone</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<!--<dependency>-->
<!--<groupId>com.h2database</groupId>-->
<!--<artifactId>h2</artifactId>-->
<!--<version>1.4.196</version>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
<!--<dependency>-->
<!--<groupId>com.h2database</groupId>-->
<!--<artifactId>h2</artifactId>-->
<!--<version>1.4.194</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.pygments</groupId>
<artifactId>pygments</artifactId>
<version>1.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
应用属性
server.port = 5600
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=$MAIL_USER
spring.mail.password=$MAIL_PASS
#mail properties
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.thymeleaf.cache=false
spring.thymeleaf.mode=html5
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url = $MYSQL_HOST
spring.datasource.username = $MYSQL_USERNAME
spring.datasource.password = $MYSQL_PASSWORD
spring.datasource.tomcat.max-active=20
spring.datasource.maxIdle=2
spring.datasource.tomcat.remove-abandoned=true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
【问题讨论】:
您正在使用模拟,模拟的默认行为是返回null
。对findAll
的调用会返回null
,因此forEach
上的NullPointerException
。也停止混合来自不同版本的 Spring Boot jar 1.5.9
和 1.5.2
等待发生的麻烦。
谢谢@M.Deinum 你能详细说明版本控制问题吗?我该如何解决这个问题
从spring-data-jpa-starter
依赖中删除版本,你可以删除hibernate-core
依赖。
谢谢!我现在有这个工作,感谢它
@M.Deinum 您能否发表此评论作为答案?否则,问题将显示为未回答。谢谢。
【参考方案1】:
您正在使用@MockBean
,它在下面使用Mockito.mock
来创建您的bean 的模拟。模拟的默认行为是返回默认值,在这种情况下,它将返回 null
作为默认值。因此它将在forEach
上中断
您需要做的是告诉您的模拟在特定方法调用上要做什么。在您的情况下,您可能希望返回一个空列表。在您的测试方法中,您需要在这些方面添加一些内容。
@Test
public void subscriberListNull() throws Exception
Mockito.when(employeeService.findAll)).thenReturn(new ArrayList());
ArrayList<Subscriber> subs = aService.getSubscribers();
assertThat(subs).isEmpty();
这也与 Spring Data JPA 的默认值内联,因为它永远不会从集合返回方法返回 null
。如果没有结果,您将获得一个空集合。
【讨论】:
以上是关于JPA 在 Spring Boot 中导致 java.lang.NullPointerException的主要内容,如果未能解决你的问题,请参考以下文章
Spring <form:select> 标签在 Spring mvc + Hibernate 应用程序中导致错误
SpringBoot2(thymeleaf模板jsp页面和jpa)
Spring Boot(17)——使用Spring Data JPA