Parameter 0 of constructor in 'y' required a bean of type 'x' that could not be found - spring

try to create a simple crud api using spring boot kotlin but keep getting this error 'Parameter 0 of constructor in com.example.demo.service.CustomerService required a bean of type 'com.example.demo.repository.CustomerRepository' that could not be found.'
this is my directory structure
directory structure (https://i.stack.imgur.com/gw9Fp.png)
this is my model/customerModel.kt file
package com.example.demo.model
import java.util.Date
import javax.persistence.Id
data class CustomerModel (
#Id
val customerId : Int,
val customerName : String,
val customerBirthDate : Date,
) {
}
this is my repository
package com.example.demo.repository
import com.example.demo.model.CustomerModel
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository
#Repository
interface CustomerRepository : CrudRepository<CustomerModel, Int> {
}
this is my service
package com.example.demo.service
import com.example.demo.model.CustomerModel
import com.example.demo.repository.CustomerRepository
import org.springframework.stereotype.Service
#Service
class CustomerService (val customerRepository: CustomerRepository)
{
fun getAllCustomers(): List<CustomerModel> = customerRepository.findAll().toList()
}
this is my controller
package com.example.demo.controller
import com.example.demo.Message
import com.example.demo.model.CustomerModel
import com.example.demo.service.CustomerService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
#RestController
#RequestMapping("/api/v1")
class CustomerController (val customerService: CustomerService){
#GetMapping("/customers")
fun getAllCustomer() : List<CustomerModel>
{
return customerService.getAllCustomers()
}
}
this is my application.properties
## use create when running the app for the first time
## then change to "update" which just updates the schema when necessary
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
spring.datasource.url= jdbc:oracle:thin:#localhost:1521:XE
spring.datasource.username=SYS
spring.datasource.password=*********
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
## this shows the sql actions in the terminal logs
spring.jpa.show-sql=true
i start to run the code but always get this error
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.demo.service.CustomerService required a bean of type 'com.example.demo.repository.CustomerRepository' that could not be found.
Action:
Consider defining a bean of type 'com.example.demo.repository.CustomerRepository' in your configuration.
Process finished with exit code 1
i try googling and most i found usually missing annotation or the component is not scanned by the application but it's still not working. this is my first time using kotlin and spring boot so i have no idea how to solve this

Related

Spring injects a bean other than what is specified in #Configuration

Recently I've made an error while wiring beans in Spring that caused a behaviour that I'm unable to replicate. Instead of a property sourced with #Value getting injected into Stuff (see the complete demo code below) a value of another bean of type String defined in #Configuration was used when the application was deployed.
What I find puzzling is that everything works as expected when running locally (including the unit test), the output is foo not kaboom, and that this 'bean swap' happened at all when deployed rather than 'no qualifying bean' error.
The commented out line shows the fix which I think makes the configuration similar to what is in the manual.
What is the problem with my set-up? What would make the code as shown (i.e. without the fix) use kaboom String rather than foo property?
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
#SpringBootApplication
open class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
#Configuration
open class Config {
// ...beans of types other than String in original code...
#Bean
open fun beanBomb(): String {
return "kaboom"
}
#Bean
// fix:
// #Value("\${stuff}")
open fun beanStuff(stuff: String): Stuff {
return Stuff(stuff)
}
}
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
#Component
class Stuff(#Value("\${stuff}") val stuff: String)
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import javax.annotation.PostConstruct
#Component
class Init {
#Autowired
private lateinit var stuff: Stuff
#PostConstruct
fun init() {
println("stuff: " + stuff.stuff)
}
}
// application.properties
stuff=foo
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
#TestPropertySource(properties = {"stuff=testFoo"})
class DemoApplicationTests {
#SpyBean
private Stuff stuff;
#Test
void test() {
assertEquals("testFoo", stuff.getStuff());
}
}
Also, is the #Value annotation in Stuff necessary once the fix has been applied? If I uncomment the fix, remove #Value from Stuff and add the following annotation to the test class the test passes:
#ContextConfiguration(classes = {Config.class})
but when I run the app it prints kaboom...
You can check the order in which the bean is being created. if the bean is created before than in my view the Spring IoC container inject the value by type i.e. kaboom and since the Bean of any type is singleton by default, the instance of Stuff won't come into effect even though it is annotated with #component.
In your test you're loading the configuration manually where the bean of Stuff defined in Config is being injected not the Stuff annotated with #component.
The problem is the annotation needs to go on the parameter not the function.
In your way Spring is looking for a bean that meets the Type of String and there is a bean of Type String produced by the function beanBomb(). If you move the annotation like this it should remove the ambiguity.
#Bean
open fun beanStuff(#Value("\${stuff}") stuff: String): Stuff {
return Stuff(stuff)
}
I would add tho, that it's a bit unusual to have a bean of Type String, but I suppose if you don't want to use property/yaml files it would allow you to change a String based on profile.

#RestControllerAdvice not scanned

i have looked at 5 tutorials; more than 10 stackoverflow or similar answers but i still haven't resolved that (apparently common) problem.
All i want to achieve is to set a custom JSON upon when exception are thrown on my API. But the Controller advice is never even instantiated (watch breakpoint never crossed.)
Here are the relevant files:
Main class:
package com.bancarelvalentin.plaxdmin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
#SpringBootApplication(scanBasePackages = ["com.bancarelvalentin.*"])
class Main
fun main(args: Array<String>) {
runApplication<Main>(*args)
}
Sample controller:
package com.bancarelvalentin.plaxdmin.controller
import com.bancarelvalentin.plaxdmin.playground.CustomException
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
#RestController
#RequestMapping("/")
class DummyCtrl : PlController() {
#GetMapping
fun throwError(): ResponseEntity<Any> {
throw CustomException()
}
}
Error handler:
package com.bancarelvalentin.plaxdmin.playground;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice;RestControllerAdvice
import org.springframework.web.servlet.configjava.annotationlang.EnableWebMvc;Exception
#RestControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler
public Exceptionfun handleException(Exception ce: Exception): Exception {
return ce;
}
}
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/plaxdmin
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update
Here is what i tried:
Adding other anotation to the main and/or the ErrorHandler class (#EnableWebMvc, #Component, some others i don't remember)
Putting the 3 above files in the same package
turning in and off the white label page
add a scanBasePackages attributes in my main class annotaation

How to resolve javax.enterprise.inject.IllegalProductException when using JPA repository

I am getting exception when calling findAll method on CrudRepository in quarkus - based code.
Here is my database configuration.
quarkus.datasource.url = jdbc:postgresql://localhost:5432/postgres
quarkus.datasource.driver = org.postgresql.Driver
quarkus.datasource.username = ZZZZ
quarkus.datasource.password = XXX
Here is repository code.
import org.springframework.data.repository.CrudRepository;
public interface FruitRepository extends CrudRepository<FruitEntity, Integer> {
}
Here is client code.
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
#Path("/fruitz")
public class FruitController {
#Inject
FruitRepository fruitRepository;
#GET
#Produces("application/json")
public Iterable<FruitEntity> findAll() {
return fruitRepository.findAll();
}
}
I am getting following exception.
Caused by: javax.enterprise.inject.IllegalProductException: Normal scoped producer method may not return null: io.quarkus.agroal.runtime.DataSourceProducer.createDefaultDataSource()
at io.quarkus.agroal.runtime.DataSourceProducer_ProducerMethod_createDefaultDataSource_7c487e3ef869f878aa871e917c94f4d26d5d5c56_Bean.create(DataSourceProducer_ProducerMethod_createDefaultDataSource_7c487e3ef869f878aa871e917c94f4d26d5d5c56_Bean.zig:306)
at io.quarkus.agroal.runtime.DataSourceProducer_ProducerMethod_createDefaultDataSource_7c487e3ef869f878aa871e917c94f4d26d5d5c56_Bean.create(DataSourceProducer_ProducerMethod_createDefaultDataSource_7c487e3ef869f878aa871e917c94f4d26d5d5c56_Bean.zig:244)
at io.quarkus.arc.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:69)
at io.quarkus.arc.ComputingCache$CacheFunction.lambda$apply$0(ComputingCache.java:99)
at io.quarkus.arc.LazyValue.get(LazyValue.java:26)
at io.quarkus.arc.ComputingCache.getValue(ComputingCache.java:41)
at io.quarkus.arc.AbstractSharedContext.get(AbstractSharedContext.java:20)
at io.quarkus.agroal.runtime.DataSourceProducer_ProducerMethod_createDefaultDataSource_7c487e3ef869f878aa871e917c94f4d26d5d5c56_ClientProxy.arc$delegate(DataSourceProducer_ProducerMethod_createDefaultDataSource_7c487e3ef869f878aa871e917c94f4d26d5d5c56_ClientProxy.zig:152)
at io.quarkus.agroal.runtime.DataSourceProducer_ProducerMethod_createDefaultDataSource_7c487e3ef869f878aa871e917c94f4d26d5d5c56_ClientProxy.getConnection(DataSourceProducer_ProducerMethod_createDefaultDataSource_7c487e3ef869f878aa871e917c94f4d26d5d5c56_ClientProxy.zig:23)
You have to annotate your interface with #Named to make it available for injection. Also ensure to have quarkus-jdbc-postgresql added as a dependency.

Spring data repository not found at compile time

I am trying to use Spring data and repositories in a Spring Boot application, but I have an error when compiling the project.
Here is my Entity :
package fr.investstore.model;
import javax.persistence.Id;
...
#Entity
public class CrowdOperation {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Long id;
#Enumerated(EnumType.STRING)
public RepaymentType repaymentType;
...
}
And the corresponding Repository:
package fr.investstore.repositories;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import fr.investstore.model.CrowdOperation;
public interface CrowdOperationRepository extends CrudRepository<CrowdOperation, Long> {
}
I use it in a WS controller, generating a repository through the Autowired annotation:
package fr.investstore.ws;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
...
#Controller
#EnableAutoConfiguration
public class SampleController {
#Autowired
private CrowdOperationRepository crowdOperationRepository;
#RequestMapping(path = "/", method = RequestMethod.GET)
#ResponseBody
public String getOperations(#RequestParam(required=true, defaultValue="Stranger") String name) {
crowdOperationRepository.save(new CrowdOperation());
return "Hello " + name;
}
}
And the code of the application:
package fr.investstore;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import fr.investstore.ws.SampleController;
#SpringBootApplication
public class InvestStoreApplication {
public static void main(String[] args) {
SpringApplication.run(SampleController.class, args);
}
}
But when compiling the project I get:
APPLICATION FAILED TO START
Description: Field crowdOperationRepository in
fr.investstore.ws.SampleController required a bean of type
'fr.investstore.repositories.CrowdOperationRepository' that could not
be found.
Action: Consider defining a bean of type
'fr.investstore.repositories.CrowdOperationRepository' in your
configuration.
Woudn't Spring automatically generate a bean for the repository through the interface?
How can I resolve this?
EDIT: I also tried to put the Repository annotation (from org.springframework.stereotype.Repository) onto CrowdOperationRepository, but I got the same error
While creating a spring-boot application, we need to keep some point in our mind like
Always keep main class (class with `#SpringBootApplication annotation) on the top level package and other classes should lie under sub-packages.
Always mark your bean classes with proper annotation e.g. all repositories should be marked by #Repository annotation, all service implementation classes should be marked with #Service, other component classes should be marked by #Component, class which defines our beans should be marked as #Configuration
Enable the feature which you are using e.g. #EnableJpaRepositories, #EnableTransactionManagement, #EnableJpaAuditing, these annotations also provides functionality which let us define which package spring needs to scan.
So in your case, you need to mark InvestStoreApplication class with #EnableJpaRepositories annotation and CrowdOperationRepository with #Repository.
you have to tell your spring boot application to load JPA repositories.
copy this one to your application class
it will auto-scan your JPA repository and load it in your spring container even if you do not define your interface with #Repository it will wire that bean in your dependent class.
#EnableJpaRepositories(basePackages = { "fr.investstore.repositories" })
Thank to #JBNizet for his comment, that made it working.
I create this answer since he did not:
Replace SpringApplication.run(SampleController.class, args); with SpringApplication.run(InvestStoreApplication.class, args);. And remove the useless #EnableAutoConfiguration on your controller.
Annotating your entity class as shown as spring hint below to allow spring get a valid repository bean
Spring Data JPA - Could not safely identify store assignment for repository candidate interface com.xxxxx.xxxxRepository.
If you want this repository to be a JPA repository, consider annotating your entities with one of these annotations: javax.persistence.Entity, javax.persistence.MappedSuperclass (preferred),
or consider extending one of the following types with your repository: org.springframework.data.jpa.repository.JpaRepository.
2022-05-06 12:32:12.623 [ restartedMain] INFO [.RepositoryConfigurationDelegate:201 ] - Finished Spring Data repository scanning in 3 ms. Found 0 JPA repository interfaces.

Spring cannot serve end point

I have a simple Spring back-end. It has a folder that contains controllers.
package com.movieseat.controllers;
// Java imports
import java.util.List;
// Spring imports
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
// Project imports
import com.movieseat.models.Movie;
import com.movieseat.services.MovieService;
#RestController
#RequestMapping("/api/movies")
public class MovieController {
#Autowired
private MovieService movieService;
#RequestMapping(value = "/allMovies", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<Movie> getAllMovies() {
return movieService.getAllmovies();
}
}
In my Angular service I have a getAll() method:
public getAll<T>(): Observable<T[]> {
return this.http.get<T[]>('/api/movies/allMovies');
}
When I run the application I get a:
GET http://localhost:8090/api/movies/allMovies 404 ()
I have the server running on port 8090.
The following structure is used:
com
movieseat
Application.java
controllers
MovieController.java
models
MovieModel.java
repositories
MovieRepository.java
services
impl
MovieServiceImpl.java
MovieService.java
See if your controller class is picked up by spring scanning and performs mapping correctly. For example - If you are using Spring Boot, put a #SpringBootApplication on your main class that runs the app. The best way to know if your endpoint is scanned is to look for it when spring launches (in the log). You should look for something like
2017-09-17 14:45:49.522 INFO 2873 --- [main] RequestMappingHandlerMapping : Mapped "{[/allMovies],methods=[GET]}" onto public java.lang.String com.movieseat.controllers.MovieController.getAllMovies...

Resources