0

There is a SpringBoot & JPA based web project developed in Intellij IDEA. It can be run in IDEA debugger correctly, but when packaged with gradle using plugin shadow (com.github.johnrengelman.shadow) and run in local console, it causes an exception below:

...
09:17:29.462 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sessionFactory' defined in com.zccxy.zcmapservicejava.ZcmmServiceJavaApplication: Unsatisfied dependency expressed through method 'sessionFactory' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.hibernate.ejb.HibernateEntityManagerFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
        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:953)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:745)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:420)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1317)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
        at com.zccxy.zcmapservicejava.ZcmmServiceJavaApplication.main(ZcmmServiceJavaApplication.java:53)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.hibernate.ejb.HibernateEntityManagerFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1799)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1355)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
        ... 18 common frames omitted

Sometimes it causes an exception like below:

...
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'concreteRepository' defined in com.zccxy.zcmapservicejava.domain.meta.ConcreteRepository defined in @EnableJpaRepositories declared on ZcmmServiceJavaApplication: Cannot create inner bean '(inner bean)#6731787b' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#6731787b': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:389)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:134)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1707)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1452)
        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:934)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:745)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:420)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1317)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
        at com.zccxy.zcmapservicejava.ZcmmServiceJavaApplication.main(ZcmmServiceJavaApplication.java:54)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#6731787b': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:693)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:510)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
        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.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:374)
        ... 18 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:872)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1344)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
        ... 26 common frames omitted

I considered that maybe causes by dependency version,but modify it makes no sense.

build.gradle file below:

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This project uses @Incubating APIs which are subject to change.
 */

buildscript {
    repositories {
        maven { url 'https://repo.spring.io/libs-milestone' }
    }

    dependencies {
        classpath 'org.springframework.boot:spring-boot-gradle-plugin:2.6.8'
    }
}

plugins {
    id 'java'
    id 'maven-publish'
    id "com.github.johnrengelman.shadow" version "7.1.2"
//    id "org.springframework.boot.spring-boot-gradle-plugin"
}


repositories {
    mavenLocal()
    maven {
        url = uri('https://repo.spring.io/release')
    }
    maven {
        url = uri('https://repo.maven.apache.org/maven2/')
    }
    maven {
        url = uri("https://plugins.gradle.org/m2/")
    }
}

ext{
    sourceCompatibility = 1.8
}

dependencies {
//    implementation 'org.springframework.boot:spring-boot-starter:2.6.8'
//// https://mvnrepository.com/artifact/io.lettuce/lettuce-core
//    implementation 'io.lettuce:lettuce-core:6.1.8.RELEASE'
//// https://mvnrepository.com/artifact/org.springframework.data/spring-data-keyvalue
//    testImplementation 'org.springframework.data:spring-data-keyvalue:2.6.4'
//// https://mvnrepository.com/artifact/org.springframework/spring-context-support
//    implementation 'org.springframework:spring-context-support:5.3.20'
//// https://mvnrepository.com/artifact/org.springframework/spring-oxm
//    implementation 'org.springframework:spring-oxm:5.3.20'

    implementation "org.springframework.boot:spring-boot-starter-data-redis:${SPRING_BOOT_VERSION}"
    implementation "org.springframework.boot:spring-boot-starter-data-jpa:${SPRING_BOOT_VERSION}"
    implementation "org.springframework.boot:spring-boot-starter-data-rest:${SPRING_BOOT_VERSION}"
    implementation "org.springframework.boot:spring-boot-configuration-processor:${SPRING_BOOT_VERSION}"
    implementation "org.springframework.boot:spring-boot-gradle-plugin:${SPRING_BOOT_VERSION}"
    implementation "org.springdoc:springdoc-openapi-ui:${SPRINGDOC_VERSION}"
    implementation "org.springdoc:springdoc-openapi-native:${SPRINGDOC_VERSION}"
    implementation "mysql:mysql-connector-java:${MYSQL_CONNECTOR_VERSION}"
    implementation "redis.clients:jedis:${JEDIS_VERSION}"
    implementation "com.alibaba:fastjson:${FASTJSON_VERSION}"

    compileOnly "org.projectlombok:lombok:${LOMBOK_VERSION}"
    annotationProcessor "org.projectlombok:lombok:${LOMBOK_VERSION}"
}

apply plugin: "com.github.johnrengelman.shadow"
apply plugin: 'java'
//apply plugin: 'org.springframework.boot'

tasks.withType(JavaCompile){
    options.encoding = "GBK"
}

group = 'com.zccxy'
version = '0.0.1-SNAPSHOT'
description = 'ZCMMServiceJava'
java.sourceCompatibility = JavaVersion.VERSION_1_8

publishing {
    publications {
        maven(MavenPublication) {
            from(components.java)
        }
    }
}

tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

shadowJar{
    manifest {
        attributes(
                'Main-Class': 'com.zccxy.zcmapservicejava.ZcmmServiceJavaApplication'
        )
    }
}

gradle.properties file below:

SPRING_BOOT_VERSION=2.6.8
SPRINGDOC_VERSION=1.6.6
LOMBOK_VERSION=1.18.22
MYSQL_CONNECTOR_VERSION=8.0.29
JEDIS_VERSION=4.1.1
FASTJSON_VERSION=1.2.79
Apostolos
  • 10,033
  • 5
  • 24
  • 39
  • Use the `spring-boot` plugin not the shadow plugin> Spring Boot has a special plugin to generate the fat jar. – M. Deinum Jun 01 '22 at 07:34

1 Answers1

0

It's not unlikely to be a problem caused by the Shadow Plugin, it has a hurdle: You have to tell it how to handle file collisions, i.e. files with the same name. I use it with Gradle Kotlin DSL like:


tasks.withType<ShadowJar> {
    mergeServiceFiles()
    append("META-INF/spring.handlers")
    append("META-INF/spring.schemas")
    append("META-INF/spring.tooling")
    transform(
        PropertiesFileTransformer().apply {
            paths = mutableListOf("META-INF/spring.factories")
            mergeStrategy = "append"
        })
}

It doesn't tell in its current version when a file conflict occurs, so you have to waste big amounts of time finding the conflicts yourself. But there is a pull request that it tells if there is a collision: https://github.com/johnrengelman/shadow/pull/773. Until the pull request gets merged you could use the forked branch to be always informed about file collisions: https://github.com/JD-CSTx/shadow/tree/chapmajs-collision_logging.

Maybe I'm guessing wrong, and your problem is caused by something else, but this looks definitely like it could come from file collisions.

Jan
  • 1,032
  • 11
  • 26
  • Spring Boot has a specialized loader, only merging the `spring.factories` won't help. – M. Deinum Jun 13 '22 at 08:12
  • @M.Deinum No, merging is 100% enough. It works. Only thing is, there is maybe more than one service to merge, in one project I have to use for the append part: `append("META-INF/additional-spring-configuration-metadata.json") append("META-INF/spring-autoconfigure-metadata.properties") append("META-INF/spring-configuration-metadata.json") append("META-INF/spring.factories") append("META-INF/spring.handlers") append("META-INF/spring.schemas") append("META-INF/spring.tooling")`. The added file collision warnings help identifying those files. – Jan Jun 13 '22 at 13:02
  • No it isn't, not with Spring Boot as it has a specialized loader. So no it isn't enough. Unless you want to user to also work around that... Just use the Spring Boot Plugin as recommended instead of trying to reinvent the wheel. – M. Deinum Jun 13 '22 at 14:01
  • @M.Deinum I use _standard_ Spring Boot, no hacks, I use the Shadow Plugin because the Spring Boot plugin did **not** work. Tried now again, since you insist, after many new Spring versions, now it works. I will still use the Shadow Plugin, since the JARs are in total 2% smaller and have no unwanted duplicates. This solution works a while now, without any loading problems. Although, for WAR files (Web-Archives), we use the Spring-Boot plugin. But for JPA / Hibernate, the Shadow Plugin works great. – Jan Jun 13 '22 at 15:21
  • @M.Deinum The Gradle Shadow plugin is on the list of official Spring-Boot Fat JAR alternatives: https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html#appendix.executable-jar.alternatives – Jan Jun 14 '22 at 07:48
  • Good for you. My experience with various projects is very different and required a fair amount of workarounds and hacks to get it to fully and reliably to work. I prefer to stick with the defaults instead of trying to figure out how to work around those. I've used the Spring Boot plugin since boot 0.9 without any issues, where as I had numerous issues with the shadow plugin (without all the hacks/workarounds to get different jars to work, it gets especially fun with signed jars and crypto libraries). – M. Deinum Jun 14 '22 at 08:43