Reputation: 2912
I am getting below exception while running Spring Boot
application during start up:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'testController':
Injection of autowired dependencies failed;
nested exception is
org.springframework.beans.factory.BeanCreationException:
Could not autowire field:
private org.springframework.web.client.RestTemplate
com.micro.test.controller.TestController.restTemplate;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type
[org.springframework.web.client.RestTemplate]
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)}
I am autowiring RestTemplate
in my TestController. I am using Maven for dependency management.
TestMicroServiceApplication.java
package com.micro.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TestMicroServiceApplication {
public static void main(String[] args) {
SpringApplication.run(TestMicroServiceApplication.class, args);
}
}
TestController.java
package com.micro.test.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class TestController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value="/micro/order/{id}",
method=RequestMethod.GET,
produces=MediaType.ALL_VALUE)
public String placeOrder(@PathVariable("id") int customerId){
System.out.println("Hit ===> PlaceOrder");
Object[] customerJson = restTemplate.getForObject("http://localhost:8080/micro/customers", Object[].class);
System.out.println(customerJson.toString());
return "false";
}
}
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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.micro.test</groupId>
<artifactId>Test-MicroService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Test-MicroService</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Upvotes: 198
Views: 282650
Reputation: 901
You must add
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){
return builder.build();
}
Upvotes: 12
Reputation: 421
If a TestRestTemplate is a valid option in your unit test, this documentation might be relevant
Short answer: if using
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
then @Autowired
will work. If using
@SpringBootTest(webEnvironment=WebEnvironment.MOCK)
then create a TestRestTemplate like this
private TestRestTemplate template = new TestRestTemplate();
This will help to avoid creation of a RestTemplate that wouldn't be used outside tests.
Upvotes: 13
Reputation: 44675
It's exactly what the error says. You didn't create any RestTemplate
bean, so it can't autowire any. If you need a RestTemplate
you'll have to provide one. For example, add the following to TestMicroServiceApplication.java:
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
Since Spring boot 1.4, there's also a convenient builder that you can autowire and use to create a RestTemplate
bean. The benefit is that you can use the builder pattern to register interceptors, customizers, ... .
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
Note, in earlier versions of the Spring cloud starter for Eureka, a RestTemplate
bean was created for you, but this is no longer true.
Upvotes: 310
Reputation: 797
Since RestTemplate instances often need to be customized before being used, Spring Boot does not provide any single auto-configured RestTemplate bean.
RestTemplateBuilder offers proper way to configure and instantiate the rest template bean, for example for basic auth or interceptors.
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.basicAuthorization("user", "name") // Optional Basic auth example
.interceptors(new MyCustomInterceptor()) // Optional Custom interceptors, etc..
.build();
}
Upvotes: 5
Reputation: 261
you are trying to inject the restTemplate but you need to create configuration class . then there you need to create bean that return you new RestTemplate see the below example.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class YourConfigClass {
@Bean
public RestTemplate restTesmplate() {
return new RestTemplate();
}
}
Upvotes: 8
Reputation: 765
The simplest way I was able to achieve a similar feat to use the code below (reference), but I would suggest not to make API calls in controllers(SOLID principles). Also autowiring this way is better optimsed than the traditional way of doing it.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class TestController {
private final RestTemplate restTemplate;
@Autowired
public TestController(RestTemplateBuilder builder) {
this.restTemplate = builder.build();
}
@RequestMapping(value="/micro/order/{id}", method= RequestMethod.GET, produces= MediaType.ALL_VALUE)
public String placeOrder(@PathVariable("id") int customerId){
System.out.println("Hit ===> PlaceOrder");
Object[] customerJson = restTemplate.getForObject("http://localhost:8080/micro/customers", Object[].class);
System.out.println(customerJson.toString());
return "false";
}
}
Upvotes: 1
Reputation: 79
Please make sure two things:
1- Use @Bean
annotation with the method.
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){
return builder.build();
}
2- Scope of this method should be public not private.
Complete Example -
@Service
public class MakeHttpsCallImpl implements MakeHttpsCall {
@Autowired
private RestTemplate restTemplate;
@Override
public String makeHttpsCall() {
return restTemplate.getForObject("https://localhost:8085/onewayssl/v1/test",String.class);
}
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){
return builder.build();
}
}
Upvotes: 2
Reputation: 6855
Error points directly that RestTemplate
bean is not defined in context and it cannot load the beans.
If you are sure that the bean is defined for the RestTemplate then use the following to print the beans that are available in the context loaded by spring boot application
ApplicationContext ctx = SpringApplication.run(Application.class, args);
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
If this contains the bean by the name/type given, then all good. Or else define a new bean and then use it.
Upvotes: 1