Jersey2.13: MessageBodyReader not found for StreamingOutput - java

I'm returning a StreamingOutput inside a Response object:
#GET
#Path("/downloadFile/{filename}")
#Produces(MediaType.TEXT_PLAIN)
public Response downloadFile(#PathParam("filename") String fileName) {
LOG.debug("called: downloadFile({})", fileName);
final File f = new File("/tmp/" + fileName);
try {
if (f.exists()) {
StreamingOutput so = new StreamingOutput() {
#Override
public void write(OutputStream os) throws IOException,
WebApplicationException {
FileInputStream fis = new FileInputStream(f);
byte[] buffer = new byte[4 * 1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
LOG.debug("streaming file contents #{}", bytesRead);
os.write(buffer, 0, bytesRead);
}
fis.close();
os.flush();
os.close();
}
};
return Response.ok(so, MediaType.TEXT_PLAIN).build();
} else {
return createNegativeXmlResponse("file not found or not readable: '"
+ f.getPath() + "'");
}
} catch (Exception e) {
return handle(e);
}
}
Client side (Junit test case):
#Test
public void testDownloadFile() throws Exception {
Client client = ClientBuilder.newBuilder()
.register(MultiPartFeature.class).build();
WebTarget target = client.target(BASE_URI).path("/downloadFile/b.txt");
Response r = target.request(MediaType.TEXT_PLAIN_TYPE).get();
System.out.println(r.getStatus());
Object o = r.readEntity(StreamingOutput.class);
StreamingOutput so = (StreamingOutput) o;
}
The server runs in a tomcat7 instance. What I get on the client side when r.readEntity is executed is this:
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=text/plain, type=interface javax.ws.rs.core.StreamingOutput, genericType=interface javax.ws.rs.core.StreamingOutput.
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:230)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:154)
...
How can I get the StreamingOutput object from the Response object on the client side ?

StreamingOutput is a helper class to allow us to write directly to the response output stream, but is not meant to be recreated from the response, so there is no reader to convert the byte stream to a StreamingOutput. We could simple get an InputStream from the response though.
Response response = target.request().get();
InputStream is = response.readEntity(InputStream.class);
Full example:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
public class TestStreamingOutput extends JerseyTest {
#Path("/streaming")
public static class StreamingResource {
#GET
public StreamingOutput getImage() throws Exception {
final InputStream is
= new URL("http://i.stack.imgur.com/KSnus.gif").openStream();
return new StreamingOutput() {
#Override
public void write(OutputStream out)
throws IOException, WebApplicationException {
byte[] buffer = new byte[4 * 1024];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
out.flush();
out.close();
is.close();
}
};
}
}
#Override
protected Application configure() {
return new ResourceConfig(StreamingResource.class);
}
#Test
public void test() throws Exception {
Response response = target("streaming").request().get();
InputStream is = response.readEntity(InputStream.class);
ImageIcon icon = new ImageIcon(ImageIO.read(is));
JOptionPane.showMessageDialog(null, new JLabel(icon));
}
}
Only Maven dependency
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.13</version>
<scope>test</scope>
</dependency>
Result:

Related

Streaming Merge PDF

I´m looking for a Java PDF Merger solution where I can streaming the merged pdf while I getting (example from a REST API) the PDF pages parts from a REST api.
A pseudo code should be something like this:
public void doGet(HttpServletRequest req, HttpServletResponse res) throws Exception {
sOut = res.getOutputStream();
MergeDocument merger = MergeDocument.merge(sOut);
for (int i = 0; i < 1000; i++) {
byte[] contentPDF = restClient.get("http://mywebsite.com/files/mypdf"+i+".pdf");
merger.append(contentPDF);
sOut.flush(); // sending merged PDF bytes now
}
sOut.close();
}
My point is to not wast heap memory with all PDFs in memory before start sending it to user. In other words, when I get a "contentBytes pdf" from rest I want to send it to the user as a streaming now.
Hope someone can help me :)
Using itextpdf
package com.example.demo.controller;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/pdf")
public class PdfMerger {
#GetMapping
public void merge(HttpServletResponse response) {
Document document = new Document(PageSize.LETTER);
response.setContentType("application/pdf");
response.setHeader("Content-disposition", "attachment; filename=\"merged.pdf\"");
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
PdfCopy copy = new PdfCopy(document, outputStream);
document.open();
for (InputStream file : getPdfs()) {
copy.addDocument(new PdfReader(file)); // writes directly to the output stream
}
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen()) {
document.close();
}
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
private List<InputStream> getPdfs() {
List<InputStream> list = new ArrayList<>();
for (int i = 0; i < 10; i++){
list.add(PdfMerger.class.getResourceAsStream("/pdf/1.pdf"));
list.add(PdfMerger.class.getResourceAsStream("/pdf/2.pdf"));
}
return list;
}
}

I want to return response in XML form from REST API in java

I have REST API in java that take image file and save on the server i want to return the path of that uploaded image in XML form but don't know how to do it.Currently it returns the response as a string in the browser.
Here is my code.
package com.javacodegeeks.enterprise.rest.jersey;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataParam;
#Path("/files")
public class JerseyFileUpload {
private static final String SERVER_UPLOAD_LOCATION_FOLDER = "/home/hassan/Downloads/";
/**
* Upload a File
*/
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
#FormDataParam("file") InputStream fileInputStream,
#FormDataParam("file") FormDataContentDisposition contentDispositionHeader) {
String filePath = SERVER_UPLOAD_LOCATION_FOLDER + contentDispositionHeader.getFileName();
// save the file to the server
saveFile(fileInputStream, filePath);
String output = "File saved to server location : " + filePath;
return Response.status(200).entity(output).build();
}
// save uploaded file to a defined location on the server
private void saveFile(InputStream uploadedInputStream,
String serverLocation) {
try {
OutputStream outpuStream = new FileOutputStream(new File(serverLocation));
int read = 0;
byte[] bytes = new byte[1024];
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
outpuStream.write(bytes, 0, read);
}
outpuStream.flush();
outpuStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
If you want to return xml from Rest, try to create Object with some fields. and Object and field will have #XmlRootElement #XmlElement and put #Produces("application/xml") on top of method signature.
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces("application/xml")
public Response uploadFile(...){
//body
}
also you can use #produces(MediaType.APPLICATION_XML) instead of #Produces("application/xml"). both are same.

How to POST a multipart/form data with files programatically in a REST API

I am having a Rest URL with form data which i succesfully execute from my REST Client POST MAN.How to do this from a java program ? How to pass the attached files programtically. The snapshot of the rest call is as follows.
check the below code example.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataParam;
#Path("/file")
public class UploadFileService {
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition fileDetail,
#FormDataParam("path") String path) {
// Path format //10.217.14.97/Installables/uploaded/
System.out.println("path::"+path);
String uploadedFileLocation = path
+ fileDetail.getFileName();
// save it
writeToFile(uploadedInputStream, uploadedFileLocation);
String output = "File uploaded to : " + uploadedFileLocation;
return Response.status(200).entity(output).build();
}
// save uploaded file to new location
private void writeToFile(InputStream uploadedInputStream,
String uploadedFileLocation) {
try {
OutputStream out = new FileOutputStream(new File(
uploadedFileLocation));
int read = 0;
byte[] bytes = new byte[1024];
out = new FileOutputStream(new File(uploadedFileLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}

build FAST web service to download an image from aws s3 using jersey

i am trying to build web service to download an image from aws s3 using jersey 1.18
i have S3ObjectInputStream with the file.
i need FAST way to retrive the image, my way is very slow (5 seconds)
what is the right way to do that?
here is my code
import java.io.InputStream;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
#Path("/getfile")
public class Temp3 {
#GET
#Produces("image/*")
public Response getFile() throws IOException {
System.out.println("in getfile");
awsBL _bl = new awsBL();
S3Object object = _bl.getFile("gps.png");
//System.out.println("**meta:\n"+object.getObjectMetadata());
InputStream objectContent = object.getObjectContent();
InputStream reader = new BufferedInputStream(objectContent);
File file = new File("localFilename");
OutputStream writer = new BufferedOutputStream(new FileOutputStream(file));
int read = -1;
while ( ( read = reader.read() ) != -1 ) {
writer.write(read);
}
writer.flush();
writer.close();
reader.close();
String filename = object.getKey();
ResponseBuilder response = Response.ok(file);
response.header("Content-Disposition",
"attachment; filename="+filename);
return response.build();
}
}
Step one
static byte[] getBinaryData(String filename, String logId) {
return S3_SDK.download(S3_SDK.getFilesBucket(), "/foldername/" + filename, logId);
}
Step two
public static byte[] download(String bucketName, String name, String logId) {
LOG.log(Level.INFO, "{0} :: start download process, bucketName: {1}, name: {2}", new Object[]{logId, bucketName, name});
S3Object object = downloadAsS3Object(bucketName, name, logId);
LOG.log(Level.INFO, "{0} :: download process returns, S3Object: {1}", new Object[]{logId, object});
try {
return IOUtils.toByteArray(object.getObjectContent());
} catch (IOException ex) {
LOG.log(Level.SEVERE, "{0} :: error download process, bucketName: {1}, name: {2}\n{3}", new Object[]{logId, bucketName, name, Utilities.getStackTrace(ex)});
}
return null;
}

java.io.EOFException error on object serialization with HttpHandler

I am trying to serialize an object in a HttpHandler class.
I have 2 files, Server3.java:
package server3;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class Server3 {
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(3333), 0);
server.createContext("/", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
static class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
String response = "Kjo eshte nje pergjigje nga serveri! n";
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
Personat obj = new Personat();
ObjectOutputStream objOut = new ObjectOutputStream(t.getResponseBody());
objOut.writeObject(obj);
objOut.close();
}
}
}
class Personat implements Serializable{
private static final long serialVersionUID = 1L;
int ID=3;
String Name="Andi";
}
and Client3.java:
package server3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.net.HttpURLConnection;
import java.net.URL;
//te gjithe personat qe jan ne database me nej objekt
public class Client3 {
public static void main(String[] args) throws Exception {
try {
URL url = new URL("http://localhost:3333");
HttpURLConnection s = (HttpURLConnection) url.openConnection();
s.setDoOutput(true);
s.setDoInput(true);
s.setRequestMethod("POST");
s.setUseCaches(false);
InputStream in = s.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
int c;
while ((c = br.read()) != -1) {
System.out.print((char) c);
}
ObjectInputStream ios = new ObjectInputStream(s.getInputStream());
Personat oin = (Personat) ios.readObject();
String emri=oin.Name;
System.out.println(emri);
ios.close();
s.disconnect();
} catch (IOException ex) {
System.err.println(ex);
System.out.print(ex);
}
}
}
But when I run it eclipse shows me
java.io.EOFException Kjo eshte nje pergjigje nga serveri! njava.io.EOFException`
and I cant understand why.
The problem is that you are trying to fit both the string response and the object into response.length() bytes. What happens is that only response.length() bytes are sent and so if you try to read more you get the EOFException.
If you instead set the responseLength parameter to be 0 it will allow you to transmit an arbitrary amount of data
t.sendResponseHeaders(200, 0);
You also shouldn't close the stream if you are going to write more data into it. Don't call os.close() until all the writing is complete.

Categories

Resources