Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot Multi Module with Data JPA Not Working

I have my multimodule spring boot project. I moved service, entity and repository to the core module and in the war module I have the controller alone.

What is the problem here? If I use without JPA, then my core module working fine. If I add JPA dependency in core module and injecting repository in my service then I get various errors like noclassdefinitionfound for repository, No qualifying bean of type Service etc.

How to make this application work?

parent pom.xml

<?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">

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <name>appx</name>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.imsx</groupId>
    <artifactId>appx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>core</module>
        <module>webx</module>
        <module>imsx</module>
    </modules>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <version.wildfly.maven.plugin>1.0.2.Final</version.wildfly.maven.plugin>
        <version.jboss.bom>8.2.1.Final</version.jboss.bom>
        <version.wildfly>14.0.1.Final</version.wildfly>
        <version.compiler.plugin>3.8.0</version.compiler.plugin>
        <version.ear.plugin>3.0.1</version.ear.plugin>
        <version.jar.plugin>3.1.1</version.jar.plugin>
        <version.war.plugin>3.2.2</version.war.plugin>

        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                    </configuration>
                    <version>${version.compiler.plugin}</version>
                </plugin>
                <plugin>
                    <groupId>org.wildfly.plugins</groupId>
                    <artifactId>wildfly-maven-plugin</artifactId>
                    <version>${version.wildfly.maven.plugin}</version>
                    <inherited>true</inherited>
                    <configuration>
                        <skip>true</skip>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

Below is my Ear module pom.

<?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>

    <parent>
        <artifactId>appx</artifactId>
        <groupId>org.imsx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>imsx</artifactId>
    <packaging>ear</packaging>

    <name>appx: EAR Module</name>

    <dependencies>
        <dependency>
            <groupId>org.imsx</groupId>
            <artifactId>webx</artifactId>
            <version>${project.version}</version>
            <type>war</type>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ear-plugin</artifactId>
                <version>${version.ear.plugin}</version>
                <configuration>
                    <version>7</version>
                    <defaultLibBundleDir>lib</defaultLibBundleDir>
                    <modules>
                        <webModule>
                            <groupId>org.imsx</groupId>
                            <artifactId>webx</artifactId>
                            <contextRoot>/imsx</contextRoot>
                            <bundleFileName>webx.war</bundleFileName>
                        </webModule>
                    </modules>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.wildfly.plugins</groupId>
                <artifactId>wildfly-maven-plugin</artifactId>
                <configuration>
                    <filename>${project.artifactId}.ear</filename>
                    <skip>false</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Here is my core module pom with JPA and mysql dependency.

<?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>

    <parent>
        <artifactId>appx</artifactId>
        <groupId>org.imsx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>core</artifactId>
    <packaging>jar</packaging>
    <name>appx: Core Module</name>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <scope>provided</scope> <!-- I tried by removing this provided scope as well and got different error in repository level like datasource is not found -->
            <exclusions>
                <exclusion>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-jdbc</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <version>${version.jar.plugin}</version><!--$NO-MVN-MAN-VER$ -->
            </plugin>
        </plugins>
    </build>

</project>

Finally I have my war module pom. I have included core module within it.

<?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>

    <parent>
        <artifactId>appx</artifactId>
        <groupId>org.imsx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>webx</artifactId>
    <packaging>war</packaging>

    <name>appx: WAR Module</name>

    <url>http://wildfly.org</url>
    <licenses>
        <license>
            <name>Apache License, Version 2.0</name>
            <distribution>repo</distribution>
            <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
        </license>
    </licenses>

    <dependencies>

        <dependency>
            <groupId>org.imsx</groupId>
            <artifactId>core</artifactId>
            <version>${project.version}</version>
            <type>jar</type>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

I have application.properties in core module, where I have specified my db connection.

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/bootear?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
spring.datasource.username = root
spring.datasource.password = root
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto = update

I don't have anything in the war module's property file.

Here are my Java Code:

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping(value="/test", method=RequestMethod.GET)
    public String test() {
        Optional<User> user = userService.findUserById(1);
        System.out.println(user.isPresent());
        return "Search Completed...";
    }
}


public interface UserService {
    Optional<User> findUserById(Integer id);
}


@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public Optional<User> findUserById(Integer id) {
        return userRepository.findById(id);
    }
}

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

}

If I have all these code within a single war module then it works fine. what is the issue here?

And I am deploying this EAR in wildfly server. It still not working and spoiled my 2 days of time.

like image 649
Shakthi Avatar asked Jan 26 '19 20:01

Shakthi


2 Answers

It happens because spring boot by default is looking for repositories only in the same package/sub-package of your class with @EnableAutoConfiguration (or @SpringBootApplication) annotation.

if you want to manually indicate where the repositories are located use @EnableJpaRepositories annotation and add appropriate basePackages value like this:

@SpringBootApplication(scanBasePackages = "com.xyz")
@EnableJpaRepositories(basePackages = "com.xyz")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

This way, spring boot will find your repositories even if they are in another module, you just need to stick to the naming convention of your packages.

More info about this is in spring docs (point 83.3):
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html

like image 87
Jakubeeee Avatar answered Jan 04 '23 00:01

Jakubeeee


The easiest way to handle it is to put module code in the same package naming as your main application resides in. Spring will automatically discover JPA Entities.

This can be seen in the image below, I have two modules, Server has JPA and the Application has only @SpringBootApplication from the spring initializer.

enter image description here

If you want to have different naming, then you should use @EnableJpaRepositories(basePackages = {"you.package.name1","you.package.name2"}) along with @SpringBootApplication.

like image 22
asadnwfp Avatar answered Jan 04 '23 01:01

asadnwfp