how to read multipart entity from android in jersey web service - java

i am getting multipart entity from android client as shown below.
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(
"http://localhost:9090/MBC_WS/rest/network/mobileUserPictureInsert1");
MultipartEntity reqEntity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("message", new StringBody("hi moni"));
postRequest.setEntity(reqEntity);
HttpResponse response = httpClient.execute(postRequest);
In jersey i am trying to retrieve message but getting only object.the code is:
#Path("/mobileUserPictureInsert1")
#POST
#Consumes("multipart/*")
public String create(MultiPart multiPart){
BodyPartEntity bpe = (BodyPartEntity) multiPart.getBodyParts().get(0).getEntity();
String message = bpe.toString();
here i AM getting some object ony not message value. what mistake i made.pl help me.

Yes the the right result. toString() will just use Object.toString(), which will result in
getClass().getName() + '#' + Integer.toHexString(hashCode())
which is most likely what you're seeing. Unless BodyEntityPart overrides the toString(), which it doesn't. You should instead be getting the InputStream with BodyEntityPart.getInputStream(). Then you can do whatever with the InputStream.
A simple example:
#POST
#Consumes("multipart/*")
public String create(MultiPart multiPart) throws Exception {
String message;
try (BodyPartEntity bpe
= (BodyPartEntity) multiPart.getBodyParts().get(0).getEntity()) {
message = getString(bpe.getInputStream());
}
return message;
}
private String getString(InputStream is) throws Exception {
StringBuilder builder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
String line;
while((line = reader.readLine()) != null) {
builder.append(line).append("\n");
}
}
return builder.toString();
}
On another note: You are already using the Jersey multipart support, you can make life easier and just use its annotation support. For instance, you can just do
#POST
#Consumes("multipart/*")
public String create(#FormDataParam("message") String message){
return message;
}
That is much easier. The #FormDataParam("message") gets the body name that you defined here:
reqEntity.addPart("message", new StringBody("hi moni"));
and converts to to String. As long as there's a MessageBodyReader available for the Content-Type of the body part, it should be able to be auto-converted.
See more on Multipart support
Here's another example showing a file upload

Related

How to send multiple HTTP requests from the same service in Java?

Java noob here. I'm trying to develop a web service as per the following diagram.
When a POST request is sent to the REST server, with certain values, the values (being read from a list, in a loop) get inserted in a table (new row with an id). Server returns HTTP 202 Accepted.
To ensure that the resource(with id from 1) is created, a GET request is issued that returns the POJO as Json.
Finally a PATCH request is sent to update a certain column.
I have written a service class that does all three tasks when each API is called individually. I need to implement something that would automatically execute steps 2 and 3 when a POST request is sent to the server. Here's my code so far.
#Path("attachments")
public class FilesService {
private TiedostoService tiedostoService;
private AttachmentService attachmentService;
#GET
#Path("{id}")
#Produces({MediaType.APPLICATION_JSON})
public Response listAttachmentsAsJson(#PathParam("id") Integer attachmentId) throws Exception {
attachmentService = new AttachmentService();
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Attachment attachment = attachmentService.getAttachment(attachmentId);
String jsonString = gson.toJson(attachment.toString());
return Response.status(Response.Status.OK).entity(jsonString).build();
}
#PATCH
#Path("{id}")
#Produces({MediaType.APPLICATION_JSON})
public Response patchAttachments(#PathParam("id") Integer attachmentId) throws Exception {
attachmentService = new AttachmentService();
Integer update = attachmentService.update(attachmentId);
String jsonString = new Gson().toJson(update);
return Response.status(Response.Status.ACCEPTED).entity(jsonString).build();
}
#POST
#Produces({MediaType.APPLICATION_JSON})
public Response migrateToMinio(#Context UriInfo uriInfo) throws Exception {
Response response;
List<String> responseList = new ArrayList<>();
tiedostoService = new TiedostoService();
attachmentService = new AttachmentService();
List<Tiedosto> tiedostoList = tiedostoService.getAllFiles();
String responseString = null;
int i = 1;
for (Tiedosto tiedosto : tiedostoList) {
Attachment attachment = new Attachment();
attachment.setCustomerId(tiedosto.getCustomerId());
attachment.setSize(tiedosto.getFileSize());
Integer id = attachmentService.createNew(attachment);
if (id == 1) {
UriBuilder builder = uriInfo.getAbsolutePathBuilder();
builder.path(Integer.toString(i));
response = Response.created(builder.build()).build();
System.out.println(response);
responseString = response.toString();
}
responseList.add(responseString);
i++;
}
String jsonString = new Gson().toJson(responseList);
return Response.status(Response.Status.OK).entity(jsonString).build();
}
}
when I test the individual endpoints with curl or postman, they work as expected, but I got stuck on how to execute GET and PATCH automatically after POST. I'd really appreciate some advice/suggestions/help.

Returning custom object with InputStream parameter in JAX-RS

I'm storing objects of type Binary in a database and I have a JAX-RS web service that can retrieve them by their ID.
public class Binary {
private InputStream data;
private String id;
private String name;
private String description;
... // constructors/getters/setters
}
I was able to get it working with this code:
#GET
#Path("{id}")
#Produces(MediaType.MULTIPART_FORM_DATA)
Response getBinary(#PathParam("id") String id) {
Binary binary = ... // get binary from database
FormDataMultiPart multipart = new FormDataMultiPart();
multipart.field("name", binary.getName());
multipart.field("description", binary.getDescription());
multipart.field("data", app.getData(),
MediaType.APPLICATION_OCTET_STREAM_TYPE);
return multipart;
}
I don't like wrapping the values in a FormDataMultiPart and unwrapping them in the client code. I want to directly return the Binary object like this:
#GET
#Path("{id}")
#Produces(/* ? */)
Binary getBinary(#PathParam("id") String id) {
Binary binary = ... // get binary from database
return binary;
}
I can't use XML or JSON representation because of the InputStream parameter.
I'd appreciate any help of how to deal with this problem. Thanks!
If you have data as InputStream you will have problems having to reset every time you read from the InputStream. Better have it as byte[].
If you are using jackson you can then return like:
#GET
#Path("{id}")
#Produces(/* ? */)
public Response get(String documentId) {
Binary binary = ... // get binary from database
return Response.ok(binary).build();
}
you can test it with:
CloseableHttpClient httpclient = HttpClients.createDefault();
ObjectMapper mapper = new ObjectMapper();
TestObj obj = new TestObj();
obj.setFile(IOUtils.toByteArray(new FileInputStream(new File("C:\\download.jpg"))));
obj.setMimetype("image/jpeg");
obj.setDescription("asd");
String jsonInString = mapper.writeValueAsString(obj);
HttpPost httpPost = new HttpPost("http://localhost:8080/url");
httpPost.setHeader("Authorization", "Bearer asdf");
httpPost.setHeader("Content-type", "application/json");
StringEntity se = new StringEntity(jsonInString);
httpPost.setEntity(se);
System.out.println(httpPost.toString());
CloseableHttpResponse response2 = httpclient.execute(httpPost);
try {
System.out.println("!!!! " + jsonInString);
System.out.println("!!!! " + se.toString());
System.out.println("!!!! " + response2.getStatusLine());
HttpEntity entity2 = response2.getEntity();
EntityUtils.consume(entity2);
} finally {
response2.close();
}

Retrieving String from JAX-RS Response

In short terms, I simplified the problem a lot. I am calling this code, and the response is received with status 200 (OK):
Receiver.java:
Response response = componentInstanceService.getResource(componentResourceType);
However, I don't know how can I retrieve the String contained in the body from this method:
Sender.java:
#Override
public Response getResource(ComponentResourceType resourceType) {
String path = getPath();
return Response.ok(this.getClass().getResourceAsStream(path)).build();
}
Please note that the communication between classes is working fine, as long as the Response is OK, however, how can I retrieve the String that Response contains?
This is what I would like to do roughly:
Receiver:
String result = componentInstanceService.getResource(componentResourceType);
The documentation for Response makes this pretty clear:
static Response.ResponseBuilder ok(java.lang.Object entity)
Create a new ResponseBuilder that contains a representation.
And:
abstract java.lang.Object getEntity()
Return the response entity.
In other words, the object you passed to Response.ok is the entity. You can retrieve it with the Response’s getEntity() method.
Obviously, you will need to cast it:
Response response = componentInstanceService.getResource(componentResourceType);
InputStream dataSource = (InputStream) response.getEntity();
Then you can read the stream as text. You haven’t mentioned the charset of your text files, so I’ll assume it’s UTF-8:
String result;
try (Scanner scanner = new Scanner(dataSource, StandardCharsets.UTF_8)) {
result = scanner.useDelimiter("\\z").next();
}
Update:
I suspected this might happen. You are returning a raw InputStream, which has no information about what type of data it is.
Change Sender.java to return a DataSource:
#Override
public DataSource getResource(ComponentResourceType resourceType) {
String path = getPath();
return new URLDataSource(this.getClass().getResource(path));
}
This way, the JAX-RS service will not only return HTTP 200 OK, but will also return a Content-Type header corresponding to the intuited type of your file.
You should then be able to invoke the method with:
DataSource dataSource = componentInstanceService.getResource(componentResourceType);
String result;
try (Scanner scanner = new Scanner(dataSource.getInputStream(), StandardCharsets.UTF_8)) {
result = scanner.useDelimiter("\\z").next();
}
There actually is a more robust way to read a DataSource. You can wrap it in a DataHandler:
DataSource dataSource = componentInstanceService.getResource(componentResourceType);
DataHandler handler = new DataHandler(dataSource);
DataFlavor flavor = DataFlavor.selectBestTextFlavor(
handler.getTransferDataFlavors());
if (flavor == null) {
// This should never happen with text files.
throw new IllegalArgumentException(
"Data has no flavors capable of supplying text.");
}
String result;
try (Reader reader = flavor.getReaderForText(handler)) {
StringBuilder s = new StringBuilder();
int c;
while ((c = reader.read()) >= 0) {
s.append((char) c);
}
result = s.toString();
} catch (UnsupportedFlavorException e) {
// Since we started with a flavor provided by the DataHandler,
// we should never get here.
throw new RuntimeException(e);
}
If you want to read the string from the body simply use
String result = componentInstanceService.getResource(componentResourceType).readEntity(String.class);

How to pass multipart file along with file name to post method using Apache httpclient 3.x?

service code:
#RequestMapping(value="/uploadFile", method=RequestMethod.POST, consumes = "multipart/form-data")
public String uploadFile(#RequestParam("file") MultipartFile file,#RequestParam("filePath") String filePath){
//logic here
}
Part of the client code:
public static synchronized String responseOfPost(String restUrl, FileSystemResource file,String filePath) {
PostMethod post = new PostMethod(restUrl);
HttpClient client = new HttpClient();
post.setParameter("filePath", filePath);
try {
Part[] parts = {new FilePart("file",file.getFile())};
post.addRequestHeader("Content-Type", "multipart/form-data; boundary=Endedlogging");
if (file != null) {
post.setRequestEntity(new MultipartRequestEntity(parts, post.getParams()));
}
client.executeMethod(post);
String response = post.getResponseBodyAsString();
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
this is the error I am getting:
org.springframework.web.bind.MissingServletRequestParameterException: Required MultipartFile parameter 'file' is not present
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:251)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:96)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:78)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
How can I pass multipart file("file") and filePath("filePath") to POST method in client code? NOT FROM UI
I'm also getting the exception like FileNotFoundException with nearly same code as your's.So can you try with this change,it maybe helpful.
Part[] parts = {new FilePart(file.getName(),file)};

Java convert Json array to typed List<T>

I have a webservice that sends a typed arraylist which I capture via HttpResponse like so:
// create GET request
HttpGet httpGet = new HttpGet("http://localhost:8084/MinecraftRestServer/webresources/Items");
// execute GET request
HttpResponse response = client.execute(httpGet);
// check response
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) { // response OK
// retreive response
List<Recipe> recipesList = new ArrayList<Recipe>();
HttpEntity jsonObj = response.getEntity();
//What's next?
The array that's being sent from the webservice looks like this:
recipesList.add(new Item(1, 11, "diamond_ingot", "Diamond ingot",
"0,0,0,0,0,0,0,0,1", "air,diamond_ore"));
recipesList.add(new Item(2, 11, "iron_ingot", "Iron ingot",
"0,0,0,0,0,0,0,0,1", "air,iron_ore"));
And comes out in this format:
[{"recipeCategory":11,"recipeImageID":"diamond_ingot","recipeDescription":"Diamond ingot","recipeLocations":"0,0,0,0,0,0,0,0,1","usedImages":"air,diamond_ore","recipeID":1},{"recipeCategory":11,"recipeImageID":"iron_ingot","recipeDescription":"Iron ingot","recipeLocations":"0,0,0,0,0,0,0,0,1","usedImages":"air,iron_ore","recipeID":2},{"recipeCategory":11,"recipeImageID":"gold_ingot","recipeDescription":"Gold ingot","recipeLocations":"0,0,0,0,0,0,0,0,1","usedImages":"air,gold_ore","recipeID":3},{"recipeCategory":11,"recipeImageID":"diamond_ore","recipeDescription":"Diamond ore","recipeLocations":"0,0,0,0,0,0,0,0,1","usedImages":"air,wooden_pickaxe","recipeID":4},{"recipeCategory":11,"recipeImageID":"iron_ore","recipeDescription":"Iron ore","recipeLocations":"0,0,0,0,0,0,0,0,1","usedImages":"air,wooden_pickaxe","recipeID":5},{"recipeCategory":11,"recipeImageID":"gold_ore","recipeDescription":"Gold ore","recipeLocations":"0,0,0,0,0,0,0,0,1","usedImages":"air,wooden_pickaxe","recipeID":6},{"recipeCategory":2,"recipeImageID":"diamond_boots","recipeDescription":"Boots (Diamond)","recipeLocations":"0,0,0,1,0,1,1,0,1","usedImages":"air,diamond_ingot","recipeID":7},{"recipeCategory":2,"recipeImageID":"gold_boots","recipeDescription":"Boots (Gold)","recipeLocations":"0,0,0,1,0,1,1,0,1","usedImages":"air,gold_ingot","recipeID":8},{"recipeCategory":2,"recipeImageID":"iron_boots","recipeDescription":"Boots (Iron)","recipeLocations":"0,0,0,1,0,1,1,0,1","usedImages":"air,iron_ingot","recipeID":9},{"recipeCategory":2,"recipeImageID":"diamond_leggings","recipeDescription":"Leggings (Diamond)","recipeLocations":"1,1,1,1,0,1,1,0,1","usedImages":"air,diamond_ingot","recipeID":10},{"recipeCategory":2,"recipeImageID":"gold_leggings","recipeDescription":"Leggings (Gold)","recipeLocations":"1,1,1,1,0,1,1,0,1","usedImages":"air,gold_ingot","recipeID":11},{"recipeCategory":2,"recipeImageID":"iron_leggings","recipeDescription":"Leggings (Iron)","recipeLocations":"1,1,1,1,0,1,1,0,1","usedImages":"air,iron_ingot","recipeID":12},{"recipeCategory":2,"recipeImageID":"diamond_chestplate","recipeDescription":"Chestplate (Diamond)","recipeLocations":"1,0,1,1,1,1,1,1,1","usedImages":"air,diamond_ingot","recipeID":13},{"recipeCategory":2,"recipeImageID":"gold_chestplate","recipeDescription":"Chestplate (Gold)","recipeLocations":"1,0,1,1,1,1,1,1,1","usedImages":"air,gold_ingot","recipeID":14},{"recipeCategory":2,"recipeImageID":"iron_chestplate","recipeDescription":"Chestplate (Iron)","recipeLocations":"1,0,1,1,1,1,1,1,1","usedImages":"air,iron_ingot","recipeID":15},{"recipeCategory":2,"recipeImageID":"diamond_helmet","recipeDescription":"Helmet (Diamond)","recipeLocations":"1,1,1,1,0,1,0,0,0","usedImages":"air,diamond_ingot","recipeID":16},{"recipeCategory":2,"recipeImageID":"gold_helmet","recipeDescription":"Helmet (Gold)","recipeLocations":"1,1,1,1,0,1,0,0,0","usedImages":"air,gold_ingot","recipeID":17},{"recipeCategory":2,"recipeImageID":"iron_helmet","recipeDescription":"Helmet
My question is, how can I convert this back into an arraylist (ArrayList<Item>)
There is already an Item class present in the client application.
I've read examples about the Gson library but it seems it's not included anymore when compiling in API 17.
What would be the easiest approach?
Download and include GSON jar from here in your project if using Eclipse.
If using Android Studio then open your build.gradle and add the below to your dependencies block. Or again you can choose not to use maven and simply drop the jar in your lib folder.
compile 'com.google.code.gson:gson:2.2.4'
Next, use GSON to construct a list of items.
Make sure you have your Item.java class with same member names as in the JSON response
List<Recipe> recipesList = new ArrayList<Recipe>();
HttpEntity jsonObj = response.getEntity();
String data = EntityUtils.toString(entity);
Log.d("TAG", data);
Gson gson = new GsonBuilder().create();
recipesList = gson.fromJson(data, new TypeToken<List<Item>>() {}.getType());
Make sure you handle the exceptions appropriately.
You could use Jackson to parse the incoming JSON. (Quick introduction)
If you already have a Class with the appropriate properties, it can be as easy as something like this:
public class Items {
private List<Item> items;
// getter+setter
}
ObjectMapper mapper = new ObjectMapper();
Items = mapper.readValue(src, Items.class);
See this for more information.
Step 1 : Item obj=new Item;
Step 2: Parse the json formar for example here :
[[Example1][1]
Step 3: while parsing put ur values in obj :
obj.recipeCategory=value1;
Step 4: insret ur obj into arraylist:
arrayList.add(obj);
I think you should using json-simple library to parse string Json to JsonObject and convert to simple data type.
Example:
JSONArray arrJson = (JSONArray) parser.parse("String json");
Get each element JSONObject in JSONArray, then parse it to simple data type:
long recipeCategory = (long) jsonObject.get("recipeCategory");
You can use Gson like many users said, here is an example of a RESTfull client using Gson:
public class RestRequest {
Gson gson = new Gson();
public <T> T post(String url, Class<T> clazz,
List<NameValuePair> parameters) {
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
try {
// Add your data
httppost.setEntity(new UrlEncodedFormEntity(parameters));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
StringBuilder json = inputStreamToString(response.getEntity()
.getContent());
T gsonObject = gson.fromJson(json.toString(), clazz);
return gsonObject;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// Fast Implementation
private StringBuilder inputStreamToString(InputStream is)
throws IOException {
String line = "";
StringBuilder total = new StringBuilder();
// Wrap a BufferedReader around the InputStream
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
// Read response until the end
while ((line = rd.readLine()) != null) {
total.append(line);
}
// Return full string
return total;
}
}
The usage will be something like this:
new RestRequest("myserver.com/rest/somewebservice", SomeClass.class, Arrays.asList(new BasicValuePair("postParameter", "someParameterValue")));
Where SomeClass.class will be Recipe[].class in your case. Also check this question to properly handle server side errors.
Man, google is your friend! A quick search for "android json" or "android json parse" gives you some nice tutorials like this one or this here.

Categories