【问题标题】:Where exactly is the NullPointer Exception?NullPointer 异常到底在哪里?
【发布时间】:2018-08-25 21:15:05
【问题描述】:

我正在使用 Spring 和 MongoDb 测试 API Rest 资源。 这是从资源到文档的“链”关系:

资源:

@RestController
@RequestMapping(CustomerResource.CUSTOMERS)
public class CustomerResource {

public static final String CUSTOMERS = "/customers";

public static final String CUSTOMER_ID = "/{id}";

@Autowired
private CustomerController customerController;

@PostMapping
public void createCustomer(@RequestBody CustomerDto customerDto) {
    this.customerController.createCustomer(customerDto);
}

...

}

控制器:

@Controller
public class CustomerController {

private CustomerRepository customerRepository;


...

public void createCustomer(CustomerDto customerDto) {
    Customer customer = new Customer(customerDto.getName(),
    customerDto.getAddress());
    this.customerRepository.save(customer);
}

...
}

dto:

public class CustomerDto {


private String name;

private String address;

private Date date;

public CustomerDto (String name, String address) {
    this.name = name;
    this.address = address;
}

public CustomerDto() {
}

...(getters & setters & toString())...
}

存储库:

public interface CustomerRepository extends MongoRepository<Customer, String> {

public List<Customer> findByName(String name);

public Customer findById(String id);

public List<Customer> findAll();

@Query("{$and:[{'name':?0},{'address':?1}]}")
Customer findByNameAndAddress(String name, String address);

}

还有文件:

@Document
public class Customer {

@Id
private String id;

private String name;

private String address;

private Date date;

public Customer (String name, String address) {
    this();
    this.name = name;
    this.address = address;
    this.date = new Date();
}

public Customer() {
}

public String getId() {
    return id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getAddress() {
    return address;
}

public void setAddress(String address) {
    this.address = address;
}

public Date getDate() {
    return date;
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Customer other = (Customer) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (!id.equals(other.id))
        return false;
    return true;
}

@Override
public String toString() {
    return "Customer [id=" + id + ", name=" + name + ", address=" + address + ", date=" + date + "]";
}

}

但是在运行测试时,我得到了 NullPointer 异常,我不明白 proccess 的哪一点是错误的。

资源测试:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@TestPropertySource(locations = "classpath:test.properties")
public class CustomerResourceFunctionalTesting {

 @Rule
 public ExpectedException thrown = ExpectedException.none();

 @Autowired
 private RestService restService;

 private CustomerDto customerDto;

 @Before
    public void before() {
        this.customerDto = new CustomerDto("Mark", "Washington");
    }

 @Test
    public void testCreateCustomer() {
        restService.restBuilder().path(CustomerResource.CUSTOMERS).body(this.customerDto).post().build();
    }

}

我认为这可能与未明确声明 id 字段有关,但由于 is 将通过 @Id 注释“实例化”,我认为不存在问题。

这是踪迹:

org.springframework.web.client.HttpServerErrorException: 500 
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:88)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:708)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:661)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:636)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:557)
at account.persistence.resources.RestBuilder.build(RestBuilder.java:191)
at account.persistence.resources.CustomerResourceFunctionalTesting.testCreateCustomer(CustomerResourceFunctionalTesting.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
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.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
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:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)

但我认为控制台日志会更有用:

java.lang.NullPointerException: null
at account.persistence.controllers.CustomerController.createCustomer(CustomerController.java:36) ~[classes/:na]
at account.persistence.resources.CustomerResource.createCustomer(CustomerResource.java:36) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_144]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_144]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_144]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_144]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.27.jar:8.5.27]
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_144]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_144]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.27.jar:8.5.27]
at java.lang.Thread.run(Unknown Source) [na:1.8.0_144]

编辑

这是 RestBuilder(与资源测试在同一文件夹中):

public class RestBuilder<T> {

private static final String SERVER_URI_DEFAULT = "http://localhost";

private static final int PORT_DEFAULT = 8080;

private RestTemplate restTemplate = new RestTemplate();

private String serverUri;

private int port;

private String path;

private List<Object> expandList;

private Map<String, String> headerValues;

private List<MediaType> mediaTytes;

private String authorization = null;

private Object body = null;

private MultiValueMap<String, String> params;

private Class<T> clazz;

private HttpMethod method;

private boolean log;

public RestBuilder(String serverUri, int port) {
    restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory()); // org.apache.httpcomponents.httpclient
    this.serverUri = serverUri;
    this.port = port;
    this.path = "";
    this.expandList = new ArrayList<>();
    this.headerValues = new HashMap<>();
    this.mediaTytes = new ArrayList<>();
    this.params = new HttpHeaders();
    this.log = false;
}

public RestBuilder() {
    this(SERVER_URI_DEFAULT, PORT_DEFAULT);
}

public RestBuilder(int port) {
    this(SERVER_URI_DEFAULT, port);
}

public RestBuilder(String serverUri) {
    this(serverUri, PORT_DEFAULT);
}

public RestBuilder<T> clazz(Class<T> clazz) {
    this.clazz = clazz;
    return this;
}

public RestBuilder<T> port(int port) {
    this.port = port;
    return this;
}

public RestBuilder<T> serverUri(String serverUri) {
    this.serverUri = serverUri;
    return this;
}

public RestBuilder<T> path(String path) {
    this.path = this.path + path;
    return this;
}

public RestBuilder<T> expand(Object... values) {
    for (Object value : values) {
        this.expandList.add(value);
    }
    return this;
}

public RestBuilder<T> basicAuth(String token) {
    return basicAuth(token, "");
}

public RestBuilder<T> basicAuth(String nick, String pass) {
    String auth = nick + ":" + pass;
    String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
    String authHeader = "Basic " + encodedAuth;
    this.authorization = authHeader;
    return this;
}

public RestBuilder<T> param(String key, String value) {
    this.params.add(key, value);
    return this;
}

public RestBuilder<T> header(String key, String value) {
    this.headerValues.put(key, value);
    return this;
}

public RestBuilder<T> accept(MediaType mediaType) {
    if (this.mediaTytes.isEmpty()) {
        this.mediaTytes.add(MediaType.APPLICATION_JSON);
    }
    this.mediaTytes.add(mediaType);
    return this;
}

public RestBuilder<T> body(Object body) {
    this.body = body;
    return this;
}

public RestBuilder<T> notError() {
    restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
        protected boolean hasError(HttpStatus statusCode) {
            return false;
        }
    });
    return this;
}

private HttpHeaders headers() {
    HttpHeaders headers = new HttpHeaders();
    for (String key : headerValues.keySet()) {
        headers.set(key, headerValues.get(key));
    }
    if (authorization != null) {
        headers.set("Authorization", authorization);
    }
    if (!this.mediaTytes.isEmpty()) {
        headers.setAccept(this.mediaTytes);
    }
    return headers;
}

private URI uri() {
    UriComponents uriComponents;
    if (params.isEmpty()) {
        uriComponents = UriComponentsBuilder.fromHttpUrl(serverUri + ":" + port + path).build();
    } else {
        uriComponents = UriComponentsBuilder.fromHttpUrl(serverUri + ":" + port + path).queryParams(params).build();
    }
    if (!expandList.isEmpty()) {
        uriComponents = uriComponents.expand(expandList.toArray());
    }
    return uriComponents.encode().toUri();

}

public RestBuilder<T> log() {
    this.log = true;
    return this;
}

public T build() {
    ResponseEntity<T> response;
    if (log) {
        Logger.getLogger(this.getClass()).info(method + " " + this.path + this.headers() + "{" + this.body + "}");
    }
    if (body != null && !method.equals(HttpMethod.GET)) {
        response = restTemplate.exchange(this.uri(), method, new HttpEntity<Object>(body, this.headers()), clazz);
        if (log) {
            Logger.getLogger(this.getClass()).info(response.getStatusCode() + "==" + response.getHeaders());
        }
        return response.getBody();
    } else {
        response = restTemplate.exchange(this.uri(), method, new HttpEntity<Object>(this.headers()), clazz);
        if (log) {
            Logger.getLogger(this.getClass()).info(response.getStatusCode() + "==" + response.getHeaders());
        }
        return response.getBody();
    }
}

public RestBuilder<T> post() {
    this.method = HttpMethod.POST;
    return this;
}

public RestBuilder<T> get() {
    this.method = HttpMethod.GET;
    return this;
}

public RestBuilder<T> put() {
    this.method = HttpMethod.PUT;
    return this;
}

public RestBuilder<T> patch() {
    this.method = HttpMethod.PATCH;
    return this;
}

public RestBuilder<T> delete() {
    this.method = HttpMethod.DELETE;
    return this;
}

}

还有 RestService(与 RestBuilder 在同一个文件夹中):

@Service
public class RestService {

@Autowired
private Environment environment;

@Value("${server.contextPath}")
private String contextPath;

private int port() {
    return Integer.parseInt(environment.getProperty("local.server.port"));
}

public <T> RestBuilder<T> restBuilder(RestBuilder<T> restBuilder) {
    restBuilder.port(this.port());
    restBuilder.path(contextPath);
    return restBuilder;
}

public RestBuilder<Object> restBuilder() {
    RestBuilder<Object> restBuilder = new RestBuilder<>(this.port());
    restBuilder.path(contextPath);
    return restBuilder;
}

}

编辑 2

作为替代方案,我尝试了另一种方法,正如我在 Resource Access Exception 中解释的那样,不使用 RestService 而是修改测试和 restbuilder,但是在访问资源时出现异常。

【问题讨论】:

  • 可以在帖子中添加 RestBuilder 和 RestService 类吗?

标签: mongodb spring-boot testing nullpointerexception


【解决方案1】:

尝试在您的CustomerController 上添加@Autowired 注释

@Autowired
private CustomerRepository customerRepository;

NullPointerException 的原因可能是存储库未正确注入。

【讨论】:

  • 如果我这样做,我会收到一个错误,其跟踪包括:“原因:org.springframework.beans.factory.NoSuchBeanDefinitionException:没有可用的 'account.persistence.dtos.CustomerDto' 类型的合格 bean :预计至少有 1 个符合自动装配候选资格的 bean。依赖注释:{@org.springframework.beans.factory.annotation.Autowired(required=true)}"
  • 如果我这样做,NullPointer 异常仍然存在。我尝试过另一种方法:stackoverflow.com/questions/49334739/resource-access-exception。我仍然遇到问题(资源访问异常),但我认为我们可以更轻松地找到问题。
  • 从您的示例中,可能是因为实际的server_url 尚未运行,这就是您得到ResourceAccessException 的原因?您是否尝试使用暴露的端点启动另一个示例 spring 应用程序,然后将您的 server_url 更改为该端点???
  • 我在另一个应用程序中使用了另一个 RestBuilder,它似乎运行良好
  • 那么,这解决了ResourceAccessException 的问题,对吧?端点尚未运行,不妨尝试不同的方法,而不是直接访问 server_url 端点。
猜你喜欢
  • 2012-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 2011-09-19
  • 2011-03-07
相关资源
最近更新 更多