【问题标题】:JPA repository throwing null pointer exceptionJPA 存储库抛出空指针异常
【发布时间】:2020-09-08 08:54:42
【问题描述】:

我对 Spring Boot 和 jpa 还很陌生。我正在为我的学习目的做一个小项目。

实体类

package com.jranjanacademy.currencyexchangeservice.service;

import java.math.BigDecimal;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class ExchangeService {

    @Id
    private long id;

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

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

    private BigDecimal conversionMultiple;

    private int port;

    // == Constructors ==

    // == No arg Constructors ==
      public ExchangeService() {

      }

    // == Parametrised Constructors ==
    public ExchangeService(long id, String from, String to, BigDecimal conversionMultiple) {
        super();
        this.id = id;
        this.from = from;
        this.to = to;
        this.conversionMultiple = conversionMultiple;
    }

    /**
     * @return the id
     */
    public long getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(long id) {
        this.id = id;
    }

    /**
     * @return the from
     */
    public String getFrom() {
        return from;
    }

    /**
     * @param from the from to set
     */
    public void setFrom(String from) {
        this.from = from;
    }

    /**
     * @return the to
     */
    public String getTo() {
        return to;
    }

    /**
     * @param to the to to set
     */
    public void setTo(String to) {
        this.to = to;
    }

    /**
     * @return the conversionMultiple
     */
    public BigDecimal getConversionMultiple() {
        return conversionMultiple;
    }

    /**
     * @param conversionMultiple the conversionMultiple to set
     */
    public void setConversionMultiple(BigDecimal conversionMultiple) {
        this.conversionMultiple = conversionMultiple;
    }

    /**
     * @return the port
     */
    public int getPort() {
        return port;
    }

    /**
     * @param port the port to set
     */
    public void setPort(int port) {
        this.port = port;
    }
}

控制器类:

package com.jranjanacademy.currencyexchangeservice.controller;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.env.Environment;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;

    import com.jranjanacademy.currencyexchangeservice.service.ExchangeService;
    import com.jranjanacademy.currencyexchangeservice.service.ExchangeServiceRepository;

    @RestController
    public class ExchangeServiceController {

        @Autowired
        private Environment environment;

        @Autowired
        private ExchangeServiceRepository exchangeServiceRepository;

        @GetMapping("/currency-exchange/from/{from}/to/{to}")
        public ExchangeService retrieveExchangeValue(@PathVariable String from, @PathVariable String to){
            ExchangeService exchangeValue =
                    exchangeServiceRepository.findByFromAndTo(from, to);
        exchangeValue.setPort(
                    Integer.parseInt(environment.getProperty("local.server.port")));
        return exchangeValue;
        }
    }

JPARepository

package com.jranjanacademy.currencyexchangeservice.service;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ExchangeServiceRepository extends JpaRepository<ExchangeService, Long>{

    ExchangeService findByFromAndTo(String from, String to);
}

data.sql 如下所示,我可以在 h2 控制台中看到该表

insert into exchange_service(id,currency_from,currency_to,conversion_multiple,port)
values(1001,'USD','INR',75,0);
insert into exchange_service(id,currency_from,currency_to,conversion_multiple,port)
values(1002,'AUD','INR',42,0);
insert into exchange_service(id,currency_from,currency_to,conversion_multiple,port)
values(1003,'EUR','INR',65,0);
insert into exchange_service(id,currency_from,currency_to,conversion_multiple,port)
values(1004,'POUND','INR',51,0);

当我尝试访问网址“http://localhost:8000/currency-exchange/from/INR/to/USD”时遇到异常情况

2020-05-21 21:14:58.229 ERROR 9384 --- [nio-8000-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

    java.lang.NullPointerException: null
        at com.jranjanacademy.currencyexchangeservice.controller.ExchangeServiceController.retrieveExchangeValue(ExchangeServiceController.java:25) ~[classes/:na]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93) ~[spring-boot-actuator-2.3.0.RELEASE.jar:2.3.0.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.35.jar:9.0.35]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_91]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_91]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.35.jar:9.0.35]

Application.properties

spring.application.name=currency-exchange-service
server.port=8000
spring.jpa.show-sql=true
spring.h2.console.enabled=true

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

有什么线索吗?

【问题讨论】:

  • 两个问题:你的表中是否填充了数据?你能证实这一点吗?另外,您的 application.properties 是什么样的?
  • 你可以尝试将@Repository 注解添加到存储库接口吗?
  • 是的,我可以在 h2 控制台中看到数据。 application.properties 如下所示。 spring.application.name=currency-exchange-service server.port=8000 spring.jpa.show-sql=true spring.h2.console.enabled=true spring.datasource.url=jdbc:h2:mem:testdb spring.datasource .driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
  • @TharakaDevinda 我尝试将 Repository 注释放在界面中,但仍然没有乐趣。我看到了同样的错误。
  • 在控制器中设置断点并检查哪些变量是 null 并告诉我们。

标签: java spring-boot rest jpa


【解决方案1】:

我很惊讶您在运行时开始时没有收到异常。 ExchangeServiceRepository 引用为空。您需要将@Repository 注释添加到ExchangeServiceRepository 类型。 Spring 可能无法自动装配此 Bean,因为它没有注释为存储库 (DAO),其核心是 @Component

@Repository
public interface ExchangeServiceRepository extends JpaRepository<ExchangeService, Long>{

    ExchangeService findByFromAndTo(String from, String to);
}

我没有看到您的主要课程,因此请确保您致电 @EnableJpaRepositories 以便 Spring Boot 可以获取您的存储库。

【讨论】:

  • 我尝试将 Repository 注释放在界面中,但仍然没有乐趣。我看到同样的错误
  • 我也有最初的怀疑。但他的情况似乎并非如此。既然有 JpaRepository,那真的需要吗?
  • 我非常肯定不需要@Repository,因为我能够使用 JpaRepository 的默认方法,但不确定当我尝试使用“ExchangeService findByFromAndTo(String from, String to) 时发生了什么;"。
  • 这太奇怪了。您是否在应用程序入口点类中调用了注解@EnableJpaRepositories?
  • @Json 应用程序入口点类是什么意思?你是说主班吗?如果是,我也尝试在主类中添加 EnableJpaRepositories 注释,但我仍然看到相同的异常
【解决方案2】:

尝试使用

@Value("${local.server.port}")
int port;

而不是

environment.getProperty("local.server.port")

看来问题是存在的。 为了反驳或确认这一点,只需删除带有exchangeValue.setPort(Integer.parseInt(environment.getProperty("local.server.port")));的行

【讨论】:

  • 我在上面的代码行中发表了评论,现在我没有遇到任何异常。但我也没有在浏览器中看到任何输出。我记录了“exchangeValue”的值,发现它为空,这就是我得到空指针异常的原因,因为我试图将端口设置为空引用。现在我不确定为什么我会得到 exchangeValue 的空引用。
【解决方案3】:

好的,从问题中我可以看到 2 件事

  1. 插入的项目是
id,  | currency_from | currency_to | conversion_multiple |port
1001 |    'USD'      |    'INR'    |     75.             |0
1002 |    'AUD'      |    'INR'    |     42              |0
1003 |    'EUR'      |    'INR'    |     65              |0
1004 |    'POUND'    |    'INR'    |     51              |0
  1. 请求http://localhost:8000/currency-exchange/from/INR/to/USD
From : INR, TO : USD

所以我怀疑在下面的行中你一定有 NULL 值,因为表中不存在 FROM :INRTO: USD

ExchangeService exchangeValue = exchangeServiceRepository.findByFromAndTo(from, to);

所以解决办法是,

  • 在处理前检查exchangeValue是否为null

(或)

  • 将 Employee 作为 Optional 数据返回,参考 this(上面的 sol 更简单,代码质量更好)

【讨论】:

  • 是的,exchangeValue 为空。但为什么它是空的?谢谢
  • select * from exchange_service where currency_from = 'INR' and currency_to='USD'; 将返回空,这就是为什么 exchangeValue 为空
  • 因为正如@Avi 所建议的那样,根据您的 URL http://localhost:8000/currency-exchange/**from/INR**/to/USD,您在表中没有具有 INR 值的 currency_from 的此类实体。
  • @Andrew 感谢您的解释。我使用了错误的网址。我应该使用localhost:8000/currency-exchange/from/USD/to/INR
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-27
  • 2020-11-22
  • 2020-08-10
  • 2013-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多