Beans instantiation error when starting my Tomcat server. The failing Bean refers to a Repository class which is an interface

Viewed 499

Following is the Error I get on Tomcat server startup. Mine is a Java Maven project that uses Spring boot to implement REST API that interacts with Postgres DB using its JPA/Hibernate capability. Based on my understanding, during startup Spring boot will generate the implementation class for the interface causing the issue but that does not seem to be happening

SEVERE: Exception sending context initialized event to listener instance of class [org.springframework.web.context.ContextLoaderListener]
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.ibm.fda.splfhirpoc.audit.SubmissionService#0': Unsatisfied dependency expressed through field 'submissionRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.ibm.fda.splfhirpoc.audit.SubmissionRepository#0' defined in ServletContext resource [/WEB-INF/beans.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ibm.fda.splfhirpoc.audit.SubmissionRepository]: Specified class is an interface
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1415)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:608)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:531)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$108/0x0000000000000000.getObject(Unknown Source)
    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:944)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:923)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:588)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:401)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:292)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:103)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4716)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5177)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:843)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:434)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:772)
    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.catalina.startup.Bootstrap.start(Bootstrap.java:342)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:473)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.ibm.fda.splfhirpoc.audit.SubmissionRepository#0' defined in ServletContext resource [/WEB-INF/beans.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ibm.fda.splfhirpoc.audit.SubmissionRepository]: Specified class is an interface
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1318)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1216)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:571)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:531)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$108/0x0000000000000000.getObject(Unknown Source)
    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.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
    ... 46 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ibm.fda.splfhirpoc.audit.SubmissionRepository]: Specified class is an interface
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:70)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1310)
    ... 58 more

Following is 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 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!-- Make it a Sprint Boot application -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ibm.fda.spltofhir</groupId>
    <artifactId>SplToFhirService</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>SplToFhirService CXF JAX-RS webapp service using spring configuration</name>
    <description>SplToFhirService CXF JAX-RS webapp service using spring configuration</description>
    <properties>
        <jackson.version>1.9.1</jackson.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>2.15.14</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <!-- version>1.15</version-->
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-rs-client</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-core-asl</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>${jackson.version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <!-- version>2.12.1</version-->
        </dependency>

        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-jaxrs</artifactId>
            <version>${jackson.version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <!-- version>2.12.1</version-->
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <!--version>5.2.12.RELEASE</version-->
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <!-- version>5.2.12.RELEASE</version-->
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <!-- version>4.13.1</version-->
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <!-- version>2.14.0</version-->
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <!-- version>2.14.0</version-->
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk</artifactId>
            <version>1.11.943</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <!-- version>1.7.25</version-->
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>kms</artifactId>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>sqs</artifactId>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3control</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <!-- version>3.0.1</version-->
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <!-- version>42.2.18</version-->
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <!-- version>2.8.0</version-->
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <!-- version>2.9.0</version-->
        </dependency>
        <!-- Include HIbernate Library -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-commons -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-commons</artifactId>
            </dependency>
        <!-- To enable testing of Sprint boot application -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- To enable Production-grade Spring boot management services (such as health, audit, beans and more) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

    </dependencies>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-eclipse-plugin</artifactId>
                    <configuration>
                        <projectNameTemplate>[artifactId]-[version]</projectNameTemplate>
                        <wtpmanifest>true</wtpmanifest>
                        <wtpapplicationxml>true</wtpapplicationxml>
                        <wtpversion>2.0</wtpversion>
                    </configuration>
                </plugin>
                <!-- Include the Spring Boot Maven plugin to enable running of Spring boot application, 
                     generate build information and start your Spring Boot application prior to running integration tests. -->
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            
            </plugins>
        </pluginManagement>
    </build>
</project>

SubmissionController.java

package com.ibm.fda.splfhirpoc.audit;


import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/submission")
@EnableAutoConfiguration
public class SubmissionController {
    
    @Autowired
    private SubmissionService submissionService;

    @GetMapping("getAll")
    public ResponseEntity<List<Submission>> getAllSubmissions() {
        List<Submission> list = submissionService.getAllSubmissions();
 
        return new ResponseEntity<List<Submission>>(list, new HttpHeaders(), HttpStatus.OK);
    }
    
    @GetMapping("/{sub_id}")
    public ResponseEntity<Submission> getSubmissionBySubmissionID(@PathVariable(value = "sub_id") Long sub_id)
        throws ResourceNotFoundException {
        Submission submission = submissionService.getSubmissionByID(sub_id);
         
        return new ResponseEntity<Submission>(submission, new HttpHeaders(), HttpStatus.OK);
    }
    
    
    // POST method to create a submission
    @PostMapping("/create")
    public ResponseEntity<Submission> createSubmission(@Validated @RequestBody Submission submission)
            throws ResourceNotFoundException {
        Submission created = submissionService.createSubmission(submission);
        return new ResponseEntity<Submission>(created, new HttpHeaders(), HttpStatus.OK);
    }

}

SubmissionService.java

package com.ibm.fda.splfhirpoc.audit;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class SubmissionService {
    
    @Autowired
    private SubmissionRepository submissionRepository;

    public List<Submission> getAllSubmissions() {

        Iterable<Submission> it = submissionRepository.findAll();

        ArrayList<Submission> submissions = new ArrayList<Submission>();
        it.forEach(e -> submissions.add(e));

        return submissions;
    }
    
    public Submission getSubmissionByID(Long id) throws ResourceNotFoundException {
        
        Optional<Submission> submission = submissionRepository.findById(id);
        
        if (submission.isPresent()) {
            return submission.get();
        }
        else {
            throw new ResourceNotFoundException("No submission record exist for given id");
        }
        
        
    }
    
    public Submission createSubmission(Submission submission) throws ResourceNotFoundException {
        
        Submission mySubmission =  submissionRepository.save(submission);
        return mySubmission;
    }
    
}

SubmissionRepository.java

package com.ibm.fda.splfhirpoc.audit;

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

@Repository
public interface SubmissionRepository extends JpaRepository<Submission, Long> {

}

beans.xml file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <context:property-placeholder />
    <context:annotation-config />
    
    <bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer" />
    <bean class="com.ibm.fda.splfhirpoc.audit.SubmissionService" />
    <bean class="com.ibm.fda.splfhirpoc.audit.SubmissionRepository" />
    <jaxrs:server id="services" address="/">
        <jaxrs:serviceBeans>
            <bean class="com.ibm.fda.splfhirpoc.SplFhirPOCService"/>
            <bean class="com.ibm.fda.splfhirpoc.audit.AuditService"/>
            <bean class="com.ibm.fda.splfhirpoc.common.ValidationService"/>
            <bean class="com.ibm.fda.splfhirpoc.audit.SubmissionController"/>
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
            <bean class="com.ibm.fda.splfhirpoc.audit.ClientExceptionMapper" />
            <bean class="com.ibm.fda.splfhirpoc.audit.ServerExceptionMapper" />
            <bean class="com.ibm.fda.splfhirpoc.audit.ThrowableMapper" />
            <bean class="com.ibm.fda.splfhirpoc.audit.JsonMappingExceptionMapper" />
        </jaxrs:providers>
    
    </jaxrs:server>
    
</beans>
1 Answers

While working with Spring Boot, you don't need any beans.xml file. Make sure you annotated your main Application class with @SpringBootApplication (you haven't provided this class' code, so hard to guess how it looks like). Then Spring Boot engine will autoconfigure everything for you and find appropriate classes, assuming you annotate them properly, especially with @Entity (applying to Submission.class) and @Repository (already here).

Instead of declaring beans in and XML file, annotate other classes as @Service, @RestController (both already done), @Component and the beans declared within such classes (usually services or components) as @Bean. You'll be surprised how Sring Boot autoconfiguration could make use of those annotations and make your app working.

The simplified example of a working set of classes:

@SpringBootApplication
public class App() {
public static void main(String[] args) {        
    SpringApplication.run(App.class, args);
}
@Entity
public class Submission() {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // depending on your db policy
    private Long id;
    private someField;
    // getters, setters, Lombok's @Data very useful here
}
@Repository
public interface SubmissionRepository extends JpaRepository<Submission, Long>() {}
@Service
@Transactional    
public class SubmissionService() {
    private SubmissionRepository repository;
    @Autowired // avoid autowiring fields, as Spring folks say, autowire setters instead
    public setRepository(SubmissionRepository repository) {
        this.repository = repository;
    }
    // just an example
    public void saveSubmission(Submission: subbmission {
        repository.save(submission);
    }
    // all other logic here
}
@RestController("/submission") // or whatever endpoint your client uses
public class SubmissionController() {
    private SubmissionService service;
    @Autowired
    public setSubmissionService(Submission service) {
        this.service = service;
    }
    // example
    @PostMapping("/save")
    public void save(@RequestBody Submission submission) {
        service.saveSubmission(submission);
    }
    // other GET, POST methods here, annotated with @GetMapping, @PostMapping, @RequestMapping etc. 
}

Hope this is gonna help.

Related