187

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>
Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
Khuzi
  • 2,792
  • 3
  • 15
  • 26

8 Answers8

298

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.

g00glen00b
  • 41,995
  • 13
  • 95
  • 133
  • 51
    Upvoted the question and your answer cause It's not obvious that you have to manually create a `RestTemplate` when everything else is magically created and linked for you. Especially if one used spring-cloud before which provides an autoconfigured `RestTemplate`. ;-) – daniel.eichten Mar 22 '16 at 11:31
  • 2
    Honestly, that was the reason I put this issue here in forum. I was expecting RestTemplate to be linked for me. :-) This was working fine when I had included Eureka dependency in POM.xml. It was working fine without defining RestTemplate bean. One of the classes of Eureka might have defined this bean or so. – Khuzi Mar 23 '16 at 03:52
  • 8
    Just an update. From Spring Boot 1.4.0 `RestTemplateBuilder` can be used for managing `RestTemplate` instances. Example here https://spring.io/guides/gs/consuming-rest/ – Mensur Sep 27 '16 at 10:58
  • I cant yet upgrade to SB 1.4.0. I want to do this with 1.3.8.RELEASE but @g00glen00b solution didn't work for me. I am also using `spring-cloud-netflix` artifactid with version `1.1.5.RELEASE`. My RestTemplate is being called from an `@RestController` java class which uses `@Autowired` for the `RestTemplate`. Can someone please help ? – ZeroGraviti Oct 20 '16 at 20:02
  • @ZeroGraviti, can you create a new question? I think this problem is unrelated to this question/answer. – g00glen00b Oct 21 '16 at 12:42
  • This answer does not work for Spring Boot 1.4.x java.lang.IllegalStateException: Test classes cannot include @Bean methods – Avec Nov 30 '16 at 21:53
  • @Avec this question/answer is not about test classes though. – g00glen00b Dec 01 '16 at 17:58
  • Autowired* (just add method) – raffian Feb 23 '18 at 19:33
12

If a TestRestTemplate is a valid option in your unit test, this documentation might be relevant

http://docs.spring.io/spring-boot/docs/1.4.1.RELEASE/reference/htmlsingle/#boot-features-rest-templates-test-utility

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.

ClaudiaR
  • 3,108
  • 2
  • 13
  • 27
Mark K.
  • 411
  • 4
  • 3
10
  • You must add @Bean public RestTemplate restTemplate(RestTemplateBuilder builder){ return builder.build(); }
5

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();
    }

}
Fazle Subhan
  • 211
  • 3
  • 5
4

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();
}
Dmitry Rakovets
  • 557
  • 1
  • 6
  • 15
2

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();
}
}
Harun Diluka Heshan
  • 1,155
  • 2
  • 18
  • 30
vineet
  • 59
  • 1
  • 4
1

Error points directly that RestTemplate bean is not defined in context and it cannot load the beans.

  1. Define a bean for RestTemplate and then use it
  2. Use a new instance of the RestTemplate

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.

Vinay Veluri
  • 6,671
  • 5
  • 32
  • 56
1

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";
    }
}
Padi kodwo Amu
  • 575
  • 4
  • 7
  • do you think thar the getForObject() violate the SOLID principales ? Wich one ? – Hamdy Sep 17 '21 at 09:45
  • @Hamdy you violate the SOLID principle by putting your main logic in the controller ... controllers are meant to be entry points for your code not processors of the request. in spring you will usually use a service class for such functions. – Padi kodwo Amu Apr 09 '22 at 11:58