Spring Jersey Corrupts Binary Data - java

I have a controller like that:
#POST
#Path("/{mon}/update")
public Response update(#PathParam("mon") String mon, #QueryParam("er") String er, #Context HttpServletRequest httpServletRequest, String data) {
...
}
When I send XML or JSON data there is not a problem. However when I send binary data I see that data is corrupted. I had a character encoding chain for UTF-8 and I removed it but problem did not resolved.
Any ideas?
EDIT: I've detect the problem. I've changed my controller as like that and converted my variable into String if needed:
#POST
#Path("/{mon}/update")
public Response update(#PathParam("mon") String mon, #QueryParam("er") String er, #Context HttpServletRequest httpServletRequest, byte[] data) {
...
}
How can I solve this problem?

Related

Can we use multipart and #RequestBody together in spring?

I want to create a API which can have parameter as multipart file and JSON object (#RequestBody). Please find following snippet while calling this API. I am getting HTTP 415 Unsupported Media Type error. If I remove #RequestBody LabPatientInfo reportData then it works fine.
#RequestMapping(value={"/lab/saveReport"}, method={RequestMethod.POST},
consumes={"multipart/form-data"}, headers={"Accept=application/json"})
#ResponseBody
public ResponseEntity<String>
saveReport(#RequestParam(value="reportFile") MultipartFile reportFile,
#RequestBody LabPatientInfo reportData) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
logger.info("in Lab Save Report");
logger.info("Report Data {} ", reportData);
//logger.info("Request BODY {} ", request.getAttribute("data"));
return new ResponseEntity<String>(HttpStatus.OK);
}
following is LabPatientInfo class.
#RooJson(deepSerialize = true)
#RooToString
public class LabPatientInfo {
private String firstName;
private String phoneNumber;
private String DateOfBirth;
private Integer age;
private String gender;
private String refferedBy;
private String reportfile;
private String reportType;
private String reportDate;
private String purpose;
private String followUpDate;
private List<ReportDataInfo> analytes;
while hitting API I am passing following JSON object with uploaded file..
{
"firstName":"abc",
"phoneNumber":"898989",
"DateOfBirth":"asas",
"age":"asas",
"gender":"asas",
"refferedBy":"asas",
"reportfile":"asas",
"reportType":"asas",
"reportDate":"asas",
"purpose":"asas",
"followUpDate":"asas",
"analytes":null
}
You can use #RequestPart like below. This will support both json object and multipart file.
#ResponseBody
public ResponseEntity<String>
saveReport(#RequestPart (value="reportFile") MultipartFile reportFile,
#RequestPart LabPatientInfo reportData) throws IOException {
In order to test it using curl you can create one file for your json part (reportData). Say for example you create "mydata.json" file and paste your json payload in it. And say your reportFile is "report.txt". Now you can send request using curl like below.
curl -v -H "Content-Type:multipart/form-data" -F "reportData=#mydata.json;type=application/json" -F "reportFile=#report.txt;type=text/plain" http://localhost:8080/MyApp/lab/saveReport
An example of a post method which receives a json object and a generic file:
public ResponseEntity<Resource> postGenerateReport(#RequestPart GenerateReportDTO, generateReportDTO, #RequestPart MultipartFile jxhtmlReport)
For the PostMan setup (or curl or anyother REST test utility) you just have to add form-data request with 2 elements:
Key:generateReportDTO, Value: File with .json extension (and compatible content with the object)
Key:jxhtmlReport, Value: just any file.
Gl
When a parameter is annotated with #RequestPart the content of the part is passed through an HttpMessageConverter to resolve the method argument with the 'Content-Type' of the request part in mind. This is analogous to what #RequestBody does to resolve an argument based on the content of a regular request.
so, we can parse #Requestbody as #RequestPart as "abaghel" and reportData need to be a json file.
Spring Roo 2.0.0.M3 includes support for automatic scaffolding of a REST API.
For complete information, see the REST API in the reference manual.
Note the M3 version generate artifacts that could change in newer versions, so your project might not upgrade automatically if you open it with RC1 or above.
May the Force be with you.

Receiving a MultiPart file and JSON data using Spring and AngularJS

Here's my controller below:
#RequestMapping(value="/upload", method=RequestMethod.PUT)
public ResponseEntity<String> handleFileUpload(
#RequestParam("file") MultipartFile file,
#RequestParam("data") String campaignJson,
Principal principal) throws JsonParseException, JsonMappingException, IOException {
I want to be able to receive a MultipartFile as well as a JSON string containing data associated to the file (title, description, etc).
I can get MultipartFile uploading to work on it's own, and I can receive a JSON string and parse it on its own, but when I have them together in 1 controller, it fails. Whenever I print out the String campaignJson it says [object Object] instead of the data that I'm sending (when I print out the data being sent in angular, it's in correct JSON format.)
I've tried #RequestBody, #RequestParam, #RequestPart, but to no avail.
My question is: How do I receive both a MultipartFile and data in the form of JSON in one Spring controller?
This worked for me :
#RequestMapping(value = "/{id}/upload", method = RequestMethod.PUT)
public DocumentResource uploadPut(#PathVariable("id") Long id,
MultipartHttpServletRequest request,
HttpServletResponse response) {
String next = request.getFileNames().next();
MultipartFile file = request.getFile(next);
.....
}
Edit :
Using the MultipartHttpServletRequest should not limit you in any way to use other #PathVariables or #RequestParams, so passing title and description should be possible.
I used it to upload multiple images with AngularJS and FileUploader
( angular-file-upload v1.1.5 )
like this
var uploader = new FileUploader({
url: config.apiUrl('/machine/' + $scope.id + '/images/'),
method: "post",
queueLimit: maxFiles
});

Spring mvc send an excel as byte array to server error

In our spring mvc project we simply send an .xlsx file to the server on a DTO object:
DtoClass {
private String filename;
private byte[] array;
}
now on the server we receive this file through a simple controller.
The problem is when we save this simple excel file on to the disk from this byte[] the file is corrupted.
Any ideas why?
p.s the client sends the byte array with encoding using base64.
Another interesting fact - txt files actually work and can be opened regularly with a text editor after being sent from client-> server
Have a look at MultipartFile.
You can either update the DTO to have MultipartFile as field or can send it directly.
Approach 1 - MultipartFile as part of DTO
Update the DTO as below
DtoClass {
private String filename;
private MultipartFile file;
// getter & setters
}
The controller should look like below
#RequestMapping(value = "/doUpload/", method = RequestMethod.POST )
public void uploadMultipart(
final HttpServletRequest request,
#RequestParam("file") DtoClass dto) { ... }
Approach 2 - MultipartFile sent directly
Here your controller would look like something as below
#RequestMapping(value = "/doUpload/", method = RequestMethod.POST )
public void uploadMultipart(
final HttpServletRequest request,
#RequestParam("file") final MultipartFile multiPartFile) { ... }
P.S.: Make sure you make an entry of <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" /> in your config file.
Also client should set enctype="multipart/form-data"

How to calculate MD5 hash of multipart request body using Jersey

I am using Jersey and I need to calculate the MD5 hash of the body of a multipart post request. My current resource method signature looks like this:
#POST
#Consumes("multipart/form-data")
#Produces("application/json")
public String post(
#FormDataParam("name") String name,
#FormDataParam("description") String description,
#FormDataParam("iconfile") FormDataBodyPart part,
#Context HttpServletRequest hsr) {
// ...
}
I did not find a way to get the raw request body, that I need to calculate the MD5 hash. When my resource method is invoked the input stream from the HttpServletRequest (hsr.getInputStream()) is already consumed and I can not read it again.
I tried changing my method signature to the following:
#POST
#Consumes("multipart/form-data")
#Produces("application/json")
public String test(byte[] bytes) {
// ...
}
This way I get the raw bytes of the request body and I can successfully calculate the MD5 hash but I don't know how to handle the multipart request from there (split the parts, get each part, etc.). Do I have to resort to handle the raw request myself? Or can I let Jersey do the dirty job and extract the FormDataParams for me and let me calculate the MD5 hash somehow?
Thanks,
This is what I ended up doing:
I created a container request filter that consumes the entity input stream, calculates the MD5 checksum and sets the entity input stream again so it can be consumed by Jersey to handle the multipart request and extract the FormDataParams for me.
I also injected the HttpServletRequest both in my filter and my resource method to communicate data between the two.
This is the filter class:
public class MD5CheckFilter implements ContainerRequestFilter {
#Context HttpServletRequest hsr;
public ContainerRequest filter(ContainerRequest request) {
byte[] bytes = request.getEntity(byte[].class); // this consumes the entity input stream
String contentMD5 = calculateMD5(bytes);
hsr.setAttribute("contentMD5", contentMD5);
// set the entity input stream so it can be consumed again
request.setEntityInputStream(new ByteArrayInputStream(bytes));
return request;
}
}
This is the relevant section of my web.xml within the servlet section:
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>path.to.MD5CheckFilter</param-value>
</init-param>
This way I don't need to change the original method signature:
#POST
#Consumes("multipart/form-data")
#Produces("application/json")
public String post(
#FormDataParam("name") String name,
#FormDataParam("description") String description,
#FormDataParam("iconfile") FormDataBodyPart part,
#Context HttpServletRequest hsr) {
// ...
}

spring mvc jquery ajax response as json encoding issue

Recenlty I have big problem with Polish Characters in JSON response from the server. I have simple Ajax request for this:
jQuery.ajax( "/GetSimpleRuleList",
{
type:"GET",
responseType:"application/json;charset=utf-8",
contentType:"application/json;charset=utf-8",
cache:false
} ).done( function ( data )
{
console.log( data );
//nevermind here
} );
And appropriate Controller at server end:
#RequestMapping(value = "/GetSimpleRuleList", method = RequestMethod.GET)
public
#ResponseBody
String getRuleList( ServletResponse response )
{
//magically getting my list here
response.setCharacterEncoding( "UTF-8" );
return //Using JACKSON ObjectWriter here
}
Now I'm 100% sure that encoidng on server side and database from where I take data from is OK, no problem with that.
But when It comes to reading response from server it is:
???
instead of Polish char like:
ąćź
Moreover it only fails when receiving response from server, while sending a request with data is encoded correctly.
In my web.xml I have filter for character encoding.
Any help with this? I'm out of ideas.
Now I'm 100% sure that encoidng on server side and database from where I take data from is OK
try adding the Content-Type header if it's not already present int your response:
response.setHeader("Content-Type", "application/json;charset=UTF-8")
Get sure to use UTF-8 charset when reading from database. Jackson's encoding defaults to UTF-8, so your data might not be encoded using UTF-8?!?
what encoding do you use when reading from database? maybe ISO-8859-2?
Try changing your response type to org.springframework.http.ResponseEntity
public ResponseEntity<String> getRuleList(){
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "application/json; charset=utf-8");
responseHeaders.setCacheControl("no-cache, max-age=0");
String allyourjson = "yourjsongoeshere";
return new ResponseEntity<String>(allyourjson, responseHeaders, HttpStatus.OK);
}
You can use spring annotation RequestMapping above controller class for receveing application/json;utf-8 in all responses
#Controller
#RequestMapping(produces = {"application/json; charset=UTF-8","*/*;charset=UTF-8"})
public class MyController{
...
#RequestMapping(value = "/GetSimpleRuleList", method = RequestMethod.GET)
public
#ResponseBody
String getRuleList( ServletResponse response )
{
//magically getting my list here
response.setCharacterEncoding( "UTF-8" );
return //Using JACKSON ObjectWriter here
}
...
}

Categories

Resources