How to read HTTP 500 using a Spring RestTemplate client - spring-mvc

A simple Spring Boot REST Controller
#PostMapping(path = "check-and-submit", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<MyOutput> checkAndSave(#RequestBody #Valid MyInput input, Errors errors){
ResponseEntity<MyOutput> result = null;
if (errors.hasErrors()) {
result = new ResponseEntity<>(MyOutput.buildErrorResponse(errors), HttpStatus.INTERNAL_SERVER_ERROR);
} else {
myDao.save(input.buildEntity());
result = new ResponseEntity<>(MyOutput.buildSuccessResponse(), HttpStatus.OK);
}
return result;
}
And the test class for it
public static void main(String[] args) {
MyInput dto = new MyInput();
// set properties
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Content-Type", "application/json");
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<MyInput> request = new HttpEntity<MyInput>(dto, headers);
try {
ResponseEntity<MyOutput> result = restTemplate.postForEntity(URL, request, MyOutput.class);
System.out.println(result);
} catch(Exception e) {
e.printStackTrace();
}
}
For success scenario this works fine. But, for exception scenrio, i.e. HTTP 500 this fails
org.springframework.web.client.HttpServerErrorException: 500 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:97)
As suggested in one of the posts, I created a error-handler that can successfully read the response
public class TestHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
Scanner scanner = new Scanner(response.getBody());
String data = "";
while (scanner.hasNext())
data += scanner.next();
System.out.println(data);
scanner.close();
}
}
But how can I let RestTemplate read and deserialize the response JSON even in case of HTTP 500.
Before any other human-question-flagging-bot marks this as duplicate, here's a humble explanation on how this is different from the others.
All other questions address how to handle HTTP 500, at max read the response-body. This questions is directed at if it is possible to deserialize the response as JSON as well. Such functionality is well established in frameworks such as JBoss RESTEasy. Checking how same can be achieved in Spring.

This should work.
try {
ResponseEntity<MyOutput> result = restTemplate.postForEntity(URL, request, MyOutput.class);
} catch(HttpServerErrorException errorException) {
String responseBody = errorException.getResponseBodyAsString();
// You can use this string to create MyOutput pojo using ObjectMapper.
}

Related

Pact Basic test fails

I am trying a simple pact test but its failing giving the error. Below is my code. Is there any issue with the way I'm trying to call pact.
ERROR:
groovy.json.JsonException: Unable to determine the current character, it is not a string, number, array, or object The current character read is 'T' with an int value of 84
CODE
public class PactTest1 {
#Rule
//public PactProviderRule rule = new PactProviderRule("assessments", this);
public PactProviderRule provider = new PactProviderRule("test_provider", "localhost", 8080, this);
#Pact(state = "default", provider = "test_provider", consumer = "test_consumer")
public PactFragment createFragment(PactDslWithProvider builder) {
Map<String, String> headers = new HashMap<>();
headers.put("content-type", "application/json");
return builder
.given("test GET")
.uponReceiving("GET REQUEST")
.path("/assessments")
.method("GET")
.willRespondWith()
.status(200)
.headers(headers)
.body("Test Successful")
.toFragment();
}
#Test
#PactVerification("test_provider")
public void runTest() {
final RestTemplate call = new RestTemplate();
// when
final String response = call.getForObject(provider.getConfig().url()+"/assessments", String.class);
assertEquals(response, "Test Successful");
}
}
It worked after the changed the header content type to text/json. However I'm not able to find the pact file. Where can I find it?

How to send http request parameters using Jersey client

I use the following rest client implementation of jersey to consume a rest service.I am able to do it successfully.Additionally now I need to send request parameters which will be consumed as part of HttpServletRequest on the producer side.
Consumer side Jersey client code
private ClientResponse getWebClientResponse(String RESOURCE_PATH, String methodType, Object requestObj) {
WebResource webResource;
ClientResponse response = null;
try {
String environmentHost = EnvironmentUtil.resolveEnvironmentHost();
Client client = prepareClient();
String RWP_BASE_URI = environmentHost + "/workflow/rest";
webResource = client.resource(RWP_BASE_URI);
WebResource path = webResource.path(RESOURCE_PATH);
if (GET.equals(methodType)) {
response = path.type(javax.ws.rs.core.MediaType.APPLICATION_JSON).get(
ClientResponse.class);
} else if (POST.equalsIgnoreCase(methodType)) {
response = path.type(javax.ws.rs.core.MediaType.APPLICATION_JSON).post(ClientResponse.class, requestObj);
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
return response;
}
Producer side
#Context
public void setContext(SecurityContext context) {
this.context = context;
}
public HttpServletRequest getRequest() {
return request;
}
#Context
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public String getSessionUserPID(final HttpServletRequest request,
final SecurityContext context) {
if (request.getSession(false) == null) {
final String exceptionMessage = "getSessionUserPID() failed, session NOT FOUND for this request";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
if (context.getUserPrincipal() == null) {
final String exceptionMessage = "getSessionUserPID() failed, user principal NOT FOUND";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
final String userPID = context.getUserPrincipal().getName();
if (userPID == null || userPID.isEmpty()) {
final String exceptionMessage = "getSessionUserPID() failed, user principal name cannot be null or empty";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
return userPID;
}
The main intention here is currently I get user information from weblogic security context but for a particular scenario I need to pass this part of rest service request and obtain it from HttpServletRequest object.How can I obtain this from httpservletrequest
You can use QueryParam or PathParam in GET method and FormParam in the POST method for sending request parameter to the server.

java.lang.NoClassDefFoundError: Failed resolution of: Lokio/Buffer;

when i use retrofit .I got the exception java.lang.NoClassDefFoundError: Failed resolution of: Lokio/Buffer;i use okhttpclient in order to set header for retrofit.get userList is a post method,and i need to send body in request.
private void getUserList(int startIndex){
final JSONObject audienceObj = ProtocolHelper.getProtocolUtils(mContext).getUserlistJsonObj(mRoomData.mUid, mRoomData.mRoomId, startIndex);
OkHttpClient okClient = new OkHttpClient.Builder()
.addInterceptor(
new Interceptor() {
#Override
public okhttp3.Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("sessionId", CommonData.getUserInfo(mContext).sessionId);
Request request = requestBuilder.build();
return chain.proceed(request);
}
})
.build();
String baseUrl = ProtocolUtils.BASE_URL+"/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(okClient)
.build();
String audienceUrl = ProtocolHelper.getProtocolUtils(mContext).getProtocolUrl(ProtocolUtils.PROTOCOL_MSG_ID_MEMBER_LIST);
AudienceInterface audienceInterface = retrofit.create(AudienceInterface.class);
Call<String> call = audienceInterface.getAudienceList(audienceUrl,audienceObj);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.d(TAG, "onResponse");
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.d(TAG, "onFailure"+t.getMessage());
}
});
}
public interface AudienceInterface {
#POST("{url}")
Call<String>getAudienceList(#Path("url") String url,#Body JSONObject boder);
}
the log t.getMessage is :java.lang.NoClassDefFoundError: Failed resolution of: Lokio/Buffer;
I solved it by adding:
implementation 'com.squareup.okio:okio:2.1.0'
in dependencies under build.gradle(Module: app).
Alright.~I found this error last time too.
By this:
NoClassDefFoundError: Failed resolution of: Lokio/Buffer
You might lost another jar lib--Okio.
You can download the jar file from github:
https://github.com/square/okio
And add this lib to your project.

Play Framework and custom http headers. How to?

I need to send custom HTTP header with login information to my play application (play 1.2.5). That custom header is added by filter.
Problem is that play always throws NullPointerException when I attempt to read:
String loggedUser = request.headers.get("loggeduser").value();
I have also a servlet for testing, where following prints vale from header correctly.
out.println(request.getHeader("loggeduser"));
Am I missing something in play?
Thanks
EDIT: This is my filter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
CustomHeaderWrapper wrapper = new CustomHeaderWrapper((HttpServletRequest) request);
String username = ((HttpServletRequest) request).getRemoteUser();
wrapper.addHeader("loggeduser", username);
chain.doFilter(wrapper, response);
}
And CustomHeaderWrapper:
private Map<String, String> customHeaderMap = null;
public CustomHeaderWrapper(HttpServletRequest request) {
super(request);
customHeaderMap = new HashMap<String, String>();
}
#Override
public String getHeader(String name) {
String header = super.getHeader(name);
return (header != null) ? header : this.getParameter(name);
}
#Override
public Enumeration getHeaderNames() {
List<String> names = Collections.list(super.getHeaderNames());
names.addAll(Collections.list(super.getParameterNames()));
return Collections.enumeration(names);
}
#Override
public String getParameter(String name) {
String paramValue = super.getParameter(name); // query Strings
if (paramValue == null) {
paramValue = customHeaderMap.get(name);
}
return paramValue;
}
public void addHeader(String headerName, String headerValue) {
customHeaderMap.put(headerName, headerValue);
}
I created a little test project, and used the line of code from your question. It works perfectly. I used the Dev HTTP Client plugin for Chrome to set the header.
Remember that all headers are converted to lowercase, before they are added to the request.headers hashmap. So if you placed "loggedUser" inside request.headers.get(), it would never work.

Handling MaxUploadSizeExceededException with Spring MVC

How can I intercept and send custom error messages with file upload when file size is exceeded. I have an annotated exception handler in the controller class, but the request does not come to the controller. The answer I came across on this link How to handle MaxUploadSizeExceededException suggests implementing HandlerExceptionResolver.
Have things changed in Spring 3.5 or is that still the only solution?
I ended up implementing HandlerExceptionResolver:
#Component public class ExceptionResolverImpl implements HandlerExceptionResolver {
private static final Logger LOG = LoggerFactory.getLogger(ExceptionResolverImpl.class);
#Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object obj, Exception exc) {
if(exc instanceof MaxUploadSizeExceededException) {
response.setContentType("text/html");
response.setStatus(HttpStatus.REQUEST_ENTITY_TOO_LARGE.value());
try {
PrintWriter out = response.getWriter();
Long maxSizeInBytes = ((MaxUploadSizeExceededException) exc).getMaxUploadSize();
String message = "Maximum upload size of " + maxSizeInBytes + " Bytes per attachment exceeded";
//send json response
JSONObject json = new JSONObject();
json.put(REConstants.JSON_KEY_MESSAGE, message);
json.put(REConstants.JSON_KEY_SUCCESS, false);
String body = json.toString();
out.println("<html><body><textarea>" + body + "</textarea></body></html>");
return new ModelAndView();
}
catch (IOException e) {
LOG.error("Error writing to output stream", e);
}
}
//for default behaviour
return null;
}
}

Resources