0

I've been getting into Java again after some years only dealing with javascript and typescript, and I'm trying to get into Spring Boot.

It sounds really fun and convenient, but I'm trying to do something simple and for some reason I can't get my repository to get injected into my service. It sounds something really simple, but I've been digging for hours and can't get it to work.I'm wondering if some of you can help me to understand what I'm doing wrong ,please.

Thanks in advance

Projects (Entity)

package com.example.demo.modules.projects.entities;

import javax.persistence.*;

@Entity
@Table
public class Projects {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column
    private String project_name;
    @Column
    private String description;
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getProject_name() {
        return project_name;
    }
    public void setProject_name(String project_name) {
        this.project_name = project_name;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
}

The Repository

package com.example.demo.modules.projects.repositories;

import com.example.demo.modules.projects.entities.Projects;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;


@Repository
public interface IProjectRepository extends JpaRepository<Projects, Long> {
    
}

CreateProjectsService

package com.example.demo.modules.projects.services;

import com.example.demo.modules.projects.entities.Projects;
import com.example.demo.modules.projects.repositories.IProjectRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CreateProjectService {


    @Autowired
    IProjectRepository iProjectRepository;

    public Projects execute(Projects project){
        System.out.println("Received " + project.toString());
        Projects CreatedProject= this.iProjectRepository.save(project);
        System.out.println("Created " + CreatedProject);
        return CreatedProject;
    }
}

The Error

It seems to not be injecting/instantiating correctly.

2020-10-09 00:56:08.774 ERROR 5856 --- [nio-8080-exec-1] 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: Cannot invoke "com.example.demo.modules.projects.repositories.IProjectRepository.save(Object)" because "this.iProjectRepository" is null] with root cause

java.lang.NullPointerException: Cannot invoke "com.example.demo.modules.projects.repositories.IProjectRepository.save(Object)" because "this.iProjectRepository" is null
    at com.example.demo.modules.projects.services.CreateProjectService.execute(CreateProjectService.java:17) ~[classes/:na]
    at com.example.demo.ServerApplication.newEmployee(ServerApplication.java:26) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[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:564) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:652) ~[tomcat-embed-core-9.0.38.jar:4.0.FR]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.38.jar:4.0.FR]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.38.jar:9.0.38]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
    at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]
MattV
  • 314
  • 3
  • 14

1 Answers1

1

The issue is because you did not allow Spring to instantiate CreateProjectService and takes control of the bean, probably you instantiated the object with new CreateProjectService().

The recommended approach is to create an interface e.g. ICreateProjectService like below:

public interface ICreateProjectService {

    Projects execute(Projects project);

}

And then implement ICreateProjectService in CreateProjectService like below:

@Service
public class CreateProjectService implements ICreateProjectService {

    @Autowired
    private IProjectRepository iProjectRepository;

    @Override
    public Projects execute(Projects project) {
        System.out.println("Received " + project.toString());
        Projects CreatedProject= this.iProjectRepository.save(project);
        System.out.println("Created " + CreatedProject);
        return CreatedProject;
    }
}

Then in your Controller layer, as an example of the service usage, autowire your service by injecting the interface, like below:

@Restcontroller
@RequestMapping("/api/v1")
public class CreateProjectRest {

    @Autowired
    private ICreateProjectService iCreateProjectService;

    @PostMapping
    public Projects execute(Projects project) {
        createProjectService.execute(project);
        // your code here
    }
}

Now Spring is able to recognize CreateProjectService as a concrete implementation, instantiates it as a Spring bean, keeps it in Spring container and make it available for Dependency Injection wherever injected.

Hope this helps out.

UPDATE:

It is more advisable to inject dependencies via constructor than field or setter method.

@Restcontroller
@RequestMapping("/api/v1")
public class CreateProjectRest {

    private ICreateProjectService iCreateProjectService;
    
    /* No needed to annotate @Autowired after Spring 4.3.*/
    public CreateProjectRest(ICreateProjectService iCreateProjectService){
      this.iCreateProjectService = iCreateProjectService;
    }

    @PostMapping
    public Projects execute(Projects project) {
        createProjectService.execute(project);
        // your code here
    }
}
Ali K. Nouri
  • 495
  • 5
  • 18
  • 1
    Thank you very much! It's working great now and the explanation helped me understand what was wrong and why!! – MattV Oct 09 '20 at 04:26
  • 5
    There is nothing wrong with the `CreateProjectService` nor is an interface a requirement. The main issue proibably was doing a `new CreateProjectService()` in the controller instead of autowiring it. – M. Deinum Oct 09 '20 at 07:08
  • I agree with @M.Deinum – Morteza Oct 09 '20 at 12:09
  • Using an interface or not has nothing to do with inversion of control or preventing anyone from instantiating something with new. – M. Deinum Oct 09 '20 at 17:40
  • I think having an interface here is completly wrong. Additional layer for nothing – Lemmy Oct 11 '20 at 19:42
  • @Lemmy Please refer to Martin Fowler's article https://martinfowler.com/articles/injection.html#FormsOfDependencyInjection Of course it is less code to inject the implementation, but this is not necessarily the better approach only because it has less layers. "In the case of a dependency injection-informed framework such as Spring, components are coded to interfaces." Here's more info: https://www.springbyexample.org/examples/core-concepts-dependency-injection-to-the-rescue.html#d0e357 – Ali K. Nouri Oct 11 '20 at 20:19
  • You are using constructor injection with interface, what is the point? Additionaly, just because something can be used you shouldn’t use it all the time, but use it when it is usefull – Lemmy Oct 11 '20 at 20:54
  • @Lemmy Constructor injection is another topic that is discussed here https://stackoverflow.com/questions/7779509/setter-di-vs-constructor-di-in-spring. What is the relation between constructor injection and adding interface layer you mentioned ? You're mixing two things. – Ali K. Nouri Oct 11 '20 at 21:24