0

On the heels of a previous question I asked about integrating Spring Boot and React together, I used that solution to resolve Spring Boot finding React build files, as well as displaying information from API requests.

Another unexpected issue has formed up - Apache Tomcat fails to deploy the war file that resulted from these changes. The project, however, is flawless when it works inside the IDE.

Upon trying to start the project, the following occurs: enter image description here

Before anything else, this is the stack trace:


09-Mar-2023 15:53:27.129 INFO [http-nio-8080-exec-18] org.apache.catalina.startup.HostConfig.undeploy Undeploying context [/backend]
09-Mar-2023 15:53:37.395 INFO [http-nio-8080-exec-21] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [C:\Program Files\Apache Software Foundation\Tomcat 9.0\webapps\backend.war]
09-Mar-2023 15:53:42.775 INFO [http-nio-8080-exec-21] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
09-Mar-2023 15:53:55.329 SEVERE [http-nio-8080-exec-21] org.apache.catalina.startup.HostConfig.deployWAR Error deploying web application archive [C:\Program Files\Apache Software Foundation\Tomcat 9.0\webapps\backend.war]
    java.lang.IllegalStateException: Error starting child
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:729)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:698)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:696)
        at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1023)
        at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:543)
        at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1689)
        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:566)
        at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:293)
        at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:809)
        at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
        at org.apache.catalina.manager.ManagerServlet.check(ManagerServlet.java:1614)
        at org.apache.catalina.manager.HTMLManagerServlet.upload(HTMLManagerServlet.java:291)
        at org.apache.catalina.manager.HTMLManagerServlet.doPost(HTMLManagerServlet.java:209)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:696)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:779)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
        at org.apache.catalina.filters.CsrfPreventionFilter.doFilter(CsrfPreventionFilter.java:203)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
        at org.apache.catalina.filters.HttpHeaderSecurityFilter.doFilter(HttpHeaderSecurityFilter.java:126)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:660)
        at org.apache.catalina.valves.RequestFilterValve.process(RequestFilterValve.java:378)
        at org.apache.catalina.valves.RemoteAddrValve.invoke(RemoteAddrValve.java:56)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
        at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:891)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1784)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.base/java.lang.Thread.run(Thread.java:829)
    Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/backend]]
        at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:440)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:198)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:726)
        ... 47 more
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'application': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javafx.application.Application]: Is it an abstract class?; nested exception is java.lang.InstantiationException
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1334)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
        at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:175)
        at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:155)
        at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:97)
        at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:174)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5211)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        ... 48 more
    Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javafx.application.Application]: Is it an abstract class?; nested exception is java.lang.InstantiationException
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:215)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1326)
        ... 68 more
    Caused by: java.lang.InstantiationException
        at java.base/jdk.internal.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:211)
        ... 70 more
09-Mar-2023 15:53:55.331 INFO [http-nio-8080-exec-21] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [C:\Program Files\Apache Software Foundation\Tomcat 9.0\webapps\backend.war] has finished in [17,937] ms
09-Mar-2023 15:54:03.325 INFO [http-nio-8080-exec-23] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.

The following are the various code details:

package.json:

{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "antd": "^5.1.6",
    "axios": "^1.2.1",
    "bootstrap": "^5.2.3",
    "clsx": "^1.2.1",
    "moment": "^2.29.4",
    "react": "^18.2.0",
    "react-bootstrap": "^2.7.0",
    "react-calendar": "^4.0.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.4.3",
    "react-scripts": "5.0.1",
    "react-table": "^7.8.0",
    "validator": "^13.7.0",
    "web-vitals": "^2.1.4"
  },
  
  "homepage":".",
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "css-loader": "^6.7.3"
  }
}

App.js:


class App extends Component {
  render() {
    return (      
       <HashRouter>
        <div>
          <Navigation />
            <Routes>
             <Route exact path="/" element={<Home />} />
             <Route path="/about" element={<About />}/>
             <Route path="/contact" element={<Contact />}/>
           </Routes>
        </div> 
      </HashRouter>
    );
  }
}
 
export default App;

UserController.java

package com.example.demo.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;

import com.example.demo.model.User;
import com.example.demo.service.UserService;

@Controller
public class UserController {
    
    @Autowired
    UserService userService;
    
    @GetMapping(value = "/**/{path:[^\\.]*}")
    public String forward() {
        return "forward:/";
    }
    
    @GetMapping("/clients")
    public List<User> getAllUsers() {

        return userService.getAllUsers();
    }
}


pom.xml

<?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.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>backend_2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>backend-3</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
        <tomcat.version>9.0.71</tomcat.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <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.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
    </dependencies>

    <build>
        <finalName>backend</finalName>
        <plugins>
        
            
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
            
            
            
            <plugin>
               <groupId>com.github.eirslett</groupId>
               <artifactId>frontend-maven-plugin</artifactId>
               <version>1.12.1</version>
               
               <executions>
                <execution>
                    <id>Install node and npm</id>
                    <goals>
                        <goal>install-node-and-npm</goal>
                    </goals>
                    <phase>generate-resources</phase>
                    <configuration>
                        <nodeVersion>v19.6.1</nodeVersion>
                        <npmVersion>9.4.0</npmVersion>
                    </configuration>
                </execution>
                
                <!-- running npm install -->
                <execution>
                    <id>npm install</id>
                    <goals>
                        <goal>npm</goal>
                    </goals>
                    <phase>generate-resources</phase>
                    <configuration>
                        <arguments>install</arguments>
                    </configuration>
                </execution>
                
                <!-- build production version -->
                <execution>
                    <id>npm build</id>
                    <goals>
                        <goal>npm</goal>
                    </goals>
                    <phase>generate-resources</phase>
                    <configuration>
                        <arguments>run build</arguments>
                    
                    </configuration>
                
                </execution>
               
               </executions>
               <configuration>
                    <nodeVersion>v19.6.1</nodeVersion>
                    <workingDirectory>src/main/frontend</workingDirectory>
               </configuration>
             </plugin>
             
             <!-- copy react build artigact to spring boot -->
             <plugin>
             <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
             <executions>
                <execution>
                    <id>Copy JavaScript app into SpringBoot</id>
                    <phase>process-resources</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>target/classes/static</outputDirectory>
                        <resources>
                            <resource>
                                <directory>src/main/frontend/build</directory>
                                <filtering>false</filtering>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
             </executions>
             
             </plugin>

        </plugins>
    </build>


</project>

I think that's about the required files that I'm working with.

The issue boils down to the inability of Apache to initialize the User model, or this is what the error is telling me. However, the Controller is also not an abstract method in any sense, and neither is such a method used anywhere in the project.

For the record, the project builds successfully: enter image description here

Things I've tried include the following:

  • Specify tomcat version

  • authentication issue, but for how this is not relevant to the project (still at a demo stage)

  • what seemed the most promising, change BrowserRouter to HashRouter and set the homepage to a period, but that led to nothing.

  • Arrange the context path in the application.properties file, but this is not actually meant for a production version of this app:

# these configuration details cannot be used for external Tomcat, they only work for the embedded version.
#server.servlet.context-path=/
#spring.mvc.servlet.path=/backend-3
  • changed @RestController to @Controller in the UserController file.

  • deploying the project on an external Tomcat, which essentially boiled down to having the provided scope in the pom.xml file.

  • Another suggestion i saw somewhere was to put @Autowired on the constructor in the model, but that has no impact on the outcome, and seems neither here, nor there. Otherwise, the constructors is your typical fields, getters/setters, constructor, blank constructor and toString.

UPDATE

  • Another thing that I tried was to put the name of the built project, backend, as a part of the routing in the App.js file, but that was not successful; that was based on the last example connected at the top of the question. I don't think that should be relevant for frontend routing, however?

UPDATE - MAR 10, 2023

There is no version conflict between the version of Apache Tomcat and Java 11, which I'm using:

enter image description here

The issue seems to start after removing the forward slashes from the last question in the index.html file on the static paths and that prevents Apache Tomcat from finding the initial path; seems to be another pathing problem.

<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="shortcut icon" href="/favicon.ico">
    <title>React App</title>
    <link href="static/css/main.9a0fe4f1.css" rel="stylesheet">
</head>

<body>
    <div id="root"></div>
    <script type="text/javascript" src="static/js/main.f55352b1.js"></script>
</body>

</html>

I could not find this particular trace anywhere else, but the details of it also don't make the most sense to me in the context of the project.

Thank you in advance for any insight!

epicUsername
  • 611
  • 2
  • 8
  • 21

1 Answers1

1

The issue is that Tomcat is not finding an implementation of javafx.application.Application, only the abstract definition.

This is not connected to reactJS or security. It's odd to me that JavaFX and ReactJS are being mixed - perhaps unintentionally.

The key is the following from the stack trace: Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javafx.application.Application]: Is it an abstract class?; nested exception is java.lang.InstantiationException at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:215)

I see no dependencies to javafx jars so presumably the IDE is set up to provide them.

Try adding the following to the pom to pull in all the javafx dependencies:

<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-base</artifactId>
    <version>11</version>
</dependency>
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-controls</artifactId>
    <version>11</version>
</dependency>
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-fxml</artifactId>
    <version>11</version>
</dependency>
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-graphics</artifactId>
    <version>11</version>
</dependency>
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-media</artifactId>
    <version>11</version>
</dependency>
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-swing</artifactId>
    <version>11</version>
</dependency>
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-web</artifactId>
    <version>11</version>
</dependency>
John Williams
  • 4,252
  • 2
  • 9
  • 18
  • I find it equally weird; JavaFX was never an intended aspect of this project. The Java code is entirely focused on the backend - there is JPA Repository included too, but that has nothing to do with it. The frontend is done entirely in React and the built version of that is slotted into the Spring Boot project, where it works with the compiled css/js files. Is there a way to tell Spring to ignore that, like you tell it that Tomcat is provided before mounting the project on an external server? – epicUsername Mar 10 '23 at 21:25
  • Wow, it worked. I do need to investigate this a bit more, but the base library (I have to keep the war file <=50MB, because Apache Tomcat limit) resulted in the project starting and rendering. Database isn't behaving properly yet, but I'll post a follow up answer after I fine tune the project. Thank you much for this insight! – epicUsername Mar 11 '23 at 04:32
  • Hahaha - I decided that it wouldn’t work so changed my, now accepted, answer to a suggestion that you deploy to a clean install of Tomcat. I reverted my answer. Could you change the title to something like “Tomcat 9 SpringBoot + ReactJS without JavaFX fails to start - javafx.application.Application is abstract” – John Williams Mar 11 '23 at 06:19
  • Also, you probably don’t need all the javafx dependencies. Maybe pare them back. javafx-graphics might be all you need. – John Williams Mar 11 '23 at 06:24
  • Yeah, I've got all but the base one commented out, maybe I'll do the graphics one for entertainment purposes. Granted, this is an enterprise project and it will need to move out of Tomcat very quickly. Title - definitely, I'll update it - talk about a unique combination of things for one on SO; and I'll make a post over the weekend sometime about the tuned version. Thanks again! – epicUsername Mar 11 '23 at 06:30