Issue
I developed a simple class that gets an access token from a REST api. Its not fully implemented, but the idea is for it to persist the token in a database. I also have a function to check if there is any available token and if there's not, it calls the function that gets the token for a new one. I also developed a unit test to check If i'm getting a token.
I'm getting a problem when running my test, a NoSuchBeanDefinitionException issue. I do not know what I'm doing wrong. I'm still pretty new to Spring boot, so all help is appreciated. Below is the code for both my testing and my class that communicates with the REST endpoint.
TokenIntegration class:
package com.foo.receivable.domain.token;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.time.LocalDateTime;
import java.util.Arrays;
public class TokenIntegration {
static final String GET_TOKEN_URI = "";
static final String API_CLIENT_ID = "";
static final String API_CLIENT_SECRET = "";
static final String API_AUDIENCE = "";
static final String API_GRANT_TYPE = "";
@Autowired
private RestTemplate restTemplate;
private TokenRepository repository;
private Token API_RetrieveToken(){
Token t = new Token();
try {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.set("client_id", API_CLIENT_ID);
headers.set("client_secrect", API_CLIENT_SECRET);
headers.set("audience", API_AUDIENCE);
headers.set("grant_type", API_GRANT_TYPE);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(GET_TOKEN_URI, HttpMethod.POST, entity, String.class);
//not implemented yet
}catch(Exception e){
e.printStackTrace();
}
return t;
}
public Token GetAccessToken(){
Token token;
try {
token = repository.findByExpired(LocalDateTime.now());
if(token == null){
token = API_RetrieveToken();
}
}
catch (Exception e){
token = null;
e.printStackTrace();
}
return token;
}
}
TokenIntegrationTest class:
package com.foo.receivable.domain.token;
import com.foo.receivable.infra.AbstractTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TokenIntegrationTest extends AbstractTest {
@Autowired
private TokenIntegration integration;
@Test
void ShouldReturnTokenObject(){
final Token token = integration.GetAccessToken();
if(token == null){
//not implemented yet
}
assertEquals(Token.class, token.getClass());
}
}
And my exception tracing:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.foo.receivable.domain.token.TokenIntegrationTest': Unsatisfied dependency expressed through field 'integration'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.foo.receivable.domain.token.TokenIntegration' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
EDIT: The problem was the @Component annotation was missing, and so spring did not recognize my TokenIntegration class as a bean. After I changed it, I got yet another error about having a RestTemplate bean. Any help on this?
***************************
APPLICATION FAILED TO START
***************************
Description:
Field restTemplate in com.foo.receivable.domain.token.TokenIntegration required a bean of type 'org.springframework.web.client.RestTemplate' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.web.client.RestTemplate' in your configuration.
2021-05-10 11:44:50.801 ERROR 19916 --- [ main] o.s.test.context.TestContextManager : Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@70ab2d48] to prepare test instance [com.foo.receivable.domain.token.TokenIntegrationTest@22a9170c]
java.lang.IllegalStateException: Failed to load ApplicationContext
Solution
You have your TokenIntegration marked as @Autowired
so you need to tell Spring that it should manage your TokenIntegration
bean:
@Component
public class TokenIntegration
This will let Spring know to create one of these beans and put it into the application context, which will in turn make it so that Spring can provide a bean to your @Autowired
field.
In other words:
If a bean is not in Spring's application context, it cannot be autowired by Spring. As far as Spring knows it does not exist.
To answer your edit:
Could not autowire field:RestTemplate in Spring boot application
Answered By - mikeb
Answer Checked By - Marilyn (JavaFixing Volunteer)