Spring RestTemplate UnsupportedOperationException with Collections$UnmodifiableCollection.add(Unknown Source) - java

This is our rest template config
#Bean
public RestTemplate infoBloxRestTemplate() {
RestTemplate restTemplate=new RestTemplate();
ArrayList<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(httpBasicAuthenticationInterceptor());
restTemplate.setInterceptors(interceptors);
restTemplate.getMessageConverters().add(jacksonConverter());
restTemplate.setRequestFactory(genericHttpRequestFactory());
return restTemplate;
}
We are trying to make a POST call which works successfully with Postman and returns proper response.
final HttpHeaders headers = new HttpHeaders();
headers.add("Accept", "application/json");
headers.add("Content-Type", "application/json");
HttpEntity<Object> httpEntity = new HttpEntity<Object>(record, headers);
StringBuilder uri = new StringBuilder(infobloxRestClient.createUrl("/record:host"));
infobloxRestClient.getRestTemplate().exchange(uri.toString(), HttpMethod.POST, httpEntity, String.class);
But this POST invocation fails with below error. Here is my stack trace:
com.sun.xml.ws.server.sei.TieHandler createResponse
SEVERE: null
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.add(Unknown Source)
at org.springframework.http.HttpHeaders.add(HttpHeaders.java:558)
at com.test.externalinterfaces.HTTPBasicAuthenticationInterceptor.intercept(HTTPBasicAuthenticationInterceptor.java:30)
at org.springframework.http.client.InterceptingClientHttpRequest$RequestExecution.execute(InterceptingClientHttpRequest.java:81)
at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:67)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:46)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:49)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:488)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:452)
Any help on this regard will be very helpful.

To get more people know this issue:
#Sameer, I found the problem is you're using HttpHeaders ,you can try to build your header with this code
MultiValueMap<String, String> headers =new LinkedMultiValueMap<String, String>();
And not use the HttpHeaders and then in your HttpEntity to build the object entity as
new HttpEntity<Object>(record, headers);
Then it should solve problem .

Try creating the RestTemplate object in the following way,
ResTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", authorizationProperty); //Can also use add(String headerName, String headerValue)
This way it should works.

Related

Spring boot resttemplate get request found 401 unauthorized exception

Following code snippet receives 401 unauthorized exception :
String uri = "https://api/example.json?status=all";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity entity = new HttpEntity(headers);
ResponseEntity <String> results = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class;

Retrieve a cookie using Spring RestTemplate

I need to get a cookie from a server using Spring RestTemplate. Do you guys know how I can perform this?
Thank you for your help!
final String url = "http://codeflex.co:8080/rest/Management/login";
RestTemplate template = new RestTemplate();
Credentials cred = new Credentials();
cred.setUserName("admin#codeflex.co");
cred.setPassword("godmode");
HttpEntity<Credentials> request = new HttpEntity<>(cred);
HttpEntity<String> response = template.exchange(url, HttpMethod.POST, request, String.class);
HttpHeaders headers = response.getHeaders();
String set_cookie = headers.getFirst(HttpHeaders.SET_COOKIE);
code from the example
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", "JSESSIONID=" + session.getValue());
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity rssResponse = restTemplate.exchange(
"https://jira.example.com/sr/jira.issueviews:searchrequest-xml/18107/SearchRequest-18107.xml?tempMax=1000",
HttpMethod.GET,
requestEntity,
Rss.class);
Rss rss = rssResponse.getBody();
from http://springinpractice.com/2012/04/08/sending-cookies-with-resttemplate

HTTPClientErrorException: 400 Bad Request using Spring REST template

String Stringifiedjson = new Gson().toJson(user);
Log.d("SpringAndroid", Stringifiedjson);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAccept(Collections.singletonList(new
MediaType("application", "json")));
HttpEntity <? > requestEntity = new HttpEntity < Object >
(Stringifiedjson, requestHeaders);
GsonHttpMessageConverter messageConverter = new GsonHttpMessageConverter();
List < HttpMessageConverter <? >> messageConverters =
new ArrayList < HttpMessageConverter <? >> ();
messageConverters.add(messageConverter);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(messageConverters);
try {
ResponseEntity<String> responseEntity = restTemplate.
exchange(url, HttpMethod.POST, requestEntity, String.class);
}
I am getting a 400 Bad Request, but when i send the Stringifiedjson in my fiddler. I get a valid response. Now how to post the GSON Object using RestTemplate
I had this same problem. I solved it by passing the Object itself instead of a String containing the JSON representation of that Object.
In short, I changed:
String jsonObject = convertToJSON(myObject);
HttpEntity <? > requestEntity = new HttpEntity <String>
(jsonObject, requestHeaders);
To:
HttpEntity <? > requestEntity = new HttpEntity <MyObject>
(myObject, requestHeaders);
MyObject in this case is the java bean I want to be catched in the #RequestBody parameter of the Controller.
I think the problem could be with your http request headers
The below worked for me.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

Spring RestTemplate postForObject with Header: webservice can't find my header parameters

I'm struggling with RestTemplate. I need to POST some authentication information to a rest webservice. I can send a request and I get a response. But according to the response my header parameters are not getting through. (Sending the same request with SOAPUI works fine)
This is my code:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.add("companyId", companyId);
headers.add("password", password);
HttpEntity<String> request = new HttpEntity<String>(headers);
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new MappingJacksonHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
LoginResponse response = (LoginResponse)restTemplate.postForObject(url, request, LoginResponse.class);
Anyone who can tell me what's wrong with my HttpEntity or HttpHeader?
thank you.
SOLVED:
Ok, finally got it working.
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("companyId", companyId);
map.add("password", password);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new MappingJacksonHttpMessageConverter());
messageConverters.add(new FormHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
LoginResponse response = (LoginResponse) restTemplate.postForObject(url, request, LoginResponse.class);
Because I also had a hard time on the response, maybe it can be useful to others:
#JsonIgnoreProperties(ignoreUnknown = true)
public class ItcLoginResponse {
public String loginToken;
#JsonProperty("token")
public String getLoginToken() {
return loginToken;
}
public void setLoginToken(String loginToken) {
this.loginToken = loginToken;
}
}
You're setting a header indicating you're posting a form (APPLICATION_FORM_URLENCODED), but then setting companyId and password as HTTP headers.
I suspect you want those fields to be in the body of your request.
You're also creating an HttpEntity<String> which indicates you're going to post a request body containing a String, but you're providing headers but no String.
If that doesn't help you fix it perhaps you can explain what the request is supposed to look like.

Making authenticated POST requests with Spring RestTemplate for Android

I have a RESTful API I'm trying to connect with via Android and RestTemplate. All requests to the API are authenticated with HTTP Authentication, through setting the headers of the HttpEntity and then using RestTemplate's exchange() method.
All GET requests work great this way, but I cannot figure out how to accomplish authenticated POST requests. postForObject and postForEntity handle POSTs, but have no easy way to set the Authentication headers.
So for GETs, this works great:
HttpAuthentication httpAuthentication = new HttpBasicAuthentication("username", "password");
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAuthorization(httpAuthentication);
HttpEntity<?> httpEntity = new HttpEntity<Object>(requestHeaders);
MyModel[] models = restTemplate.exchange("/api/url", HttpMethod.GET, httpEntity, MyModel[].class);
But POSTs apparently don't work with exchange() as it never sends the customized headers and I don't see how to set the request body using exchange().
What is the easiest way to make authenticated POST requests from RestTemplate?
Ok found the answer. exchange() is the best way. Oddly the HttpEntity class doesn't have a setBody() method (it has getBody()), but it is still possible to set the request body, via the constructor.
// Create the request body as a MultiValueMap
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
body.add("field", "value");
// Note the body object as first parameter!
HttpEntity<?> httpEntity = new HttpEntity<Object>(body, requestHeaders);
ResponseEntity<MyModel> response = restTemplate.exchange("/api/url", HttpMethod.POST, httpEntity, MyModel.class);
Slightly different approach:
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("HeaderName", "value");
headers.add("Content-Type", "application/json");
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<ObjectToPass> request = new HttpEntity<ObjectToPass>(objectToPass, headers);
restTemplate.postForObject(url, request, ClassWhateverYourControllerReturns.class);
I was recently dealing with an issue when I was trying to get past authentication while making a REST call from Java, and while the answers in this thread (and other threads) helped, there was still a bit of trial and error involved in getting it working.
What worked for me was encoding credentials in Base64 and adding them as Basic Authorization headers. I then added them as an HttpEntity to restTemplate.postForEntity, which gave me the response I needed.
Here's the class I wrote for this in full (extending RestTemplate):
public class AuthorizedRestTemplate extends RestTemplate{
private String username;
private String password;
public AuthorizedRestTemplate(String username, String password){
this.username = username;
this.password = password;
}
public String getForObject(String url, Object... urlVariables){
return authorizedRestCall(this, url, urlVariables);
}
private String authorizedRestCall(RestTemplate restTemplate,
String url, Object... urlVariables){
HttpEntity<String> request = getRequest();
ResponseEntity<String> entity = restTemplate.postForEntity(url,
request, String.class, urlVariables);
return entity.getBody();
}
private HttpEntity<String> getRequest(){
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + getBase64Credentials());
return new HttpEntity<String>(headers);
}
private String getBase64Credentials(){
String plainCreds = username + ":" + password;
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
return new String(base64CredsBytes);
}
}
Very useful
I had a slightly different scenario where I the request xml was itself the body of the POST and not a param. For that the following code can be used - Posting as an answer just in case anyone else having similar issue will benefit.
final HttpHeaders headers = new HttpHeaders();
headers.add("header1", "9998");
headers.add("username", "xxxxx");
headers.add("password", "xxxxx");
headers.add("header2", "yyyyyy");
headers.add("header3", "zzzzz");
headers.setContentType(MediaType.APPLICATION_XML);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));
final HttpEntity<MyXmlbeansRequestDocument> httpEntity = new HttpEntity<MyXmlbeansRequestDocument>(
MyXmlbeansRequestDocument.Factory.parse(request), headers);
final ResponseEntity<MyXmlbeansResponseDocument> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity,MyXmlbeansResponseDocument.class);
log.info(responseEntity.getBody());

Categories