Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-11409

Spring Boot JPA Repository Class is not autowired in Groovy

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Open
    • Critical
    • Resolution: Unresolved
    • 4.0.21
    • None
    • None
    • None
    • linux

    Description

      I have a code that works in java. its sample spring-boot application:

       

      package com.example.demo;
      
      import lombok.Getter;
      import lombok.Setter;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.boot.context.event.ApplicationReadyEvent;
      import org.springframework.context.event.EventListener;
      import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
      import org.springframework.data.repository.CrudRepository;
      import org.springframework.stereotype.Repository;
      import org.springframework.transaction.annotation.Isolation;
      import org.springframework.transaction.annotation.Transactional;
      
      import javax.persistence.*;
      
      @SpringBootApplication
      @EnableJpaRepositories(considerNestedRepositories = true)
      @Slf4j
      public class DemoApplication {
      
      
          @Getter @Setter
          @Entity
          @Table(name = "record")
          public static class Record {
             @Id
             @GeneratedValue(strategy = GenerationType.IDENTITY)
             private long id;
             private String data;
          }
          @Repository
          @Transactional(isolation = Isolation.SERIALIZABLE)
          interface RecordRepository extends CrudRepository<Record, Long> {
          }
      
          @Autowired
          private DemoApplication.RecordRepository recordRepository;
      
          @EventListener(ApplicationReadyEvent.class)
          public void ready() {
             Iterable<DemoApplication.Record> all = recordRepository.findAll();
             if (all.iterator().hasNext()) {
                throw new IllegalStateException("There should be no records");
             }
             recordRepository.save(new DemoApplication.Record());
             all = recordRepository.findAll();
             if (!all.iterator().hasNext()) {
                throw new IllegalStateException("There should be records");
             }
             log.info("All good");
          }
      
          public static void main(String[] args) {
             SpringApplication.run(DemoApplication.class, args).close();
          }
      
      }
       

      And its property file (application.yaml):

       

       

      server:
        port: 8080
      
      spring:
        sql:
          init:
            platform: sqlite
            mode: always
        datasource:
          url: "jdbc:sqlite::memory:"
          username:
          password:
          driver-class-name: org.sqlite.JDBC
        jpa:
          database-platform: org.sqlite.hibernate.dialect.SQLiteDialect
          show-sql: false
          defer-datasource-initialization: true
          hibernate:
            ddl-auto: create
            jdbc:
              time_zone: UTC
          open-in-view: false
       

       

       

      Running it works as expected, "All good" is shown into console.

      After converting the same code to groovy this code fail. The error is: 

       

      No qualifying bean of type 'com.example.demo2.DemoApplication$RecordRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
       

      So, the spring is not seeing static nested class IF it is in groovy. 

       

      This is the groove code I run:

       

      package com.example.demo2
      @GrabConfig
      @Grab(group = 'org.springframework.boot', module = 'spring-boot-starter-web', version = '2.7.18')
      @Grab(group = 'org.xerial', module = 'sqlite-jdbc', version = '3.45.3.0')
      @Grab(group = 'org.springframework.boot', module = 'spring-boot-starter-data-jpa', version = '2.7.18')
      
      @Grab(group = 'com.github.gwenn', module = 'sqlite-dialect', version = "0.1.4")
      @Grab(group = 'jakarta.persistence', module = 'jakarta.persistence-api', version = '2.2.2')
      @GrabExclude(group = 'javax.persistence', module='javax.persistence-api')
      @Grab(group = 'org.jboss.spec.javax.transaction', module = 'jboss-transaction-api_1.2_spec', version = '1.1.1.Final')
      @GrabExclude(group = 'org.jboss.spec.javax.transaction', module='jboss-transaction-api_1.2_spec')
      @Grab(group = 'jakarta.transaction', module = 'jakarta.transaction-api', version = '1.3.1')
      @Grab(group = 'com.zaxxer', module = 'HikariCP', version = '5.1.0')
      @Grab(group='org.slf4j', module='slf4j-simple', version='2.0.13')
      @Grab(group='org.slf4j', module='slf4j-api', version='2.0.13')
      @Grab(group='cglib', module='cglib', version='3.2.4')
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.boot.context.event.ApplicationReadyEvent
      import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
      import org.springframework.data.repository.CrudRepository;
      import org.springframework.stereotype.Repository;
      import org.springframework.transaction.annotation.Isolation;
      import org.springframework.transaction.annotation.Transactional
      import org.springframework.context.event.EventListener
      
      import javax.persistence.Entity
      import javax.persistence.GeneratedValue
      import javax.persistence.GenerationType
      import javax.persistence.Id
      import javax.persistence.Table
      
      @SpringBootApplication
      @EnableJpaRepositories(considerNestedRepositories = true)
      class DemoApplication {
      
          @Entity
          @Table(name = "record")
          static class Record {
              @Id
              @GeneratedValue(strategy = GenerationType.IDENTITY)
              private long id
              private String data
          }
          @Repository
          @Transactional(isolation = Isolation.SERIALIZABLE)
          interface RecordRepository extends CrudRepository<Record, Long> {
          }
      
          @Autowired
          private DemoApplication.RecordRepository recordRepository;
      
          @EventListener(ApplicationReadyEvent.class)
          void ready() {
              Iterable<DemoApplication.Record> all = recordRepository.findAll();
              if (all.iterator().hasNext()) {
                  throw new IllegalStateException("There should be no records");
              }
              recordRepository.save(new DemoApplication.Record());
              all = recordRepository.findAll();
              if (!all.iterator().hasNext()) {
                  throw new IllegalStateException("There should be records");
              }
              System.out.println("All good");
          }
      
          static void main(String[] args) {
              SpringApplication.run(DemoApplication.class, args).close();
          }
      } 

       

      I run it with this script:

       

      #!/bin/env bash
      groovy -version
      java -version
      cd groovy && groovy src/com/example/demo2/DemoApplication.groovy --spring.config.location=application.yaml 

      Ans this is output (boht java case and groovy case):

       

       

      ✔ nb6:~/work/bugreport> ./run_java.sh 
      [INFO] Scanning for projects...
      [INFO] 
      [INFO] --------------------------< com.example:demo >--------------------------
      [INFO] Building demo 0.0.1-SNAPSHOT
      [INFO] --------------------------------[ jar ]---------------------------------
      [INFO] 
      [INFO] --- exec-maven-plugin:3.3.0:java (default-cli) @ demo ---  .   ____          _            __ _ _
       /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
      ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
       \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
        '  |____| .__|_| |_|_| |_\__, | / / / /
       =========|_|==============|___/=/_/_/_/
       :: Spring Boot ::               (v2.7.18)2024-06-16 02:47:55.694  INFO 71733 --- [lication.main()] com.example.demo.DemoApplication         : Starting DemoApplication using Java 17 on nb6 with PID 71733 (/home/msangel/work/bugreport/java/target/classes started by msangel in /home/msangel/work/bugreport/java)
      2024-06-16 02:47:55.697  INFO 71733 --- [lication.main()] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
      2024-06-16 02:47:56.092  INFO 71733 --- [lication.main()] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
      2024-06-16 02:47:56.126  INFO 71733 --- [lication.main()] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 26 ms. Found 1 JPA repository interfaces.
      2024-06-16 02:47:56.512  INFO 71733 --- [lication.main()] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
      2024-06-16 02:47:56.551  INFO 71733 --- [lication.main()] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.6.15.Final
      2024-06-16 02:47:56.685  INFO 71733 --- [lication.main()] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
      2024-06-16 02:47:56.755  INFO 71733 --- [lication.main()] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.sqlite.hibernate.dialect.SQLiteDialect
      2024-06-16 02:47:56.793  INFO 71733 --- [lication.main()] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
      2024-06-16 02:47:56.927  INFO 71733 --- [lication.main()] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
      2024-06-16 02:47:56.935  INFO 71733 --- [lication.main()] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.sqlite.hibernate.dialect.SQLiteDialect
      2024-06-16 02:47:57.377  INFO 71733 --- [lication.main()] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
      2024-06-16 02:47:57.388  INFO 71733 --- [lication.main()] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
      2024-06-16 02:47:57.724  INFO 71733 --- [lication.main()] com.example.demo.DemoApplication         : Started DemoApplication in 2.489 seconds (JVM running for 4.638)
      2024-06-16 02:47:57.874  INFO 71733 --- [lication.main()] com.example.demo.DemoApplication         : All good
      2024-06-16 02:47:57.877  INFO 71733 --- [lication.main()] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
      2024-06-16 02:47:57.879  INFO 71733 --- [lication.main()] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
      2024-06-16 02:47:57.882  INFO 71733 --- [lication.main()] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time:  3.851 s
      [INFO] Finished at: 2024-06-16T02:47:57+02:00
      [INFO] ------------------------------------------------------------------------
      ✔ nb6:~/work/bugreport> ./run_groovy.sh 
      Groovy Version: 4.0.21 JVM: 17 Vendor: Oracle Corporation OS: Linux
      openjdk version "17" 2021-09-14
      OpenJDK Runtime Environment (build 17+35-2724)
      OpenJDK 64-Bit Server VM (build 17+35-2724, mixed mode, sharing)
      SLF4J(W): No SLF4J providers were found.
      SLF4J(W): Defaulting to no-operation (NOP) logger implementation
      SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.  .   ____          _            __ _ _
       /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
      ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
       \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
        '  |____| .__|_| |_|_| |_\__, | / / / /
       =========|_|==============|___/=/_/_/_/
       :: Spring Boot ::               (v2.7.18)Caught: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoApplication': Unsatisfied dependency expressed through field 'recordRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo2.DemoApplication$RecordRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
      org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoApplication': Unsatisfied dependency expressed through field 'recordRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo2.DemoApplication$RecordRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
          at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:713)
          at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:693)
          at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
          at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:408)
          at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431)
          at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619)
          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:929)
          at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:591)
          at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147)
          at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732)
          at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:409)
          at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
          at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300)
          at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289)
          at com.example.demo2.DemoApplication.main(DemoApplication.groovy:70)
      Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo2.DemoApplication$RecordRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1801)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1357)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1311)
          at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:710)
          ... 20 more
      ✘-1 nb6:~/work/bugreport> 
      

       

      Why the groovy version is not working with literally the same code?

       

      Attachments

        1. bugreport.7z
          11 kB
          msangel

        Activity

          People

            Unassigned Unassigned
            msangel msangel
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated: