URLDecoder: Illegal hex characters in escape (%) pattern for multipart data - java

I am using multipart to fetch the pdf and object data from the service. I get the below error
java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters
in escape (%) pattern - For input string: "PD" at
java.net.URLDecoder.decode(URLDecoder.java:205) at
org.springframework.http.converter.FormHttpMessageConverter.read(FormHttpMessageConverter.java:186)
when invoking the service.
SERVICE :
#RequestMapping(value = "/getPDF", method = RequestMethod.GET,produces = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<MultiValueMap<String, Object>> getPDF(
#RequestParam String key,
HttpServletResponse response) {
MultiValueMap<String, Object> pdfResultMap = new LinkedMultiValueMap<String, Object>();
//Get the result
ByteArrayResource byteArrayResource = getPdf(); //Assign the PDF
//1) Build the first byte[] result
/* LinkedMultiValueMap<String, String> pdfMap = new LinkedMultiValueMap<>();
pdfMap.add("Content-disposition", "attachment;" );
pdfMap.add("Content-type", "application/pdf");*/
HttpHeaders xHeader2 = new HttpHeaders();
xHeader2.setContentType(MediaType.APPLICATION_PDF);
HttpEntity<ByteArrayResource> doc = new HttpEntity<ByteArrayResource>(byteArrayResource, xHeader2);
pdfResultMap.add("doc", doc);
// 2) Build the next
//Header
HttpHeaders xHeader = new HttpHeaders();
xHeader.setContentType(MediaType.APPLICATION_JSON);
// Get the result
Map<String, String> stringMap = new HashMap<String, String>();
//populate String map
HttpEntity<Map<String, String>> stringMapObject = new HttpEntity<Map<String, String>>(stringMap, xHeader);
pdfResultMap.add("stringMap", stringMapObject);
//3) Build the simple header
HttpHeaders xHeader1 = new HttpHeaders();
xHeader.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> titlePart = new HttpEntity<String>("pdftitle", xHeader1);
pdfResultMap.add("title", titlePart);
ResponseEntity<MultiValueMap<String, Object>> responseEntity = new ResponseEntity<MultiValueMap<String, Object>>(pdfResultMap, HttpStatus.OK);
return responseEntity;
}
CLIENT :
public getPdf() {
FormHttpMessageConverter formConverter = new FormHttpMessageConverter() {
#Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
if (clazz == MultiValueMap.class) {
return true;
}
return super.canRead(clazz, mediaType);
}
};
formConverter.setCharset(Charset.forName("UTF-8"));
List<HttpMessageConverter<?>> partConverters = new ArrayList<HttpMessageConverter<?>>();
partConverters.add(new ByteArrayHttpMessageConverter());
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
stringHttpMessageConverter.setWriteAcceptCharset(false);
partConverters.add(stringHttpMessageConverter);
partConverters.add(new ResourceHttpMessageConverter());
formConverter.setPartConverters(partConverters);
restTemplate.getMessageConverters().add(formConverter);
ResponseEntity<MultiValueMap> response = restTemplate.exchange(builder.build().encode().toUri(), HttpMethod.GET,entity, MultiValueMap.class);
}
I Tried adding :
List<MediaType> a = new ArrayList<MediaType>();
a.add(MediaType.APPLICATION_OCTET_STREAM);
a.add(MediaType.MULTIPART_FORM_DATA);
a.add(new MediaType("application","pdf"));
formConverter.setSupportedMediaTypes(a);
But the same error .
Anything I am missing here?

You try to read from FormHttpMessageConverter but the doc https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/FormHttpMessageConverter.html says
"In other words, this converter can read and write the "application/x-www-form-urlencoded" media type as MultiValueMap and it can also write (but not read) the "multipart/form-data" media type as MultiValueMap."

Related

How to Get particular value from restTemplate in springboot?

I have an api with given request body and response , now I have to call restTemplate for it and get particular response from it
This is my requestBody ->
{"ids":["MS8B50FHS"]}
And this is my response ->
{
"status": 200,
"success": true,
"message": "detail found!",
"data": {
"MS8B50FHS": {
"ids": "MS8B50FHS",
"creditTerm": "Credit 45 days"
}
}
}
Now for this I need to get creditterm by calling a restTemplate
#Override
public String findByUniqueSupplierId (String ids){
final String url = BaseUrl ;
HttpHeaders headers = new HttpHeaders();
HttpEntity<Object> requestEntity = new HttpEntity<>(headers);
Map<String, List<String>> params = new HashMap<>();
params.put("ids", Collections.singletonList(ids));
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> object = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class , params);
return object.getBody();
}
I was trying something like this but not getting result
You can assign JSON data to objects using the fromJson() method from the Gson library.
String body = object.getBody();
Gson gson = new Gson();
Map<String, Object> map = gson.fromJson(body, HashMap.class);
Map<String, Object> data = (Map<String, Object>) map.get("data");
Map<String, Object> creditTerm = (Map<String, Object>) data.get("MS8B50FHS");
String creditTermValue = creditTerm.get("creditTerm").toString();
System.out.println(creditTermValue);
Could be refactored.

RestTemplate POST with query parameter without request body

I am trying a POST method with RestTemplate. I need my request to have only 1 query parameter, without body (e.g. localhost:8080/predictions/init?date=xxxx).
My current code is the following :
String url = "http://localhost:8080/predictions/init";
String dateToGenerate = "xxxx";
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
Map map = new HashMap<String, String>();
map.put("Content-Type", "application/json");
headers.setAll(map);
Map req_payload = new HashMap();
req_payload.put("date", dateToGenerate);
HttpEntity<?> request = new HttpEntity<>(req_payload, headers);
restTemplateApi.postForEntity(url, request, String.class);
The side of the REST controller I'm trying to call is the following :
#PostMapping
#ResponseStatus(HttpStatus.OK)
public PredictionGenerated initializeOnePrediction(#RequestParam #NotEmpty String date) {
.............................
.............................
}
I'm currently receiving org.springframework.web.client.HttpClientErrorException: 400 null.
Any ideas?
If you have any many query param then set all in Multiple value Map as below.
MultiValueMap<String, String> param= new
LinkedMultiValueMap<String, String>();
param.put("date", datevalue);
Then create Http header add required content.
HttpHeaders headers = new HttpHeaders()
header.setContentType("application/json");
Create the URL as below.
URI url = UriComponentsBuilder.fromHttpUrl(base url)
.queryParams(param)
.build();
HttpEntity<?> request = new HttpEntity<>(req_payload,
headers);
restTemplateApi.postForEntity(url, request, String.class);

Rest template for postForEntity with file & other properties

I want to upload the file with Json request in rest template along with other properties. But I couldn't able to do this.
#Bean
public RestTemplate getRestTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder.build();
}
#Autowired
private RestTemplate restTemplate;
#Scheduled(fixedDelay = 1000)
public void _do() throws Exception {
HashMap<String, String> documentProperties = new HashMap<>();
documentProperties.put("number", "123");
MultipartFile file = Somefile;
UploadDocumentRequest uploadDocumentRequest = new UploadDocumentRequest();
uploadDocumentRequest.setDocumentClass("DocClass");
uploadDocumentRequest.setDocumentProperties(documentProperties);
uploadDocumentRequest.setFile(file); ----???
ResponseEntity<String> value = restTemplate.postForEntity("URL", uploadDocumentRequest, String.class);
}
You have to create HttpEntity with header and body.
Set the content-type header value to MediaType.MULTIPART_FORM_DATA.
Build the request body as an instance of LinkedMultiValueMap class.
Construct an HttpEntity instance that wraps the header and the body object and post it using a RestTemplate.
A sample code is shown as follows:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", getFileToBeUploaded());
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.postForEntity(serviveUrl, requestEntity, String.class);

How can I get specific xml tag from output file from my console in java

Here is my code: I have got xml file as output and i need to get one specific tag from that file
try {
RestTemplate restTemplate = new RestTemplate();
final String url = "https://wildfire.paloaltonetworks.com/publicapi/get/verdict";
String apikey = "f719c27d2063d2e25579681a64ebc1ba";
String hash = "a1a3b09875f9e9acade5623e1cca680009a6c9e0452489931cfa5b0041f4d290";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("apikey", apikey);
map.add("hash", hash);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
ResponseEntity responseEntity = restTemplate.postForEntity("https://wildfire.paloaltonetworks.com/publicapi/get/verdict", request, String.class);
System.out.println(responseEntity);
The link below will show you how to convert your XML file (starting with either an XML file or XML String) into a Document.
https://howtodoinjava.com/xml/parse-string-to-xml-dom/
Once you have the document you can simply...
String tag = document.getDocumentElement().getAttribute("<TAG NAME>");
Hope this helps

Sending file over spring rest service via resttemplate

Title might look common but none of them fit in my issue.
I have a rest service which accept normal parameters and file in form of multipart.
i want to use resttemplate to send data and file to above rest service.
till the time i was sending normal string data there was no issue. once i add code of sending bytes then i start getting 400 Bad request error.
if i comment code to send ByteArrayResource then it start working for normal parameters.
below is sample code
Rest service controller
#RestController
#RequestMapping(value="/ticket")
public class UserTicketController {
#RequestMapping(value="/createTicket.do",method={RequestMethod.POST},
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE},headers={"content-type="+MediaType.MULTIPART_FORM_DATA_VALUE})
public void createTicket(#ModelAttribute ServiceDeskRequest serviceDeskRequest, HttpServletRequest request,HttpServletResponse response) throws Exception{
}
}
Servicedeskrequest model attribute is
public class ServiceDeskRequest implements Serializable{
private String jsonData;
private MultipartFile attachment;
}
application-context.xml
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>
Client Side code
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, Object> requestParamerterMap = new LinkedMultiValueMap<String, Object>();
requestParamerterMap.add("jsonData", jsonData);
MultipartFile attachment = userRequest.getAttachment();
if(attachment!=null && attachment.getOriginalFilename()!=null) {
ByteArrayResource byteArrayResource = new ByteArrayResource(attachment.getBytes(), attachment.getOriginalFilename());
requestParamerterMap.add("attachment", byteArrayResource);
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(requestParamerterMap, headers);
String response = restTemplate.postForObject(targetUrl, requestEntity, String.class);
I figured it out. There are two piece in this puzzle. No change in service code.
Providing right converter to resttemplate. In list of default converts spring doesn't add FormHttpMessageConverter.
FormHttpMessageConverter converter = new FormHttpMessageConverter();
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(converter);
overriding bytearrayresource class. plz note you need to override getFilename method so that document name can be received at service side.
public class MultipartByteArrayResource extends ByteArrayResource{
private String fileName;
public MultipartByteArrayResource(byte[] byteArray) {
super(byteArray);
}
public String getFilename() {
return fileName;
}
public void setFilename(String fileName) {
this.fileName= fileName;
}
}
After above changes client code will be
FormHttpMessageConverter converter = new FormHttpMessageConverter();
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(converter);
MultiValueMap<String, Object> requestParamerterMap = new LinkedMultiValueMap<String, Object>();
requestParamerterMap.add("jsonData", jsonData);
MultipartFile attachment = userRequest.getAttachment();
if(attachment!=null && attachment.getOriginalFilename()!=null) {
//ByteArrayResource byteArrayResource = new ByteArrayResource(attachment.getBytes(), attachment.getOriginalFilename());
MultipartByteArrayResource resource = new MultipartByteArrayResource(attachment.getBytes());
//pass file name sepratly
resource.setFilename(attachment.getOriginalFilename());
requestParamerterMap.add("attachment", resource);
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(requestParamerterMap, headers);
String response = restTemplate.postForObject(targetUrls.get("sdCreateTicketsUrl"), requestEntity, String.class);
First, value="/createTicket.do" is way off the REST convention. Same goes for /ticket.
Creation of a ticket should be done by POST to URL: .../tickets/

Categories