This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 4 years ago.
I am new to Spring. I develop Service that Consuming RESTful service with certficate using Java
Here is my Config class:
package configuration;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.ResourceUtils;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import java.util.function.Supplier;
#Configuration
public class RestClientCertConfig {
private char[] allPassword = "allpassword".toCharArray();
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {
SSLContext sslContext = SSLContextBuilder
.create()
.loadKeyMaterial(ResourceUtils.getFile("classpath:keystore.jks"), allPassword, allPassword)
.loadTrustMaterial(ResourceUtils.getFile("classpath:truststore.jks"), allPassword)
.build();
HttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
.build();
return builder
.requestFactory((Supplier<ClientHttpRequestFactory>)new HttpComponentsClientHttpRequestFactory(client))
.build();
}
}
And here is the class where I consume Restful EndPoint:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import java.net.URISyntaxException;
import java.util.Collections;
public class ECSConfigGet {
private static final String ECS_API_URI = "<RestEndPointToConsume";
#Autowired
private static RestTemplate restTemplate;
public static void main(String[] args) {
try {
makeECSCall("myTestHeaderValue");
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
private static void makeECSCall(String entityCode) throws RestClientException, URISyntaxException {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.set("entityCode", entityCode);
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
ResponseEntity responseEntity = restTemplate.exchange(ECS_API_URI, HttpMethod.GET, entity, String.class);
}
}
Did I completely misunderstood the concept? I would expect restTemplate would not be null with all the Annotations I use. Thank for any help!
NullPointerException is fixed. ECSConfigGet looks like:
package main;
import configuration.RestClientCertConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import services.modelsdto.ExpenseConfigDTO;
import java.util.Collections;
#SpringBootApplication
#Component
public class ECSConfigGet implements CommandLineRunner{
//API to call
private static final String ECS_API_URI = "<API_TO_CONSUME>";
#Autowired
private RestTemplate restTemplate;
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RestClientCertConfig.class);
applicationContext.getBean(RestTemplate.class);
SpringApplication.run(ECSConfigGet.class, args);
}
private void makeECSCall(String entityCode) throws RestClientException {
ExpenseConfigDTO expenseConfigDTO = new ExpenseConfigDTO();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.set("entityCode", entityCode);
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
ResponseEntity responseEntity = restTemplate.exchange(ECS_API_URI, HttpMethod.GET, entity, String.class);
}
#Override
public void run(String... args) {
for (int i = 0; i < args.length; ++i) {
makeECSCall("myTestHeaderValue");
}
}
}
You're missing a bit of Spring boilerplate that you need to make #Autowired work. If you're using Spring Boot, you're close, but #Patrick is right generally: ECSConfigGet needs to be a bean by annotating it correctly, but you also need to run your application within an application context in order for any of the Spring magic to happen. I suggest checking out this tutorial on how to use Spring Boot in a command line application.
The high level is ECSConfigGet needs to be annotated with #SpringBootApplication and then have it implement CommandLineRunner and then from the run method, you will have access to the #Autowired component. Spring will instantiate ECSConfigGet and populate the properties. Also as #Roddy pointed out, RestTemplate cannot be static, either.
The ECSConfigGet class is not a bean so it can not autowire a component.
Add #Component as class annotation to ECSConfigGet
Related
I've made an angular application with typescript code that uses a java spring web service, I'm having trouble with CORS.
The first http request gets an access token from the web server to use in all following requests, but all following requests are refused with this error:
Access to XMLHttpRequest at X from origin Y has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
X is the URL resource of my http method
Y is the origin of the request
API GATEWAY MODULE
package it.sitgeo.apigateway.controller;
import it.sitgeo.apigateway.exception.LoginException;
import it.sitgeo.apigateway.model.AppUser;
import it.sitgeo.apigateway.model.LoginForm;
import it.sitgeo.apigateway.service.AppUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
#RestController
#RequestMapping("/sitgeo")
#RequiredArgsConstructor
#CrossOrigin(allowedHeaders = "*")
public class AppUserController {
private final AppUserService service;
#PostMapping(path = "/login", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE})
public ResponseEntity<String> login (#Valid #ModelAttribute LoginForm loginForm) throws LoginException {
String access_token = service.login(loginForm.getUsername(), loginForm.getPassword());
if(access_token == null){
throw new LoginException("Le credenziali inserite non sono corrette");
}
return ResponseEntity.ok(access_token);
}
PED MODULE
package it.sitgeo.ped.Controllers;
import it.sitgeo.ped.Entities.*;
import it.sitgeo.ped.Repositories.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.mail.MessagingException;
import java.io.IOException;
#Slf4j
#RestController
#RequestMapping("/sitgeo/PED")
#AllArgsConstructor
#CrossOrigin(origins = {"http://localhost","Y"} ,allowedHeaders = "*")
public class PEDController {
final EmailConfiguration emailConfiguration;
private final PraticaRepository praticaRepository;
private final ComuneRepository comuneRepository;
private final TitolareRepository titolareRepository;
private final PdfRepository pdfRepository;
private final ProcuratoreRepository procuratoreRepository;
private final DomicilioElettronicoRepository domicilioElettronicoRepository;
private final LocalizzazioneRepository localizzazioneRepository;
private final CatastoRepository catastoRepository;
private final TecnicoRepository tecnicoRepository;
private final SoggettiTitolariRepository soggettiTitolariRepository;
private final StatoUnitaRepository statoUnitaRepository;
private final TipologiaRepository tipologiaRepository;
//#CrossOrigin(origins = "http://localhost:4200")
#GetMapping("/getCOMUNI/{provincia}")
public ResponseEntity<?> getComuni(#PathVariable String provincia) {
log.info("getCOMUNI {}", provincia);
ResponseEntity<?> response;
try {
response = new ResponseEntity<String[]>(comuneRepository.searchComuneByProvincia(provincia),
HttpStatus.OK);
} catch (Exception e) {
response = new ResponseEntity<String[]>(HttpStatus.BAD_REQUEST);
}
System.out.println(response.getBody());
return response;
}
PED MODULE
package it.sitgeo.ped.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class CORSConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("Y", "http://localhost")
.allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD","OPTIONS")
.allowedHeaders("*");
}
}
I've tried this http method using postman and it works as intended returning a JSON.
I am learning to write Unit Test for SpringBoot Restcontroller , wrote this and test passes
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {FhirApp.class, TestSecurityConfiguration.class})
#AutoConfigureMockMvc
public class ObservationControllerTest {
private ObjectMapper objectMapper = new ObjectMapper();
#Autowired
private MockMvc mockMvc;
#MockBean
private ObservationService observationService;
#Test
public void createObservationResource() throws Exception {
given(observationService.createObservation(ResourceStringProvider.observationsource()))
.willReturn(responseDocument);
String jsonString = objectMapper.writeValueAsString(
ResourceStringProvider.observationsource());
mockMvc.perform(post("/Observation")
.contentType(MediaType.APPLICATION_JSON)
.content(jsonString))
.andExpect(status()
.isOk());
}
But as this and this , i am also getting empty response for response.getContentAsString() :
Mockito.when(observationService.createObservation(Mockito.any())).thenReturn(responseDocument);
String jsonString = objectMapper.writeValueAsString(ResourceStringProvider.observationsource());
MockHttpServletResponse response = mockMvc.perform(post("/Observation")
.contentType(MediaType.APPLICATION_JSON)
.content(jsonString))
.andReturn()
.getResponse();
assertThat(response.getContentAsString())
.isEqualTo(new ObjectMapper()
.writeValueAsString(responseDocument));
I already tried the solutions provided by them :
1: Using Mockito.any(String.class)
2: webEnvironment = SpringBootTest.WebEnvironment.MOCK
3: using thenCallRealMethod instead of thenReturn(responseDocument)
But unfortunately it didn't work,already tried different possibilities , I also tried using MockitoJunitRunner :
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(classes = {FhirApp.class, TestSecurityConfiguration.class})
#AutoConfigureMockMvc
public class ObservationControllerTest {
private MockMvc mockMvc;
#Mock
private ObservationService observationService;
#Mock
private RequestFilter requestFilter;
#InjectMocks
private ObservationController observationController;
#Before
public void setup() {
Resource resource = Utility.convertFromStringToFhirResource(Observation.class,ResourceStringProvider.observationResponse());
responseDocument=Utility.convertFromFhirResourceToMongoInsertibleDoc(resource);
//these line enabled for MockitoJUnitRunner only
this.mockMvc = MockMvcBuilders.standaloneSetup(observationController)
.setControllerAdvice(new FhirRuntimeException("Error Happened"))
.addFilters(requestFilter)
.build();
}
#Test
public void createObservationResource()throws Exception{
Mockito.when(observationService.createObservation(ResourceStringProvider.observationsource())).thenReturn(responseDocument);
String jsonString = objectMapper.writeValueAsString(ResourceStringProvider.observationsource());
MockHttpServletResponse response = mockMvc.perform(
post("/Observation")
.contentType(MediaType.APPLICATION_JSON)
.content(jsonString))
.andReturn()
.getResponse();
assertThat(response.getContentAsString()).isEqualTo(new ObjectMapper().writeValueAsString(responseDocument));
}
i think since not many have went through such issues, issue isn't much talked about . What could be the reason of empty response when response status is ok?
Controller code :
#RestController
#RequestMapping("/api")
public class ObservationController {
#Autowired
private ObservationService observationService;
#GetMapping("/Observation/{id}")
public ResponseEntity<Document> getObservationByID(
#RequestParam("_pretty") Optional<String> pretty,
#PathVariable("id") String id) {
Document resultDoc = observationService.getObservationById(id);
return new ResponseEntity<>(resultDoc, HttpStatus.OK);
}
#PostMapping(path = "/Observation", consumes = {"application/json", "application/fhir+json"},
produces = {"application/json", "application/fhir+json"})
public ResponseEntity<Document> createObservationResource(#RequestBody String fhirResource) {
Document fhirDoc = observationService.createObservation(fhirResource);
return new ResponseEntity<>(fhirDoc,
Utility.createHeaders(fhirDoc),
HttpStatus.CREATED);
}
//other methods
}
I realized the call to post in test should be /api/Observation , but it didn't make any difference . Thanks in Advance.
Posting the complete answer alongwith imports here so that it will help someone (actually we don't require any annotation above and it is one way to run it , during my findings i came accross this post which helps in solving design issue which may occur if you go ahead with #InjectMocks approach)
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import com.comitemd.emr.datalayer.fhir.service.ObservationService;
import com.comitemd.emr.datalayer.fhir.utility.ResourceStringProvider;
import com.comitemd.emr.datalayer.fhir.utility.Utility;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.bson.Document;
import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.Resource;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
//#RunWith(MockitoJUnitRunner.class)
public class ObservationControllerStandaloneTest {
private MockMvc mockMvc;
#Mock
private ObservationService observationService;
#InjectMocks
private ObservationController observationController;
private Document responseDocument;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);// enable this or MockitoJUnitRunner.class
Resource resource = Utility
.convertFromStringToFhirResource(Observation.class, ResourceStringProvider.observationResponse());
responseDocument=Utility.convertFromFhirResourceToMongoInsertibleDoc(resource);
this.mockMvc = MockMvcBuilders.standaloneSetup(observationController).build();
}
#Test
public void createObservationResource()throws Exception{
Mockito.when(observationService.createObservation(ResourceStringProvider.observationsource()))
.thenReturn(responseDocument);
MockHttpServletResponse response = mockMvc.perform(
post("/api/Observation")
.contentType(MediaType.APPLICATION_JSON)
.content(ResourceStringProvider.observationsource()))
.andDo(MockMvcResultHandlers.print())
.andReturn()
.getResponse();
verify(observationService, times(1)).createObservation(Mockito.any());
assertThat(response.getContentAsString()).isEqualTo(new ObjectMapper().writeValueAsString(responseDocument));
}
}
I wrote a micro-service to make a HTTP call to an API. Code is as given below.
Connector Application
package com.ajay.dashboard.service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
#SpringBootApplication
public class DellDashboardConnectorApplication {
public static void main(String[] args) {
SpringApplication.run(DellDashboardConnectorApplication.class, args);
}
#Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
Connector COntroller
package com.ajay.dashboard.service.controller;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.bind.annotation.CrossOrigin;
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;
/*
* Created by Kulkaa
*/
#RestController
public class DellDashboardController {
private static final Logger logger = LoggerFactory.getLogger(DellDashboardController.class);
#CrossOrigin(origins = "http://localhost:8080")
#RequestMapping(method = RequestMethod.GET, value = "/incident", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> retrieveAllCircles(HttpServletRequest request) throws UnsupportedEncodingException {
logger.info("DellDashboardController -> retrieveAllIncidents : invoked.");
RestTemplate restTemplate =new RestTemplate();
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
messageConverters.add(converter);
restTemplate.setMessageConverters(messageConverters);
String formUrl = "api";
final String sysparm_query = "incident_stateNOT%20IN6%2C7%5Eassignment_group%3D4122c7f8f09cc1002283ac3a043ae3e6";
final String sysparm_display_value = "true";
final String sysparm_exclude_reference_link = "true";
try {
URIBuilder builder = new URIBuilder(formUrl);
builder.addParameter("sysparm_query", sysparm_query);
builder.addParameter("sysparm_display_value", sysparm_display_value);
builder.addParameter("sysparm_exclude_reference_link", sysparm_exclude_reference_link);
String actualUrl = builder.toString();
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic U2VydmljZV9Nb2JpbGVSZXBvcnRpbmc6U2VydmljZV9Nb2JpbGVSZXBvcnRpbmc=");
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
return restTemplate.exchange(actualUrl, HttpMethod.GET, entity, String.class);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return retrieveAllCircles(request);
}
}
When I build it by using mvn clean install, it runs perfectly. However, when I run it as SpringBoot app, I get below error:
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.lang.String out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 1]
Do I need to deserialize it by using POJO class?
JSON being mapped is in the format:
{
"result": [{
data here
}]
}
Is it a json object?
Try creating a null entity. This might work
HttpEntity<String> entity = new HttpEntity<String>(null,headers);
The JSON content is invalid, so the parser breaks. So this would induce an empty content.
I am developing a Spring Boot Application which calls a REST-API which frequently performs a 303 See Other redirect to the proper location.
For a given resource I start with a random initial URL, intercept the redirect to store the proper location for the next request and at last perform the redirect.
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
#Configuration
class RestTemplateFactory {
private static final Logger LOG = LoggerFactory.getLogger(RestTemplateFactory.class);
#Autowired
KeyMap keyMap;
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
HttpClient httpClient = HttpClientBuilder
.create()
.setRedirectStrategy(new DefaultRedirectStrategy() {
#Override
public boolean isRedirected(HttpRequest request, HttpResponse response,
HttpContext context) throws ProtocolException {
if (super.isRedirected(request, response, context)) {
String redirectURL = response.getFirstHeader("Location").getValue();
LOG.debug("Intercepted redirect: original={}, redirect={}", request.getRequestLine(),
redirectURL);
keyMap.put(redirectURL);
return true;
}
return false;
}
})
.build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
return builder
.requestFactory(requestFactory)
.build();
}
}
(The class KeyMap is used to store the location for some domain key, which is stored in a ThreadLocal before the RestTemplate is invoked.)
Question: How can I test this special RestTemplate?
I'm injecting my cookie param in that way (using javax.ws.rs.CookieParam)
#CookieParam("parameterCookie")
private String parameterCookie;
i have a problem to inject that parameter using Resteasy
ERROR
It is illegal to inject a #CookieParam into a singleton
That is a BaseResource and i can't modify all resources to accept that paramenter on all methods (it costs a lot). How could i inject that CookieParam in Resteasy without modify all resources?
You can work around this by injecting HttpHeaders instead:
import org.jboss.resteasy.core.Dispatcher;
import org.jboss.resteasy.mock.MockDispatcherFactory;
import org.jboss.resteasy.mock.MockHttpRequest;
import org.jboss.resteasy.mock.MockHttpResponse;
import org.junit.Before;
import org.junit.Test;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
public class CookieTest {
static final String COOKIE_NAME = "parameterCookie";
Dispatcher dispatcher;
#Before
public void setUp() throws Exception {
dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addSingletonResource(new Resource());
}
#Test
public void name_StateUnderTest_ExpectedBehavior() throws Exception {
String cookieValue = String.valueOf(System.currentTimeMillis());
MockHttpResponse response = new MockHttpResponse();
MockHttpRequest request = MockHttpRequest.get("/")
.cookie(COOKIE_NAME, cookieValue);
dispatcher.invoke(request, response);
assertThat(response.getContentAsString(), is(COOKIE_NAME + "=" + cookieValue));
}
#Path("/")
public static class Resource {
#Context HttpHeaders headers;
#GET #Path("/")
public String getCookie(){
return headers.getCookies().get(COOKIE_NAME).toString();
}
}
}