Strange behaviour while runnning spring boot actuator - spring

I am working with a spring boot app which evolve actuator in the pictures .It evolves the endpoint roles.
Below is my controller part which handle the healthStaus
public ModelAndView healthStatus() {
ModelAndView view= new ModelAndView();
final String uri = "http://localhost:8090/actuator";
RestTemplate restTemplate = new RestTemplate();
String response=restTemplate.getForObject(uri,String.class);
try {
Object ob=new ObjectMapper().readValue(response, Employee.class); }
catch (IOException e){
e.printStackTrace();
}
view.addObject("objects",ob);
view.setViewName("dashboard");
return view;
}
while the request handle at this part of code at time of execution it show a strange behaviour .It download a file automatically with the same name of url.

Related

Mockito is returning "java.lang.IllegalArgumentException: URI is not absolute" in RestTemplate.exchange Springboot

Mockito is returning "java.lang.IllegalArgumentException: URI is not absolute" in RestTemplate.exchange. I am not sure why this is happening because it seems I am mocking the restTemplate properly and since I am seeing that exception, it seems that RestTemplate is not a mock.
Here is my class
#Component
public class RestTemplateWrapper {
private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateWrapper.class);
public <T> ResponseEntity<T> callWebServiceGET(String url,HttpEntity<?> httpEntity,
ParameterizedTypeReference<T> parameterizedTypeReference) {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<T> response=null;
LOGGER.trace("Entered callWebServiceGET");
LOGGER.info("Calling WebService {}", url);
try {
response=restTemplate.exchange(url, HttpMethod.GET, httpEntity, parameterizedTypeReference);
} catch (HttpClientErrorException e) {
if (HttpStatus.NOT_FOUND.equals(e.getStatusCode())) {
LOGGER.error("Service Unavailable - Code 404 returned. " + url + e.getMessage());
} else if (HttpStatus.UNAUTHORIZED.equals(e.getStatusCode())) {
LOGGER.error("Token Expired- Code 401 returned. " + e.getMessage());
} else if (HttpStatus.BAD_REQUEST.equals(e.getStatusCode())) {
LOGGER.error("Bad Input, 400 returned.{} {} ", url , e.getMessage(), e);
} else {
LOGGER.error("WEB Service Failure. " + e.getMessage());
}
}
return response;
}
}
And here is my TestCase:
#PrepareForTest({RestTemplateWrapper.class})
public class RestTemplateWrapperTest {
#Mock
private RestTemplate mockRestTemplate;
#InjectMocks
private RestTemplateWrapper webUtils;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void callWebServiceGET_OK() {
HttpEntity<String> httpEntity= new ResponseEntity<>(HttpStatus.OK);
ResponseEntity<String> entityResponse=new ResponseEntity<>("MOCK_RESPONSE", HttpStatus.OK);
when(mockRestTemplate.exchange(eq("/objects/get-objectA"), eq(HttpMethod.GET), eq(httpEntity),any(
ParameterizedTypeReference.class))).thenReturn(
entityResponse);
ResponseEntity<String> mockResponse= webUtils.callWebServiceGET("",null, new ParameterizedTypeReference<String>(){
});
//verify(mockRestTemplate,times(1)).exchange(Matchers.anyString(), Matchers.any(), Matchers.any());
Assert.assertEquals("MOCK_RESPONSE",mockResponse.getBody());
}
}
The response:
URI is not absolute
java.lang.IllegalArgumentException: URI is not absolute
at java.net.URI.toURL(URI.java:1088)
at org.springframework.http.client.SimpleClientHttpRequestFactory.createRequest(SimpleClientHttpRequestFactory.java:145)
at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:87)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:727)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:666)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:604)
at com.project.di.tp.purchaseorderservice.utils.RestTemplateWrapper.callWebServiceGET(RestTemplateWrapper.java:29)
at com.project.di.tp.purchaseorderservice.utils.RestTemplateWrapperTest.callWebServiceGET_OK(RestTemplateWrapperTest.java:51)
Any idea about how to solve this issue? I have been trying like 4 hours.
I found the solution, it seems the problem is that my class is RestTemplateWrapper is creating a instance inside callWebServiceGET therefore mockito can`t mock that object. If if set the object outside the method, it works but I dont want to do that.
Is there any way to mock a object that is inside a method?
Although it is not stated explicitly in the JavaDocs it is the case that you have to provide an absolute URL there.
This is because you do nowhere provide a base URL where a relative URL would be relative to. You could not enter "/objects/get-objectA" as URL in your browser either.
So I would suggest that you use something like "http://example.com/objects/get-objectA" instead for the first parameter:
when(mockRestTemplate.exchange(
eq("http://example.com/bla"),
eq(HttpMethod.GET),
isNull(HttpEntity.class),
any(ParameterizedTypeReference.class))).
thenReturn(entityResponse);
ResponseEntity<String> mockResponse =
webUtils.callWebServiceGET(
"http://example.com/bla",
null,
new ParameterizedTypeReference<String>(){});
Please note that the call to webUtils.callWebServiceGET with given parameters would not make Mockito return the wanted answer, so I changed for one the URL in the call to the absolute URL you are expecting in the Mockito.when and also changed the parameter expected there to be a typed null (typed to match the method signature).
UPDATE:
As you found out by yourself already, your Mockito.when doesn't work because you do not use the created mock from the test in your tested method, but instead create a fresh instance of RestTemplate in each call of callWebServiceGET. (Don't know why I didn't see it earlier, sorry!)
I recommend that instead you inject the RestTemplate into the tested class with a constructor:
private final RestTemplate restTemplate;
public RestTemplateWrapper(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
// remove the following line in the method callWebServiceGET:
// RestTemplate restTemplate = new RestTemplate();
With this code, Spring will automatically inject your mocked RestTemplate into the test, but for running the production code you need to add a bean to provide a RestTemplate for injection.
Add this to a Configuration class where you also define other beans:
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
// Do any additional configuration here
return builder.build();
}
(Found this code snippet in an answer to How to autowire RestTemplate using annotations)
And as a general advice for testing: try to avoid the use of the new operator in any code you want to test, but use injection instead. If you need to create multiple instances (e.g. in a loop, etc.) try to inject a factory that creates the instances for you - so in the test you can mock the factory.

Rest api filtering in spring boot

I have a project in spring boot, in my controller I have many methods with similar functionality.
Methods for searching post, popular, latest etc and the urls with slight variation like -
url 1 - search/{topicId}
url 2 - search/popular/{topicId}
url 3 - search/latest/{topicId}
What I want, is to have a single method with filter in url like search/{topicId}?filter=popular
How to achieve this in spring boot?
OOPs... it does not depend on SpringBoot. It is simply a URL mapping...You can accept the type as a request param and can process as per business.....
#Controller
public class BookController {
#GetMapping(value = "/search/{topicId}")
#ResponseBody
public List<Object> getBooksByType(#RequestParam String type) {
try{
if("popular".equalsIgnoreCase(type)){
//do your business stuffs
}else if ("latest".equalsIgnoreCase(type)){
//do your business stuffs
}
}catch(Exception e){
e.printStackTrace();
}
return new ArrayList<>();
}
}

File upload, communication between two spring boot application

I have two spring boot application, one is 'AngularApp' (localhost:8870) supporting my front and the other one is 'batchApp'(localhost:8871) running some batches.
I would like to upload a file from my 'Front' to 'AngularApp', then to 'batchApp' as illustrated below.
Right now I did the upload from 'Front' to 'AngularApp', basically using REST API with one controller and service in 'AngularApp'.
#PostMapping("/post")
public ResponseEntity<String> handleFileUpload(#RequestParam("file") MultipartFile file)
It works well and upload the file into a specific folder 'upload-dir'.
Now I want 'AngularApp' and 'batchApp' to communicate so 'AngularApp' can give him the file uploaded, but I have no idea about how to do it. REST API ? Any ideas?
For the better approach to solve this problem using spring-framework libraries, please refer
https://piotrminkowski.wordpress.com/2017/02/05/part-1-creating-microservice-using-spring-cloud-eureka-and-zuul/
Below spring framework components make it easy.
Zuul – gateway service that provides dynamic routing, monitoring, resiliency, security, and more
Ribbon – client side load balancer
Feign – declarative REST client
Eureka – service registration and discovery
Sleuth – distributed tracing via logs
Zipkin – distributed tracing system with request visualization.
Here you'll find my working solution, with pvpkiran advice and following this method multipart upload with HttpClient4 :
In AngularApp, http post request :
public void batchAppUploadFile(String fileName) {
log.i("Creating HTTP POST Request to upload a file on batchApp server");
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(myFile_URL);
File file = new File(Paths.get("upload-dir").resolve(fileName).toString());
FileBody fileBody = new FileBody(file, ContentType.DEFAULT_BINARY);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addPart("file", fileBody);
HttpEntity entity = builder.build();
post.setEntity(entity);
log.i("Executing HTTP Request...");
try {
HttpResponse response = client.execute(post);
log.i("The request went well !");
ResponseEntity.status(HttpStatus.OK).body("SUCESS BS upload");
} catch (Exception e) {
log.i("The request failed !");
ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body("FAIL BS upload");
}
}
My controller in batchApp :
#PostMapping("/uploadfile")
public ResponseEntity<String> handleFileUpload(#RequestParam("file") MultipartFile file) {
try {
Path uploadPath = Paths.get(getUploadDirectory(file));
Files.copy(file.getInputStream(), uploadPath.resolve(file.getOriginalFilename()));
log.i(file.getOriginalFilename() + " upload complete !");
} catch (Exception e) {
throw new RuntimeException("FAIL!");
}
return ResponseEntity.status(HttpStatus.OK).body("Uploaded on batchApp");
}

Generic Error page Angular JS + Spring MVC + Controller Advice

similar or related question to this post.
I have written the multiple service calls using angular JS. psudo code here
$http.get('name').success(function(response){
$scope.name= response;
$log.info($scope.rate);
}).error(function() {
});
Now I would like to route to single error page let say error.html for any exception occurs
how would I route to error.html page in Angular JS instead of touching the hundreds of service calls.
I know I would have written/route in the error function below , but I DO NOT want to repeat in reset of my application or hundreds of service calls.
what is the alternate way. please respond
$http.get('indexrates').success(function(response){
$scope.rates= response;
$log.info($scope.rates);
}).error(function() {
$state.go('error');
});
Reference : https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
#ControllerAdvice
class GlobalDefaultExceptionHandler {
public static final String DEFAULT_ERROR_VIEW = "error";
#ExceptionHandler(value = Exception.class)
public ModelAndView
defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
// If the exception is annotated with #ResponseStatus rethrow it and let
// the framework handle it - like the OrderNotFoundException example
// at the start of this post.
// AnnotationUtils is a Spring Framework utility class.
if (AnnotationUtils.findAnnotation
(e.getClass(), ResponseStatus.class) != null)
throw e;
// Otherwise setup and send the user to a default error-view.
ModelAndView mav = new ModelAndView();
mav.addObject("exception", e);
mav.addObject("url", req.getRequestURL());
mav.setViewName(DEFAULT_ERROR_VIEW);
return mav;
}
}

spring deferred result response in weblogic

I have implemented DeferredResult in spring MVC. It returns the right response in Tomcat8 but when I deployed into weblogic 12.1.3 gives me 404 error. I tried to debug to find out what is going on then at some point handler is looking for view in web-inf directory. I am confused here.
Could you please help me to understand?
I am using Spring
Java 7
Spring 4.2.0.RELEASE
Spring OAuth2
Weblogic 12.1.3
#RequestMapping(value = "/file/{id}")
#ResponseBody
public DeferredResult<ResponseEntity<Resource>> file(#PathVariable String id) {
DeferredResult<ResponseEntity<Resource>> result = new DeferredResult<>();
try {
final ImageObject image = null;
final Resource fileResource = new FileSystemResource(image.getImagePath().replace("E:", "C:"));
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentLength(fileResource.contentLength());
result.setResult(new ResponseEntity<>(fileResource, headers, HttpStatus.OK));
} catch (Exception e) {
}
return result;
}
Thanks in advance.
In my case Spring wrongly concatenated a #RequestMapping path of #RestController and #RequestMapping path of a method. #RequestMapping path of #RestController was duplicated in a resulting URI in Spring logs.
The only workaround I've found is to create #RestControllers for each required DeferredResult method without specifying a #RequestMapping path in the methods.
WebLogic 12.2.1.3.0, Spring 4.3.23.

Resources