0

I'm building a project where I'm using Spring Boot and JavaFX. In the main scene I push a button that calls a method in a service and this one calls a method in the repository, but I'm getting an error saying the repository is null.

I have read a lot of answer because there are a lot of posts describing the same problem and tried everything I found but can't get it to work.

Please can you help me?

Here is the error:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at javafx.fxml@19/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1857)
at javafx.fxml@19/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1724)
at javafx.base@19/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at javafx.base@19/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
at javafx.base@19/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base@19/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@19/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base@19/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.base@19/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics@19/javafx.scene.Node.fireEvent(Node.java:8923)
at javafx.controls@19/javafx.scene.control.Button.fire(Button.java:203)
at javafx.controls@19/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:207)
at javafx.controls@19/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
at javafx.base@19/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
at javafx.base@19/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at javafx.base@19/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
at javafx.base@19/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base@19/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@19/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base@19/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base@19/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base@19/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.base@19/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics@19/javafx.scene.Scene$MouseHandler.process(Scene.java:3894)
at javafx.graphics@19/javafx.scene.Scene.processMouseEvent(Scene.java:1887)
at javafx.graphics@19/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2620)
at javafx.graphics@19/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:411)
at javafx.graphics@19/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:301)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics@19/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:450)
at javafx.graphics@19/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
at javafx.graphics@19/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:449)
at javafx.graphics@19/com.sun.glass.ui.View.handleMouseEvent(View.java:551)
at javafx.graphics@19/com.sun.glass.ui.View.notifyMouse(View.java:937)
at javafx.graphics@19/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics@19/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:77)
at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at javafx.base@19/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:275)
at javafx.fxml@19/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:84)
at javafx.fxml@19/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1854)
... 46 more
Caused by: java.lang.NullPointerException: Cannot invoke "com.lista.project.repository.AlimentoRepository.findAll()" because "this.alimentoRepository" is null
at com.lista.project.service.AlimentoService.getAll(AlimentoService.java:19)
at com.lista.project.controller.MainController.getAllAlimentos(MainController.java:48)
... 57 more

Here is the structure of the project:

enter image description here

Here is the Application class:

@SpringBootApplication
@EnableAutoConfiguration
@EnableJpaRepositories(basePackages = {"com.lista.project.repository", "com.lista.project.repository.custom"})
//@EnableTransactionManagement
@EntityScan(basePackages = {"com.lista.project.*"})
@ComponentScan(basePackages = {"com.lista.project.*"})
public class MiListaCompraApplication extends SpringBootServletInitializer{


    public static void main(String[] args) {
        SpringApplication.run(MiListaCompraApplication.class, args);
        MainController.main(args);
    }
    
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(MiListaCompraApplication.class);
    }

}

Here is the main scene controller:

@RestController // Don't think I really need this annotation
public class MainController extends Application {

    AlimentoService alimentoService = new AlimentoService();
    
    
    @Override
    public void start(Stage primaryStage) {
        try {
            
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/lista/project/scene/Main.fxml"));
            
            //First I was defining the controller in the Main.fxml file, but tried to change into this as I read somewhere
            loader.setController(this); 
            Parent parent = loader.load();
            
            Scene scene = new Scene(parent,400,400);
            primaryStage.setScene(scene);
            primaryStage.setTitle("Mi lista de la compra");
            primaryStage.show();
            
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        launch(args);
    }
    
    public List<Alimento> getAllAlimentos() {
        
        List<Alimento> response = alimentoService.getAll();
        System.out.println("Bien!");
        return response;
    }
}

Here is the service:

@Service
public class AlimentoService {

    @Autowired
    private AlimentoRepository alimentoRepository;
    
    
    public List<Alimento> getAll() {
        return alimentoRepository.findAll(); 
    }
}

Here is the Repository:

@Component //Don't think I need this annotation, but also tried @Repository just in case
public interface AlimentoRepository extends AlimentoRepositoryI, JpaRepository<Alimento, Integer> {

}

More parts of the same repository:

@Component //Don't think I need this annotation, but also tried @Repository just in case
public interface AlimentoRepositoryI {

}

@Component //Here is where I actually have to put the annotation, right? (Tried @Repository too)
public class AlimentoRepositoryImpl implements AlimentoRepositoryI {

}

My entity:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "alimento")
public class Alimento {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @NotNull
    @Column(name = "name", length = 100, nullable = false)
    private String name;
}

The FXML file:

<AnchorPane minHeight="400.0" minWidth="400.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1">
   <children>
        <!-- Initially, the controller was defined here -->
      <Button fx:id="btnAlimentos" layoutX="30.0" layoutY="26.0" mnemonicParsing="false" onAction="#getAllAlimentos" text="Alimentos" />
      <Button fx:id="btnPlatos" layoutX="30.0" layoutY="75.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="70.0" text="Platos" />
   </children>
</AnchorPane>

Properties file:

server.port=8090
server.servlet.context-path=

spring.jmx.enabled= false
spring.jpa.open-in-view=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
spring.jpa.properties.hibernate.format_sql=false
spring.jpa.show-sql=false

spring.datasource.url = jdbc:mysql://localhost:3306/mimenu?useSSL=false&useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#spring.main.web-application-type=none

logging.level.org.hibernate.sql= error
        
debug=true

My POM.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lista</groupId>
    <artifactId>MiListaCompra</artifactId>
    <version>0.0.1</version>
    <packaging>war</packaging>
    <name>MiListaCompra</name>
    <description>Generador de lista de la compra con JavaFX y SpringBoot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<!--        <dependency> -->
<!--            <groupId>org.springframework.boot</groupId> -->
<!--            <artifactId>spring-boot-starter</artifactId> -->
<!--        </dependency> -->
                
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
        </dependency>
                
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Build path: enter image description here

Calfa
  • 233
  • 4
  • 11
  • I already have rest applications working only with spring boot and they work fine, but in this case I want JavaFX as well – Calfa Nov 12 '22 at 10:17
  • Your opinion, as any other opinion has my respect. I'm just trying to give as much information about my problema as possible. – Calfa Nov 12 '22 at 10:20
  • Related question on [JavaFX and Spring](https://stackoverflow.com/questions/57887944/adding-spring-dependency-injection-in-javafx-jpa-repo-service/57896435#57896435). – jewelsea Nov 12 '22 at 10:29
  • 2
    I don’t see a reason to use Servlets and Spring Web or Rest here, you don’t need that to use a repository. I’d also remove the Lombok dependency. Lombok doesn’t interoperate well with JavaFX properties, among other reasons not to use it. You aren’t hooking the spring context into your JavaFX app at all, so the two things won’t be aware of each other. Create a [mcve] hello world JavaFX + spring, then spring + repository, then spring + JavaFX + repository. Build slowly from scratch and test each addition. – jewelsea Nov 12 '22 at 10:38
  • 1
    Don’t call new on Spring components like the Service class. These need to be created and injected by Spring. – jewelsea Nov 12 '22 at 10:44
  • 1
    Don’t make a JavaFX application a controller, maintain separation of concerns. – jewelsea Nov 12 '22 at 10:45
  • See this [spring data tutorial](https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa). it shows you some of the config and dependencies you need and how to declare a repository interface, there is no need for a repository impl. – jewelsea Nov 12 '22 at 10:51
  • @jewelsea The reason I called the Service by usint ght eocnstructor is because I was having the same problema I have now, but with the Service instead of the repo. However, I could use the constructor on the service because it's a class but not on the Repo because it's an interface. – Calfa Nov 12 '22 at 12:18
  • But it is an auto wired service. If you call new on it rather than using a spring created object and injected reference, Spring cannot auto wire it and any auto wired values it has will be null, which is exactly what is happening. – jewelsea Nov 12 '22 at 18:30
  • Dependency injection (DI) only works when the object which has dependencies injected is managed by the DI framework. Your service must be managed by Spring, because it has "autowired" fields, which means you can't manually create an instance yourself. In other words, your service also needs to be autowired. This is a problem, because you have the service as part of the `Application` implementation, but JavaFX manages its own instance of that class (`launch` creates an instance of your application class for you, separate from whatever Spring does). – Slaw Nov 12 '22 at 20:35

0 Answers0