Multipart File Upload on Google Appengine using jersey-1.7 - java

I wrote an application on Google Appengine with Jersey to handle simple file uploading. This works fine when it was on jersey 1.2. In the later versions (current 1.7) #FormDataParam is introduced to handle multipart/form inputs. I am using jersey-multipart and the mimepull dependency. It seems that the new way of doing it is creating temporary files in appengine which we all know is illegal...
Am I missing something or doing something wrong here since Jersey is now supposedly compatible with AppEngine?
#POST
#Path("upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public void upload(#FormDataParam("file") InputStream in) { .... }
The above will fail when called with these exceptions...
/upload
java.lang.SecurityException: Unable to create temporary file
at java.io.File.checkAndCreate(File.java:1778)
at java.io.File.createTempFile(File.java:1870)
at java.io.File.createTempFile(File.java:1907)
at org.jvnet.mimepull.MemoryData.createNext(MemoryData.java:87)
at org.jvnet.mimepull.Chunk.createNext(Chunk.java:59)
at org.jvnet.mimepull.DataHead.addBody(DataHead.java:82)
at org.jvnet.mimepull.MIMEPart.addBody(MIMEPart.java:192)
at org.jvnet.mimepull.MIMEMessage.makeProgress(MIMEMessage.java:235)
at org.jvnet.mimepull.MIMEMessage.parseAll(MIMEMessage.java:176)
at org.jvnet.mimepull.MIMEMessage.getAttachments(MIMEMessage.java:101)
at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readMultiPart(MultiPartReaderClientSide.java:177)
at com.sun.jersey.multipart.impl.MultiPartReaderServerSide.readMultiPart(MultiPartReaderServerSide.java:80)
at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:139)
at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:77)
at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:474)
at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:538)
Anyone have a clue? Is there a way to do thing while preventing mimepull from creating the temporary file?

For files beyond its default size, multipart will create a temporary file. To avoid this — creating a file is impossible on gae — you can create a jersey-multipart-config.properties file in the project's resources folder and add this line to it:
bufferThreshold = -1
Then, the code is the one you gave:
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response post(#FormDataParam("file") InputStream stream, #FormDataParam("file") FormDataContentDisposition disposition) throws IOException {
post(file, disposition.getFileName());
return Response.ok().build();
}

For the benefit of those struggling when using Eclipse with GPE (Google Plugin for Eclipse) I give this slightly modified solution derived from #yves' answer.
I have tested it with App Engine SDK 1.9.10 and Jersey 2.12. It will not work with App Engine SDK 1.9.6 -> 1.9.9 amongst others due to a different issue.
Under your \war\WEB-INF\classes folder create a new file called jersey-multipart-config.properties. Edit the file so it contains the line jersey.config.multipart.bufferThreshold = -1.
Note that the \classes folder is hidden in Eclipse so look for the folder in your operating system's file explorer (e.g. Windows Explorer).
Now, both when the multipart feature gets initialized (on Jersey servlet initialization) and when a file upload is done (on Jersey servlet post request) the temp file will not be created anymore and GAE won't complain.

It is very important to put the file jersey-multipart-config.properties under WEB-INF/classes inside the WAR.
Usually in a WAR file structure you put the config files (web.xml, appengine-web.xml) into WEB-INF/, but here you need to put into WEB-INF/classes.
Example Maven configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<archiveClasses>true</archiveClasses>
<webResources>
<resource>
<directory>${basedir}/src/main/webapp/WEB-INF</directory>
<filtering>true</filtering>
<targetPath>WEB-INF</targetPath>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
<targetPath>WEB-INF/classes</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
And your project structure can look like:
Content of jersey-multipart-config.properties with Jersey 2.x:
jersey.config.multipart.bufferThreshold = -1

i've found solution to programmatically avoid to use temporary file creation (very useful for GAE implementation)
My solution consist of creating a new MultiPartReader Provider ... below my code
#Provider
#Consumes("multipart/*")
public class GaeMultiPartReader implements MessageBodyReader<MultiPart> {
final Log logger = org.apache.commons.logging.LogFactory.getLog(getClass());
private final Providers providers;
private final CloseableService closeableService;
private final MIMEConfig mimeConfig;
private String getFixedHeaderValue(Header h) {
String result = h.getValue();
if (h.getName().equals("Content-Disposition") && (result.indexOf("filename=") != -1)) {
try {
result = new String(result.getBytes(), "utf8");
} catch (UnsupportedEncodingException e) {
final String msg = "Can't convert header \"Content-Disposition\" to UTF8 format.";
logger.error(msg,e);
throw new RuntimeException(msg);
}
}
return result;
}
public GaeMultiPartReader(#Context Providers providers, #Context MultiPartConfig config,
#Context CloseableService closeableService) {
this.providers = providers;
if (config == null) {
final String msg = "The MultiPartConfig instance we expected is not present. "
+ "Have you registered the MultiPartConfigProvider class?";
logger.error( msg );
throw new IllegalArgumentException(msg);
}
this.closeableService = closeableService;
mimeConfig = new MIMEConfig();
//mimeConfig.setMemoryThreshold(config.getBufferThreshold());
mimeConfig.setMemoryThreshold(-1L); // GAE FIX
}
#Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return MultiPart.class.isAssignableFrom(type);
}
#Override
public MultiPart readFrom(Class<MultiPart> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> headers, InputStream stream) throws IOException, WebApplicationException {
try {
MIMEMessage mm = new MIMEMessage(stream, mediaType.getParameters().get("boundary"), mimeConfig);
boolean formData = false;
MultiPart multiPart = null;
if (MediaTypes.typeEquals(mediaType, MediaType.MULTIPART_FORM_DATA_TYPE)) {
multiPart = new FormDataMultiPart();
formData = true;
} else {
multiPart = new MultiPart();
}
multiPart.setProviders(providers);
if (!formData) {
multiPart.setMediaType(mediaType);
}
for (MIMEPart mp : mm.getAttachments()) {
BodyPart bodyPart = null;
if (formData) {
bodyPart = new FormDataBodyPart();
} else {
bodyPart = new BodyPart();
}
bodyPart.setProviders(providers);
for (Header h : mp.getAllHeaders()) {
bodyPart.getHeaders().add(h.getName(), getFixedHeaderValue(h));
}
try {
String contentType = bodyPart.getHeaders().getFirst("Content-Type");
if (contentType != null) {
bodyPart.setMediaType(MediaType.valueOf(contentType));
}
bodyPart.getContentDisposition();
} catch (IllegalArgumentException ex) {
logger.error( "readFrom error", ex );
throw new WebApplicationException(ex, 400);
}
bodyPart.setEntity(new BodyPartEntity(mp));
multiPart.getBodyParts().add(bodyPart);
}
if (closeableService != null) {
closeableService.add(multiPart);
}
return multiPart;
} catch (MIMEParsingException ex) {
logger.error( "readFrom error", ex );
throw new WebApplicationException(ex, 400);
}
}
}

We experienced a similar problem, Jetty wouldn't let us upload files more than 9194 bytes, (all of a sudden - one day), we realised afterwards that someone had taken our user access from /tmp, which corresponds to java.io.tmpdir on some linux versions, so Jetty couldn't store the uploaded file there, and we got a 400 error.

Related

Spring Boot File Download Progress

I have a small problem regarding a download controller I want to implement. I want to make files accessible through an url, therefore I am using a spring boot controller. Because there could be several data types, I use the Apache Tika lib to determine the correct media type. I am currently bound to use the JAX-RS Requests. To save the byte array to a File, I use guava.
#GET
#Path("/getMedia")
public Response downloadMedia(#QueryParam("company") final String company,
#QueryParam("username") final String username,
#QueryParam("password") final String password,
#QueryParam("messageId") final int messageId) throws IOException {
ApplicationContext ctx = CyMega.getInstance().getContext(company);
if (ctx == null) {
return Response.status(Response.Status.UNAUTHORIZED).entity("Company not found").build();
}
ExternalAuthenticationService extService = ctx.getBean(ExternalAuthenticationService.class);
ExternalAuthObj authObj = extService.validateLogin(company, username, password);
if (authObj.getCode() != 0) {
return Response.status(Response.Status.UNAUTHORIZED).entity(authObj)build();
}
ChatService chatService = ctx.getBean(ChatService.class);
ChatGroupMessage message = chatService.getSingleChatGroupMessage(messageId);
if (message != null) {
Byte[] blobs = chatService.getBlob(messageId);
byte[] blob = ArrayUtils.toPrimitive(blobs);
File file = new File(message.getFilename());
Files.write(blob, file);
TikaConfig config = TikaConfig.getDefaultConfig();
Detector detector = config.getDetector();
Metadata metadata = new Metadata();
ByteArrayInputStream inputStream = new ByteArrayInputStream(blob);
TikaInputStream tikaInputStream = TikaInputStream.get(inputStream);
metadata.add(TikaCoreProperties.RESOURCE_NAME_KEY, message.getFilename());
org.apache.tika.mime.MediaType mediaType = detector.detect(tikaInputStream, metadata);
return Response.status(Response.Status.OK)
.header("Content-Length", String.valueOf(blob.length))
.header(HttpHeaders.CONTENT_TYPE, mediaType)
.entity(file).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
By using this code, the file successfully will be send to the client. The only problem is that I also want to track the progress of the download. I tried defining the Content-Length, but this causes my request to load way longer than necessary. Is there any way to achieve that? Should I use a ByteArrayStream as response entity? It would be awesome if someone could provide an example on how to do that properly.
Thanks in advance!

Receiving customized response and file from REST web services

I'm trying to create some REST web services with Java in order to send data, do calculations on the server, and return the result. In a first stage I send and receive information as an excel file (in the future I prefer to use XML or JSON).
Well, after a lots of hours trying it, and reading lots of posts, it seems I'm very close to achieve it, but I don't know how to obtain the final response of the server.
I have a service like this:
#GET
#Path("/test")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile(#QueryParam("IDfile") String IDfile) {
if(IDfile.trim().length() == 0 || IDfile == null) {
return Response.status(Response.Status.BAD_REQUEST).entity("IDfile cannot be blank").build();
}
String uploadedFileLocation = "C:\\FilesWebservice\\" + IDfile;
Boolean sortida = false;
try {
prova prueba = new prova();
sortida = prueba.prova(uploadedFileLocation); //this creates an xls file as response
} catch (Exception ex) {
System.out.println("error" + ex.toString());
Logger.getLogger(ServiceResource.class.getName()).log(Level.SEVERE, null, ex);
}
if (sortida) {
File file = new File("C:\\FilesWebservice\\out\\prediction.xls"); // the File path you want to serve.
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();
} else
return Response.status(500).entity("It was unable to calculate (Ask God for the reason)").build();
}
It works OK, if I send a GET through the browser I receive the file in my downloads folder, but I need to consume the service with another application. Thus, I'm developing a client with Netbeans, and then, NB created automatic code according to my web service. In this case I have:
public <T> T getFile(Class<T> responseType, String IDfile) throws ClientErrorException {
WebTarget resource = webTarget;
if (IDfile != null) {
resource = resource.queryParam("IDfile", IDfile);
}
resource = resource.path("test");
Builder builder = resource.request(MediaType.APPLICATION_OCTET_STREAM_TYPE);
Invocation invocation = builder.buildGet();
return resource.request(MediaType.APPLICATION_OCTET_STREAM_TYPE).get(responseType);
}
Maybe I added some lines, I can't remember now. Anyway, the service returns a status code, a customised message and the file as attachment. I want to read at least the status code and obviously save the file, but I don't know how can I do it.
I tried to do:
MyJerseyClientAlgA client = new MyJerseyClientAlgA("192.168.1.30");
Object response = client.getFile(Response.class, "3cphkhfu.xls");
but it was unsuccessful to extract the information I need from 'response'.
Any help or ideas would be appreciated.
Many thanks in advance
EDIT:
Thanks #LutzHorn for your reply. I'm not sure if I understand well your proposal, I'll do some tests and if I find a solution I'll post under my question. Anyway, I generated again the automatic code for consuming the REST service, that is:
public <T> T getFile(Class<T> responseType, String IDfile) throws ClientErrorException {
WebTarget resource = webTarget;
if (IDfile != null) {
resource = resource.queryParam("IDfile", IDfile);
}
resource = resource.path("test");
return resource.get(responseType);
}
but I have an error in the last line, it indicates:
cannot find symbol
symbol: method get(Class)
so I changed this line for
return resource.request(MediaType.APPLICATION_OCTET_STREAM_TYPE).get(responseType);
but I'm not sure if this is right.
Well, after some hours searching and testing, this piece of code works. I don't know if it is the best solution, but it does exactly what I want: extract the status and save the file returned by the web service.
public void getFile(String IDfile) throws ClientErrorException {
WebTarget resource = webTarget;
if (IDfile != null) {
resource = resource.queryParam("IDfile", IDfile);
}
resource = resource.path("test");
Invocation inv = resource.request(MediaType.APPLICATION_OCTET_STREAM_TYPE).buildGet();
Response rp = inv.invoke();
InputStream attachment = null;
try {
if (rp.getStatus() == 200) {
attachment = rp.readEntity(InputStream.class); //This method can be invoked only once unless you buffer the response...
ReadableByteChannel rbc = Channels.newChannel(attachment); //website.openStream()
FileOutputStream fos = new FileOutputStream("C://FilesWebservice/solution.xls");
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
} else {
System.out.println(rp.getStatus());
}
} catch ( Exception ex) {
ex.printStackTrace();
} finally {
rp.close();
}
}

Jersey 2 multipart/form-data issue. InputStream is empty (available=0)

I am facing issue with jersey 2 file upload. Input stream is coming empty to server side. Using jersey 2.21, jackson 2.5.4, spring 4.1.6.RELEASE (for DI only) & spring security 4.0.2.RELEASE for security. Using JDK 1.8.0_25 and Tomcat 8.0.26.
Code:
#POST
#Path("/upload")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.MULTIPART_FORM_DATA)
public SimpleResult categoryImageUpload(
#FormDataParam("file") InputStream file,
#FormDataParam("file") FormDataBodyPart bodyPart) {
return SimpleResult.success("File Uploaded successfully!!!");
}
File Details is coming in FormDataBodyPart, but InputStream is coming empty(available=0).
Jersey configuration:
#ApplicationPath("api-business")
public class BusinessApplicationConfig extends ResourceConfig {
public BusinessApplicationConfig() {
register(RequestContextFilter.class);
register(MultiPartFeature.class);
packages("com.smx.biz.api");
}
}
dependencies in pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.4</version>
</dependency>
<!--Jersey-->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.21</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.21</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.21</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.21</version>
</dependency>
<!-- Jersey + Spring -->
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.21</version>
</dependency>
Could somebody help with this issue? Am I missing something???
PS: Spring REST file upload code is working well & InputStream is coming. But Jersey code is not working. Using same client side code to test apis.
Working Spring REST api code:
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/business/upload", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
ImageItem categoryPhotoUpload(#RequestBody MultipartFile file) {
return uploadService.uploadFile(file);
}
I want to use Jersey for apis & I don't want to use Spring REST.
Could somebody help with this issue?
I found that when you use the #FormDataParam("file") InputStream file method, under the hood the parameter never gets processed because jersey is actually looking for a File. What happens (at least from what i have read so far) is that when the request comes in jersey does some mime checking using the mimepull library and in turn saves the incoming file as a temporary file. The issue is that if your parameter type is InputStream, jersey does not handle it because there is no ValueFactory registered for InputStream. So in order for this to work you have to do the following.
Inside FormDataParamValueFactoryProvider
Add the following implementation:
private final class InputStreamFactory extends ValueFactory<InputStream> {
private final String name;
public InputStreamFactory(final String name) {
this.name = name;
}
#Override
public InputStream provide() {
LOG.info("Processing paramaeter [" + name + "]");
final FormDataBodyPart part = getEntity().getField(name);
final BodyPartEntity entity = part != null ? part.getEntityAs(BodyPartEntity.class) : null;
if (entity != null) {
try {
// Create a temporary file.
final File file = Utils.createTempFile();
// Move the part (represented either via stream or file) to the specific temporary file.
entity.moveTo(file);
//Retreive file via a FileInputStream
return new FileInputStream(file);
} catch (final Exception ex) {
// Unable to create a temporary file or move the file.
LOG.warn("Error while processing InputStream. " + ex);
}
}
return null;
}
}
This will allow jersey to detect the InputStream.
You also have to change the createValueFactory method to reflect the new ValueFactoryProvider.
#Override
protected Factory<?> createValueFactory(final Parameter parameter) {
final Class<?> rawType = parameter.getRawType();
if (Parameter.Source.ENTITY == parameter.getSource()) {
if (FormDataMultiPart.class.isAssignableFrom(rawType)) {
return new FormDataMultiPartFactory();
} else {
return null;
}
} else if (parameter.getSourceAnnotation().annotationType() == FormDataParam.class) {
final String paramName = parameter.getSourceName();
if (paramName == null || paramName.isEmpty()) {
// Invalid query parameter name
return null;
}
if (Collection.class == rawType || List.class == rawType) {
final Class clazz = ReflectionHelper.getGenericTypeArgumentClasses(parameter.getType()).get(0);
if (FormDataBodyPart.class == clazz) {
// Return a collection of form data body part.
return new ListFormDataBodyPartValueFactory(paramName);
} else if (FormDataContentDisposition.class == clazz) {
// Return a collection of form data content disposition.
return new ListFormDataContentDispositionFactory(paramName);
} else {
// Return a collection of specific type.
return new FormDataParamValueFactory(parameter, get(parameter));
}
} else if (FormDataBodyPart.class == rawType) {
return new FormDataBodyPartFactory(paramName);
} else if (FormDataContentDisposition.class == rawType) {
return new FormDataContentDispositionFactory(paramName);
} else if (File.class == rawType) {
return new FileFactory(paramName);
} else if (InputStream.class == rawType) {
return new InputStreamFactory(paramName);
} else {
return new FormDataParamValueFactory(parameter, get(parameter));
}
}
return null;
}
Now... here's where it becomes a pain... if you dont pull the module source from github and and compile with the changes.... you have to basically recreate the following classes in order to reference the new class through the reference chain.
Classes:
FormDataParamValueFactoryProvider
FormDataParamInjectionFeature (References: FormDataParamValueFactoryProvider)
MultiPartFeature (References: FormDataParamInjectionFeature)
Once this is done, you can then use #FormDataParam("file") InputStream and it will work as expected.
Make sure that the string inside the annotation
#FormDataParam("theSameStringUsedInAnnotation") InputStream file
exactly matches the name of the resource that you are posting.
In my case I was using ExtJs fileupload and when you define there a fileupload like:
xtype: 'filefield',
name: 'theSameStringUsedInAnnotation',
you have to define the same string
In My case I replaced #FormDataParam("file") InputStream file with #FormDataParam("file") File file then it started working fine.

How to return actual html file using JAX-RS

so far, I'm returning html my home page by:
#GET
#Produces({MediaType.TEXT_HTML})
public String viewHome()
{
return "<html>...</html>";
}
what I want to do is return home.html itself and not copying its contents and returning the string instead.
How do I do this? thanks :)
You can just return an instance of java.io.InputStream or java.io.Reader — JAX-RS will do the right thing.
#GET
#Produces({MediaType.TEXT_HTML})
public InputStream viewHome()
{
File f = getFileFromSomewhere();
return new FileInputStream(f);
}
Read the File using getResourceAsStream
write back to returned String.
This is my preferred way of serving a web page using JAX-RS. The resources for the web page (html, css, images, js, etc.) are placed in main/java/resources, which should deploy them in WEB-INF/classes (may require some configuration depending on how you set up your project). Inject ServletContext into your service and use it to find the file and return it as an InputStream. I've included a full example below for reference.
#Path("/home")
public class HomeService {
#Context
ServletContext servletContext;
#Path("/{path: .+}")
#GET
public InputStream getFile(#PathParam("path") String path) {
try {
String base = servletContext.getRealPath("/WEB-INF/classes/files");
File f = new File(String.format("%s/%s", base, path));
return new FileInputStream(f);
} catch (FileNotFoundException e) {
// log the error?
return null;
}
}
}
You can use HtmlEasy which is built on top of RestEasy, which is a really good implementation of Jax-RS.

Http 415 on file Upload using jersey

My code for RESTful file upload :
#Path("/upload")
#POST
#Consumes("multipart/form-data")
public String post(
#FormDataParam("part") String s,
#FormDataParam("part") FormDataContentDisposition d) {
return s + ":" + d.getFileName();
}
When I try to upload a file using curl
curl -X POST --form part=#file.txt url
I am getting a HTTP 415-Unsupported Media Type Error. What is wrong ?
After trying a lot of examples finaly find the realy working example on http://iambigd.blogspot.com/2011/06/java-upload-file-using-jersey.html
#POST
#Path("/simpleupload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public void simpleUpload(
//#Context UriInfo ui,
#Context HttpServletRequest request
){
String fileRepository = "D:\\";
if (ServletFileUpload.isMultipartContent(request)) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = null;
try {
items = upload.parseRequest(request);
} catch (FileUploadException e) {
e.printStackTrace();
}
if (items != null) {
Iterator<FileItem> iter = items.iterator();
while (iter.hasNext()) {
FileItem item = iter.next();
if (!item.isFormField() && item.getSize() > 0) {
System.out.println("File is found.");
String fileName = processFileName(item.getName());
try {
String savePath = fileRepository + fileName;
System.out.println("savePath:" + savePath);
item.write(new File(savePath));
} catch (Exception e) {
e.printStackTrace();
}
}else{
System.out.println("getFieldName:" + item.getFieldName());
System.out.println(item.getString());
}
}
}
}
}
(need the servlet-api.jar, (apache) commons-oi.jar and (apache) commons-fileupload.jar)
This can happen due to a couple of reasons. I managed to narrow down some of them.
Your Content-Type header does not match with the one provided by the #Consumes header. Verify this with a proxy.
You managed to stumble upon a bug that was fixed in Jersey 1.4 related to the FormDataParam annotation.
You included jersey-bundle and jersey-server et all in the same binary and they are competing against each other.
You are using #FormParam instead of #FormDataParam.
Your #FormDataParam is unrecognized by the introspection API because of conflicts with jersey-multipart and other jersey jars. If one jar is of version 1.x make sure the other jars are on the same version. While debugging the jersey API code I noticed that these method annotations turn up blank (on jersey's code) if the jar versions are not uniform. All method parameters on the REST service are replaced by the body content of the POST request irrespective of which FormDataParam they are supposed to contain.
Please make sure you have mimepull.jar on the classpath
You may need to register the MultipartFeature as described in the Jersey documentation, chapter 8.3.1.2 Registration.
Create a class something like this:
/**
*
*/
package com.verico.multipart.app;
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
#ApplicationPath("/")
public class MultiPartApp extends ResourceConfig {
public MultiPartApp() {
super(MultiPartFeature.class);
}
}
And add the following init-param to your Jersey servlet in web.xml:
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.verico.multipart.app.MultiPartApp</param-value>
</init-param>
Have you tried with an Input stream ?
Like :
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response post(
#Context HttpServletRequest request,
#Context HttpHeaders headers,
#FormDataParam("file") InputStream fileStream,
Works fine for me.

Categories

Resources