spring boot dependency injection - java

Im new to Spring, last couple of days I've been learning about it. Now Im trying to do something with it. It seems to me that with spring boot everything has changed.
There is no applicationContext file, I should use #Bean. Ok. In in tutorials the code is working, for me it fails. What did I miss?
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
the controller:
#RestController
public class GreetingController {
private final Test test;
#Autowired
public GreetingController(Test test){
this.test = test;
}
#RequestMapping("/greeting")
public String greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return "greeting" + test.getTest();
}
}
class Test {
public String getTest() {
return "tetst";
}
}
error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [hello.Test] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1301)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1047)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 18 more
I assume that bean has to be defined... But in tutorials there is no defenicion of bean.. Or I didnt see it.

Test class is not recognized as a Spring component. Therefore, you cannot inject it in your GreetingController. In order to inject Test object in that controller, annotate Test class with like #Component annotation (or with some other annotation that indicates that your class can be auto scanned).

Missed the full error. You need #Component on Test.

Related

#ConfigurationProperties don't work in test in Spring Boot 2.4.2

I have an application that works fine in Spring Boot 2.3.8 but the #RestClientTests fails with 2.4.2 because the test objects can not be instantiated because there's no bean of the #ConfigurationProperties (which is created by the #TestConfiguration).
How do I have to change my code so it works with 2.4.x?
Code is:
#Configuration
#ConfigurationProperties(prefix = "tyntec.routetest.dsidr")
#Data
#Validated
public class DynamicSenderIdReplacementClientConfiguration {
#NotBlank
private String baseUrl;
#NotBlank
private String dsidrPath;
}
#Component
#RequiredArgsConstructor
public class DynamicSenderIdReplacementClient {
private final DynamicSenderIdReplacementClientConfiguration configuration;
}
#ExtendWith(SpringExtension.class)
#RestClientTest(DynamicSenderIdReplacementClient.class)
#AutoConfigureWebClient(registerRestTemplate = true)
class DynamicSenderIdReplacementClientWebTest {
#Autowired
private DynamicSenderIdReplacementClient cut;
#TestConfiguration
static class testConfiguration {
#Bean
#Primary
public DynamicSenderIdReplacementClientConfiguration provideConfig() {
return new DynamicSenderIdReplacementClientConfiguration() {
{
setBaseUrl(BASE_URL);
setDsidrPath(DSIDR_PATH);
}
};
}
}
This works in 2.3.8 but fails in 2.4.2 with
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.tyntec.routetesting.client.itest.clients.DynamicSenderIdReplacementClientConfiguration' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Turns out, #RestClientTest works as advertised and inhibits the beans in #TestConfiguration:
Using this annotation will disable full auto-configuration and instead
apply only configuration relevant to rest client tests (i.e. Jackson
or GSON auto-configuration and #JsonComponent beans, but not regular
#Component beans).
Using #Import helps.
#RestClientTest(DynamicSenderIdReplacementClient.class)
#AutoConfigureWebClient(registerRestTemplate = true)
#Import(DynamicSenderIdReplacementClientWebTest.testConfiguration.class)
class DynamicSenderIdReplacementClientWebTest {

Spring Boot WebFluxTest test, failed to instantiate repository, specified class is an interface

I am writing the integration tests with #WebFluxTest for my #RestController.
Here are my classes:
#RestController
#RequestMapping("/usager")
public class UsagerController {
#Autowired
private UsagerService usagerService;
#GetMapping
public Usager getUsager() {
return usagerService.create();
}
}
#Service
public class UsagerService implements CrudService<Usager, Integer> {
#Autowired
private UsagerRepository usagerRepository;
#Override
public JpaRepository<Usager, Integer> getRepository() {
return usagerRepository;
}
#Override
public Usager create() {
return new Usager();
}
}
#Repository
public interface UsagerRepository extends JpaRepository<Usager, Integer>, JpaSpecificationExecutor<Usager> {
}
#ExtendWith(SpringExtension.class)
#WebFluxTest(UsagerController.class)
#Import({ UsagerService.class, UsagerRepository.class })
#Tag(TestCase.INTEGRATION)
public class UsagerControllerIT {
#Autowired
private WebTestClient wtc;
#Test
public void getUsager_returnUsager() {
ResponseSpec rs = wtc.get().uri("/usager").exchange();
rs.expectStatus().isOk();
rs.expectHeader().contentType(MediaType.APPLICATION_JSON);
rs.expectBody(Usager.class).isEqualTo(new Usager());
}
}
I get the following exception:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.dsi.bibliosys.biblioback.repository.UsagerRepository]: Specified class is an interface
I don't understand why Spring can't inject the repository.
Does somebody have an idea ?
I tried another approach using #SpringBootTest. Here is my new test class :
#ExtendWith(SpringExtension.class)
#SpringBootTest
#Tag(TestCase.INTEGRATION)
public class UsagerController02IT {
#Autowired
private UsagerController usagerController;
#Test
public void getUsager_returnUsager() {
WebTestClient wtc = WebTestClient.bindToController(usagerController).build();
ResponseSpec rs = wtc.get().uri("/usager").exchange();
rs.expectStatus().isOk();
rs.expectHeader().contentType(MediaType.APPLICATION_JSON);
rs.expectBody(Usager.class).isEqualTo(new Usager());
}
}
I get this exception:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.dsi.bibliosys.biblioback.controller.UsagerController': Unsatisfied dependency expressed through field 'usagerService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.dsi.bibliosys.biblioback.service.entity.UsagerService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I don't understand why UserService is not available in the application context.
Thanks for your help.
This looks very similar to this. I'd suggest investigating your test configuration and adding it if appropriate.
A quote from Spring on #WebFluxTest
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to WebFlux tests (i.e. #Controller, #ControllerAdvice, #JsonComponent, Converter/GenericConverter, and WebFluxConfigurer beans but not #Component, #Service or #Repository beans).

SpringBoot JPA #Autowired no bean found exception

Edited to add proc structure:
main/java
hello(package)
Application(main app)
TestRestController
models(package)
Test
services(package)
TestRepo(interface)
I'm currently looking at component scan as just released the 'repo.Test' in the exception is a clue.
I've been through numerous tutorials and questions and still cannot find the answer to my particular issue, which is most likely to be down to my lack of understanding.
I have a spring boot application that I'm adding a db to. I've been following this tutorial : https://www.callicoder.com/spring-boot-rest-api-tutorial-with-mysql-jpa-hibernate/
However when I try and run my application (following identical steps) I get an exception:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testRestController': Unsatisfied dependency expressed through field 'testRepo'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'repo.TestRepo' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I do have another bean autowired in, the main difference is that this bean(the one that works) has a service that implements the interface and a bean configuration class. None of the examples for JPA follow that model and it seems daft to create a service to re-implement the methods from the JPARepo.
This is the controller I'm using:
#RestController
public class TestRestController {
#Autowired
GreetingService greetingService;
#Autowired
TestRepo testRepo;
#RequestMapping("/hello")
public String home() {
return greetingService.greet();
}
#RequestMapping("/testrepo")
public String testrepo() {
Test test = new Test("steve");
testRepo.save(test);
Long idOftest = test.getId();
test = null;
test = testRepo.findById(idOftest).get();
return "DID THIS WORK::::: + "+ test.toString();
}
with the interface being
#Repository
public interface TestRepo extends JpaRepository<Test, Long> {
}
and the model:
#Entity
#Data
public class Test {
private final String name;
public Test(String name){
this.name = name;
}
#Id
#GeneratedValue
private Long id;
public Long getId(){
return this.id;
}
}
The application main is:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
// #Bean
// public CommandLineRunner commandLineRunner(ApplicationContext ctx ) {
// return args -> {
//
// System.out.println("Let's inspect the beans provided by Spring Boot:");
//
// String[] beanNames = ctx.getBeanDefinitionNames();
// Arrays.sort(beanNames);
// for (String beanName : beanNames) {
// System.out.println(beanName);
// }
//
//
// };
// }
}
I recently commented out the bean annotation to see if that was causing an issue.
Thank you for any help in advance!
You are getting this exception because your class TestRepo is part of repo package, which is not the sub-package hierarchy of Application class package. #SpringBootApplication defines an automatic component scan on the packages which are subpackages of your main class i.e Application. If you want to resolve this issue without changing your package hierarchy add below line with #SpringBootApplication:
#ComponentScan({"repo","your.application.class.package"}) //// add the names of the packages where the controllers, services, repositories beans are stored

Spring boot: how to add spring-data repositories in tests

In tests i can add any bean (using static nested configuration class). but how can i add spring-data repositories? i can't return then as new bean because i can't instantiate them - they are interfaces
#RunWith(SpringRunner.class)
#DataMongoTest
//#SpringBootTest // or this annotation
public class JTest {
#Configuration
static class Config {
static class TestEntity {
String id;
}
interface TestRepository extends ReactiveMongoRepository<TestEntity, String> {}
}
#Autowired Config.TestRepository testRepository;
#Test
public void test() {}
}
running with #DataMongoTest gives me
Caused by: java.lang.IllegalStateException: Unable to retrieve #EnableAutoConfiguration base packages
running with #SpringBootTest gives:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'xxx.JTest$Config$TestRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
how can i add new repositories in tests?
Spring doesn't pick up nested interface repository (and instantiate a bean) by default. To enable, see:
#RunWith(SpringRunner.class)
#DataMongoTest
#EnableMongoRepositories(considerNestedRepositories = true)
public class JobTest {
#TestConfiguration
static class Config {
static class TestEntity {
String id;
}
....
Internally, Spring registers a bean with new SimpleMongoRepository<T, ID>(..) if none other specified.
Edit
Just realized you are using reactive Mongo. So switch to EnableReactiveMongoRepositories(..) instead.

Spring-Boot create bean with out name will cause "NoSuchBeanDefinitionException, No qualifying bean of type[]found for dependency "

I Create the bean by configuration with out name
#Configuration
#ConfigurationProperties(prefix = "mysql")
public class DbConfiguration extends BaseDbConfiguration {
#Bean//(name = "fix")
#Override
public DbClient createClient() {
return super.createClient();
}
}
usage:
#Autowired
private DbClient dbClient;
when I running application it can't start up
And throw NoSuchBeanDefinitionException:
No qualifying bean of type [DbClient] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
But I fix it by add name, why??
#Bean(name = "fix")
I also add a test such like this:
public class TestCreate {
#NotNull
private int test;
public Test createTest() {
return new Test(this.test);
}
}
it configuration like this:
#Configuration
#ConfigurationProperties(prefix = "test")
public class TestConfiguration extends TestCreate {
#Override
#Bean
public Test createTest() {
return super.createTest();
}
}
And autowired like this:
#Autowired
private Test test;
However, this test may work well
It also create Bean without name and Autowired with out Qualifier
Please Tell me why....thanks
Sorry.
I have found the results:
Overriding bean definition for bean 'createClient': replacing ...
So Spring-Boot will create Bean by FunctionName rather than returning ObjectName.

Categories

Resources