How to create a simple Spring Boot Library with a Database

85 views Asked by At

I'm trying to create a library using Spring Boot that has a database and will be used in another Spring Boot Application. I don't know what I'm doing wrong but is not working. I guess the problem is related to the autoconfiguration or the bean scanning.

These are my current files: My library is called "demo-lib" and has the following files:

User Entity:

package com.example.demolib;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private int age;

    // Constructor, getters and setters
}

UserRepository:

package com.example.demolib;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {

}

And finally I have a HelloWorldService with 3 basic methods:

package com.example.demolib;

import org.springframework.stereotype.Service;

@Service
public class HelloWorldService {

    private final UserRepository userRepository;

    public HelloWorldService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    public String getHelloMessage() {
        return "Hello World!";
    }

    public User storeUser() {
        User user = new User("John", 30);
        return userRepository.save(user);
    }
    public User getUser(Long id) {
        return userRepository.findById(id).orElseThrow();
    }
}

Now in my application project "timetreelib-integration" I have the following:

The main Spring Boot class with a @ComponentScan to been able to inject my library beans:

package com.artelys.timetreelibintegration;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan({"com.example.demolib"})
public class TimetreelibIntegrationApplication {

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

}

The demo-lib dependency in my pom.xml

        <dependency>
            <groupId>com.example</groupId>
            <artifactId>demo-lib</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

An autoconfiguration registered in META-INF/spring.factories*

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.artelys.timetreelibintegration.autoconfiguration.HelloLibConfig

The configuration class were I'm defining the HelloWorldService bean that needs as parameter the UserRepository.

package com.artelys.timetreelibintegration.autoconfiguration;

import com.example.demolib.HelloWorldService;
import com.example.demolib.UserRepository;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HelloLibConfig {

    private final UserRepository userRepository;

    public HelloLibConfig(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Bean
    @ConditionalOnBean(UserRepository.class)
    public HelloWorldService helloWorldService() {
        return new HelloWorldService(userRepository);
    }
}


And a controller to with a simple endpoints to tests everything:

package com.artelys.timetreelibintegration.controller;

import com.example.demolib.HelloWorldService;
import org.springframework.web.bind.annotation.GetMapping;

public class HelloWorldController {
    private final HelloWorldService helloWorldService;

    public HelloWorldController(HelloWorldService helloWorldService) {
        this.helloWorldService = helloWorldService;
    }

    @GetMapping("/hello")
    public String timetreelib() {
        return helloWorldService.getHelloMessage();
    }

}

Now with this setup when I try to run the application project I get this error:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2024-01-31 16:13:36.950 ERROR 17696 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.example.demolib.HelloWorldService required a bean of type 'com.example.demolib.UserRepository' that could not be found.


Action:

Consider defining a bean of type 'com.example.demolib.UserRepository' in your configuration.


Process finished with exit code 1

I don't know if I'm doing something wrong...

I have to say that everything was working well when the library didn't have a Database.

I hope you can help me I can expand more on the information if needed.

Thanks in advance :)

1

There are 1 answers

0
Víctor Cardozo On

Okay, I could find the solution. I will put it here in case this could be useful for someone.

I updated the TimetreelibIntegrationApplication main class and added 2 annotations.

@EnableJpaRepositories : To have access to the library repositories

@EntityScan : To have access to library entities (that are used by the library)

It seems to work fine :D This is how I have my application main class.

package com.artelys.timetreelibintegration;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories({"com.example.demolib"})
@EntityScan({"com.example.demolib"})
public class TimetreelibIntegrationApplication {

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

}


As an extra note, I have to say that the spring.factories file is not doing anything. I tried to remove this file and my autoconfiguration and everything is still working without problems.