Below is the logic that I used for RestTemplate. For 1000 requests made, 50 requests fail intermittently. I have to trigger a GET request which sends List<Students> in the response. Hence used ParameterizedTypeReference.
The logger "Outbound request" displays in the logs and after that I received:org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.StackOverflowError.
The logger "Inbound response" is not displaying.
Code:
private RestTemplate restTemplate;
public List<Students> getConsents(Long managementid) {
List<Students> studentList = new ArrayList<>();
RequestEntity<String> requestEntity = buildRequestEntity(managementid);
ResponseEntity<List<Students>> response = null;
LOGGER.info("Outbound request");
response = restTemplate.exchange(requestEntity, new ParameterizedTypeReference<List<Students>>() {});
LOGGER.info("Inbound response");
if(null != response && response.getStatusCode().is2xxSuccessful())
studentList = response.getBody();
return studentList;
}
private RequestEntity<String> buildRequestEntity(Long managementid) {
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
URI uri = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("managementid", managementid)
.build()
.toUri();
return new RequestEntity<>(headers, HttpMethod.GET, uri);
}
Stack Trace:
org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.StackOverflowError
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1053)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at ....
.....
at java.base/sun.nio.ch.Invoker$2.run(Invoker.java:219)
at java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.StackOverflowError: null
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
......
Please help me if I have used the RestTemplate wrong or if you know why I am receiving this error. This occurs in our production environment and I'm not able to reproduce it in our test environment. All the exception handling is done, I just did not paste it here.
Related
How to throw a custom exception in the proper way when using #javax.validation.Valid?
I'm using #Valid in controller, and #AssertTrue to validate request body fields.
public ResponseEntity<Foo> createFoo(
#Valid #RequestBody Foo FooRequest ...
#AssertTrue()
public boolean isFooValid() {
if (invalid)
return false;
...
}
However, I want to throw customized Exception class in some condition.
#AssertTrue()
public boolean isFooValid() {
if (invalid)
return false;
...
// note below
if (invalidInAnotherCondition)
throw new CustomizedException(...);
}
I know this is not desirable way to utilize #Valid in controller, and #AssertTrue. Nevertheless, as I can make my own Exception class which contains customized error info, with the convenience of #Valid.
However the error happens.
javax.validation.ValidationException: HV000090: Unable to access isFooValid
at org.hibernate.validator.internal.util.ReflectionHelper.getValue(ReflectionHelper.java:245)
at org.hibernate.validator.internal.metadata.location.GetterConstraintLocation.getValue(GetterConstraintLocation.java:89)
at org.hibernate.validator.internal.engine.ValueContext.getValue(ValueContext.java:235)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:549)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidatorImpl.java:515)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:485)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:447)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:397)
at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:173)
at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:117)
at org.springframework.boot.autoconfigure.validation.ValidatorAdapter.validate(ValidatorAdapter.java:70)
at org.springframework.validation.DataBinder.validate(DataBinder.java:889)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.validateIfApplicable(AbstractMessageConverterMethodArgumentResolver.java:266)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:137)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:523)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.reflect.InvocationTargetException: null
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.hibernate.validator.internal.util.ReflectionHelper.getValue(ReflectionHelper.java:242)
... 70 common frames omitted
Caused by: com.finda.services.finda.common.exception.CustomizedException: 'df282e0d-1205-4574-adaa-0af819af66c0'
at ...
... 75 common frames omitted
I think this happens because originally, #AssertTrue throws its own Exception itself and it is to be processed through the internal logic; However, customized thrown Exception is not acceptable which can be seen in Caused by: java.lang.reflect.InvocationTargetException: null and javax.validation.ValidationException: HV000090: Unable to access isFooValid
So my final question is below,
Can I bypass this error, still throwing customized Exception?
I really appreciate that you read this long posting in advance.
Consider the example below where I implemented something like what you asking for:
#RestController
#RequestMapping("/accounts")
public class SavingsAccountController {
private final BankAccountService accountService;
#Autowired
public SavingsAccountController(SavingsAccountService accountService) {
this.accountService = accountService;
}
#PutMapping("withdraw")
public ResponseEntity<AccountBalance> onMoneyWithdrawal(#RequestBody #Validated WithdrawMoney withdrawal, BindingResult errors) {
//this is the validation barrier
if (errors.hasErrors()) {
throw new ValidationException(errors);
}
double balance = accountService.withdrawMoney(withdrawal);
return ResponseEntity.ok(new AccountBalance(
withdrawal.getAccountNumber(), balance));
}
#PutMapping("save")
public ResponseEntity<AccountBalance> onMoneySaving(#RequestBody #Validated SaveMoney savings, BindingResult errors) {
//this is the validation barrier
if (errors.hasErrors()) {
throw new ValidationException(errors);
}
double balance = accountService.saveMoney(savings);
return ResponseEntity.ok(new AccountBalance(
savings.getAccountNumber(), balance));
}
}
In the code above, we're using Bean Validation to check that the user's DTO contains valid information. Any errors found in the DTO are provided through the BindingResult errors variable, from where the developer can extract all the details of what went wrong during the validation phase.
To make it easier for the developers to deal with this pattern, in the code above, I simply wrap the BindingResult into a custom ValidationException which knows how to extract the validation error details.
public class ValidationException extends RuntimeException {
private final BindingResult errors;
public ValidationException(BindingResult errors) {
this.errors = errors;
}
public List<String> getMessages() {
return getValidationMessage(this.errors);
}
#Override
public String getMessage() {
return this.getMessages().toString();
}
//demonstrate how to extract a message from the binging result
private static List<String> getValidationMessage(BindingResult bindingResult) {
return bindingResult.getAllErrors()
.stream()
.map(ValidationException::getValidationMessage)
.collect(Collectors.toList());
}
private static String getValidationMessage(ObjectError error) {
if (error instanceof FieldError) {
FieldError fieldError = (FieldError) error;
String className = fieldError.getObjectName();
String property = fieldError.getField();
Object invalidValue = fieldError.getRejectedValue();
String message = fieldError.getDefaultMessage();
return String.format("%s.%s %s, but it was %s", className, property, message, invalidValue);
}
return String.format("%s: %s", error.getObjectName(), error.getDefaultMessage());
}
}
Notice that in my controller definition I do not use Bean Validation's #Valid annotation, but the Spring counterpart #Validated, but under the hood Spring will use Bean Validation.
How to Serialize the Custom Exception?
In the code above the ValidationException will be thrown when the payload is invalid. How should the controller create a response for the client out of this?
There are multiple ways to deal with this, but perhaps the simplest solution is to define a class annotated as #ControllerAdvice. In this annotated class we will place our exception handlers for any specific exception that we want to handle and turn them into a valid response object to travel back to our clients:
#ControllerAdvice
public class ExceptionHandlers {
#ExceptionHandler
public ResponseEntity<ErrorModel> handle(ValidationException ex) {
return ResponseEntity.badRequest()
.body(new ErrorModel(ex.getMessages()));
}
//...
}
I wrote a few other examples of this and other validation techniques with Spring in case you may be interested in reading more about it.
Here is a solution I used (that might not answer this question directly but possibly help others who get to this page that came with similar intentions as I had):
My aim was foremost to respond with a custom error message to the client who sent a request with an invalid object.
In my controller I use a standard #Valid annotation from javax.validation.Valid before the parameter
In my entity class I use the standard validation constraint, e.g. #NotNull(message = "Field XYZ has to be provided") from javax.validation.constraints.NotNull
I catch the ValidationException in my ControllerAdvice class:
#ControllerAdvice
public class MyControllerAdvice extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException exception,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
return new ResponseEntity<>(
new JSONObject().put("message", extractValidationMessage(exception)).toString(),
HttpStatus.BAD_REQUEST);
}
private String extractValidationMessage(MethodArgumentNotValidException exception) {
String exceptionMessage = exception.getMessage();
String[] messageParts = exceptionMessage.split(";");
String finalPart = messageParts[messageParts.length -1];
return finalPart.trim().replaceAll("default message \\[|]]","");
}
}
This will return a 400 Error code and a body of this style:
{"message":"Field XYZ has to be provided"}
I am testing an API which is supposed to fetch a document from an envelope. Here is the example code:
#RestController
#Controller
#RequestMapping(value = "DocuSign")
public class DocusignController extends CoreController {
#RequestMapping(value = "/FetchPDF", method = RequestMethod.GET)
#ResponseBody
public MessageItem downloadDocument(Model model) throws ApiException, IOException {
WorkArguments args = new WorkArguments();
args.setAccountId("1e8dce91-c5....");
args.setDocumentId("1");
args.setEnvelopeId("ec1f77....");
String accessToken = "eyJ0eXAiOiJNVCIsImFsZyI6I.....";
String baseUrl = "https://demo.docusign.net/restapi";
JSONObject obj = doWork(args, null, accessToken, baseUrl);
MessageItem msg = new MessageItem();
msg.setMsg("Done!");
return msg;
}
protected JSONObject doWork(WorkArguments args, ModelMap model,
String accessToken, String basePath) throws ApiException, IOException {
// Data for this method
// accessToken (argument)
// basePath (argument)
String accountId = args.getAccountId();
String envelopeId = args.getEnvelopeId();
String documentId = args.getDocumentId();
ApiClient apiClient = new ApiClient(basePath);
apiClient.addDefaultHeader("Authorization", "Bearer " + accessToken);
EnvelopesApi envelopesApi = new EnvelopesApi(apiClient);
System.out.println("--->Checking if anything is null...");
if(envelopesApi == null )
System.out.println("Enveloper API is null!");
if(apiClient == null)
System.out.println("The apiClient is null!");
// Step 1. EnvelopeDocuments::get.
// Exceptions will be caught by the calling function
byte[] results = envelopesApi.getDocument(accountId, envelopeId, documentId);
String mimetype = ".pdf";
String docName = "success";
... etc.
When I go and test it with my rest client, I keep getting the following error:
Type Exception Report
Message Request processing failed; nested exception is
com.sun.jersey.api.client.ClientHandlerException
Description The server encountered an unexpected condition that
prevented it from fulfilling the request.
Exception
org.springframework.web.util.NestedServletException: Request
processing failed; nested exception is
com.sun.jersey.api.client.ClientHandlerException
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Root Cause
com.sun.jersey.api.client.ClientHandlerException
com.docusign.esign.client.auth.OAuth.updateAccessToken(OAuth.java:111)
com.docusign.esign.client.auth.OAuth.applyToParams(OAuth.java:99)
com.docusign.esign.client.ApiClient.updateParamsForAuth(ApiClient.java:1209)
com.docusign.esign.client.ApiClient.getAPIResponse(ApiClient.java:1094)
com.docusign.esign.client.ApiClient.invokeAPI(ApiClient.java:1158)
com.docusign.esign.api.EnvelopesApi.getDocument(EnvelopesApi.java:2624)
com.docusign.esign.api.EnvelopesApi.getDocument(EnvelopesApi.java:2556)
delaware.gov.dti.ice.esignprototypev1.controller.DocusignController.doWork(DocusignController.java:82)
delaware.gov.dti.ice.esignprototypev1.controller.DocusignController.downloadDocument(DocusignController.java:52)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Root Cause
java.lang.NullPointerException
com.docusign.esign.client.auth.OAuth.updateAccessToken(OAuth.java:109)
com.docusign.esign.client.auth.OAuth.applyToParams(OAuth.java:99)
com.docusign.esign.client.ApiClient.updateParamsForAuth(ApiClient.java:1209)
com.docusign.esign.client.ApiClient.getAPIResponse(ApiClient.java:1094)
com.docusign.esign.client.ApiClient.invokeAPI(ApiClient.java:1158)
com.docusign.esign.api.EnvelopesApi.getDocument(EnvelopesApi.java:2624)
com.docusign.esign.api.EnvelopesApi.getDocument(EnvelopesApi.java:2556)
delaware.gov.dti.ice.esignprototypev1.controller.DocusignController.doWork(DocusignController.java:82)
delaware.gov.dti.ice.esignprototypev1.controller.DocusignController.downloadDocument(DocusignController.java:52)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
I am using docusign-esign-java version 3.2.0, which is cucrently the latest. I am able to fetch the doucment when using the rest client, so I know that at least my account id, access token and document id (and template id) are correct. Also I am basing my solution from the following DocuSign refrence page Downloading Envelope Documents and using the provided downloaded code just for to doubleche to see if I am missing anything.
Furthermore I checked to see if the apiClient or the envelopesApi objects are null and they are not so I am getting the problem on the
byte[] results = envelopesApi.getDocument(accountId, envelopeId, documentId);
which for some reason, seems to give a null pointer exception. Any idea as to why?
I updated existing example without Spring to test 3.2.0 version, and it seems to work fine for me and it is not throwing any exception. If it is working w/o Spring then it will work with Spring as well, so does not look like any issue in SDK.
public void listDocuments(String envelopeId) throws ApiException, IOException {
this.checkToken();
EnvelopesApi envelopeApi = new EnvelopesApi(this.apiClient);
EnvelopeDocumentsResult envelopeDocumentsResult = envelopeApi.listDocuments(this.getAccountId(), envelopeId);
List<EnvelopeDocument> envelopeDocuments = envelopeDocumentsResult.getEnvelopeDocuments();
for (EnvelopeDocument envelopeDocument : envelopeDocuments) {
System.out.println("documentId " + envelopeDocument.getDocumentId());
envelopeApi.getDocument(this.getAccountId(), envelopeId, envelopeDocument.getDocumentId());
}
}
I have followed this blog and have created few microservices: Eureka-server,Auth-service,Zuul-service,Gallery-service,Image-service.
From the gallery service I wanted to invoke auth-service API using Feign-Client
The url doesn't require authentication but the client throws FeignException$Unauthorized
I'm using JWT tokens for authentication.
//AuthServerProxy.java
#FeignClient(name = "auth-service")
#RibbonClient(name = "auth-service")
public interface AuthServiceProxy {
#PostMapping("/auth/authenticate")
public ResponseEntity<?> authenticate(#RequestBody UserEntity userEntity);
#GetMapping("/auth/register")
public String test();
}
Controller - Gallery Service
#Autowired
AuthServiceProxy authServiceProxy;
#GetMapping("/test")
public String test(){
UserEntity userEntity = new UserEntity();
userEntity.setUsername("admin");
userEntity.setPassword("admin");
ResponseEntity<?> responseEntity = authServiceProxy.authenticate(userEntity);
System.out.println(responseEntity.getStatusCode());
return responseEntity.toString();
}
#GetMapping("/test/str")
public String testStr(){
return authServiceProxy.test();
}
Security Config - ZuulServer, Auth-Service
.antMatchers(HttpMethod.POST, "/auth/authenticate").permitAll()
This is the error log
ERROR 1123 --- [nio-8100-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.FeignException$Unauthorized: status 401 reading AuthServiceProxy#authenticate(UserEntity)] with root cause
feign.FeignException$Unauthorized: status 401 reading AuthServiceProxy#authenticate(UserEntity)
at feign.FeignException.errorStatus(FeignException.java:94) ~[feign-core-10.2.3.jar:na]
at feign.FeignException.errorStatus(FeignException.java:86) ~[feign-core-10.2.3.jar:na]
at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:93) ~[feign-core-10.2.3.jar:na]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:149) ~[feign-core-10.2.3.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78) ~[feign-core-10.2.3.jar:na]
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-10.2.3.jar:na]
at com.sun.proxy.$Proxy101.authenticate(Unknown Source) ~[na:na]
at com.test.gallery.Controller.test(Controller.java:47) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
...
Any help much appreciated.
TIA
Looks like the Authentication header is not passing with FeignClient
try to add this config:
#Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
requestTemplate.header(HttpHeaders.AUTHORIZATION, String.format("Bearer %s", details.getTokenValue()));
}
};
}
Feign is not aware of the Authorization that should be passed to the target service .Unfortunately, you need to handle this yourself.Below is a java class that can help
#Component
public class FeignClientInterceptor implements RequestInterceptor {
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER_TOKEN_TYPE = "Bearer";
#Override
public void apply(RequestTemplate template) {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, details.getTokenValue()));
}
}
It sounds like the problem could be that you don't have the #EnableResourceServer attached to your Auth-Service.
Without that annotation any endpoint that isn't apart of the spring security package (eg. /oauth/token, /oauth/check_token) will automatically require Authorization.
Furthermore you may need to add in a ResourceServerConfigurerAdapter similar to this to make sure that the resource endpoints are configured to permit all like so:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private final TokenStore tokenStore;
public ResourceServerConfig(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.POST).permitAll()
.and()
.logout().disable()
.csrf().disable();
}
}
*******EDIT*********
If you’re able to get an ok response from a request in the browser but not feign then your problem most likely is that your Feign client isn’t pointing to the correct endpoint. Normally you would expect a 404 error but since the API is secured you get a 401 because it doesn’t even allow you to know what’s a valid endpoint unless you’re authenticated or it’s an unsecured endpoint
If you have your AuthServiceProxy feign client use your zuul-server instead of the auth-service, you can then add logging to your zuul filter to see what both successful and unsuccessful requests looks like. From there make the necessary changes to have your proxy request match the request you made from the browser and you should be good to go
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String Empcode="10743";
String password="IsaiVanan";
final String uri = "https://vtop9.vit.ac.in/vtoplogin/employeeLoginPost";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
MultiValueMap<String, String> postParams = new LinkedMultiValueMap<String, String>();
postParams.add("userid",Empcode);
postParams.add("pwd",password);
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<> (postParams,headers);
System.out.println("Try coming1..!");
ResponseEntity<UserValidation> result = restTemplate.exchange(uri, HttpMethod.POST,entity, UserValidation.class);
System.out.print("result..."+result.getBody().getResponseMsg());
I did everything which i add dependency of rest api,
this witch i did response content in application/json still; it not working i find that solution only in some stackoverflow verify..!
public class UserValidation {
private String responseMsg ;
private Integer responseCode;
public String getResponseMsg() {
return responseMsg;
}
public void setResponseMsg(String responseMsg) {
this.responseMsg = responseMsg;
}
public Integer getResponseCode() {
return responseCode;
}
public void setResponseCode(Integer responseCode) {
this.responseCode = responseCode;
}
}
org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.util.LinkedMultiValueMap] and content type [application/json]
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:597)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:436)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:377)
at sample.doGet(sample.java:82)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:475)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:625)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:498)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:796)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1372)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
error occurs when i add jar files in project of build path, namely rest api jar, spring frameworks...
error shows and consult with everyone which they did know about rest api.
which someone please find the solution and get the corrected output please
For retrieving a resource with application/json Accept Header, you need MappingJackson2HttpMessageConverter, which is one of the special HttpMessageConverters which looks like you're missing.
Try adding below just after initializing RestTemplate as :
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new MappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(converters);
// carry on with your code
Spring is not able to parse your request payload (LinkedMultiValueMap) to JSON. Please make sure that you use a converter that can do this. So your request is not sent to the target system.
Please read this for more information: https://www.baeldung.com/spring-httpmessageconverter-rest
Try this -
private HttpEntity<MultiValueMap<String, Object>> makeExportRequestEntity(RequestObject requestObject ) throws IOException {
MultiValueMap<String, Object> bodyMap = new LinkedMultiValueMap<>();
bodyMap.add("DataOne", requestObject .getDataOne());
bodyMap.add("DataTwo", requestObject .getDataTwo());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(bodyMap, headers);
return requestEntity;
}
Ok first of all code (its mega simple):
#Controller
#RequestMapping("/")
public class HelloController {
private final static Logger logger = Logger.getLogger(HelloController.class);
#RequestMapping(method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
logger.info("ELO ELO");
model.addAttribute("message", "Hello world!");
RestTemplate restTemplate = new RestTemplate();
String url = "http://192.168.0.200:8000/GPIO/11/function/in";
//String url = "http://192.168.0.200:8000/GPIO/11/function";
//restTemplate.getForObject(url, String.class);
String test = "";
restTemplate.postForObject(url, null, String.class);
logger.info(test);
return "hello";
}
Next example that I'm not a crazy man here is response from postman (chrome):
And at the end full error log:
type Exception report
message Request processing failed; nested exception is
java.lang.IllegalArgumentException: "None" does not contain '/'
description The server encountered an internal error that prevented it
from fulfilling this request.
exception
org.springframework.web.util.NestedServletException: Request
processing failed; nested exception is
java.lang.IllegalArgumentException: "None" does not contain '/'
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:927)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:811)
javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
root cause
java.lang.IllegalArgumentException: "None" does not contain '/'
org.springframework.http.MediaType.parseMediaType(MediaType.java:697)
org.springframework.http.HttpHeaders.getContentType(HttpHeaders.java:305)
org.springframework.web.client.HttpMessageConverterExtractor.getContentType(HttpMessageConverterExtractor.java:113)
org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:84)
org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:492)
org.springframework.web.client.RestTemplate.execute(RestTemplate.java:447)
org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:295)
pl.piquarium.mvc.HelloController.printWelcome(HelloController.java:35)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:439)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:427)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:915)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:811)
javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
note The full stack trace of the root cause is available in the Apache
Tomcat/8.0.3 logs.
Request headers:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Cookie:__utma=212787668.2094541430.1400264829.1400264829.1400268775.2; __utmz=212787668.1400264829.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Host:192.168.0.200:8000
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36
Response Headers:
Cache-Control:no-cache
Content-Length:2
Content-Type:None
Date:Fri, 16 May 2014 22:37:16 GMT
Server:WebIOPi/0.7.0/Python3.2
Did you try setting headers like below,
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);//or any other required
HttpEntity request = new HttpEntity(null, headers);
RestTemplate restTemplate = new RestTemplate();
String url = "http://192.168.0.200:8000/GPIO/11/function/in";
String response = restTemplate.postForObject(url,request,String.class);
The problem is that the server is returning an invalid content type of None instead of something like text/plain, and Spring REST is choking on it. You will need to add a custom message converter for the None type, not use a typed query and parse the response object yourself, or get the Pi people to fix their broken Web server.