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?