[
https://issues.apache.org/jira/browse/GROOVY-11409?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
msangel updated GROOVY-11409:
-----------------------------
Attachment: bugreport.7z
> Spring Boot JPA Repository Class is not autowired in Groovy
> -----------------------------------------------------------
>
> Key: GROOVY-11409
> URL: https://issues.apache.org/jira/browse/GROOVY-11409
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 4.0.21
> Environment: linux
> Reporter: msangel
> Priority: Critical
> Attachments: bugreport.7z
>
>
> I have a code that works in java. its sample spring-boot application:
>
> {code:java}
> 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();
> }
> }
> {code}
> And its property file (application.yaml):
>
>
> {code:java}
> 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
> {code}
>
>
> Running it works as expected, "All good" is shown into console.
> After converting the same code to groovy this code fail. The error is:
>
> {code:java}
> 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)}
> {code}
> So, the spring is not seeing static nested class IF it is in groovy.
>
> This is the groove code I run:
>
> {code:java}
> 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");
> }
> log.info("All good");
> }
> static void main(String[] args) {
> SpringApplication.run(DemoApplication.class, args).close();
> }
> } {code}
>
> I run it with this script:
>
> {code:java}
> #!/bin/env bash
> groovy -version
> java -version
> cd groovy && groovy src/com/example/demo2/DemoApplication.groovy
> --spring.config.location=application.yaml {code}
> Ans this is output (boht java case and groovy case):
>
>
> {code:java}
> ✔ 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]
> ------------------------------------------------------------------------{code}
> {code:java}
> ✔ 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>
> {code}
>
> Why the groovy version is not working with literally the same code?
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)