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?
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
It is very important to put the file
jersey-multipart-config.properties
underWEB-INF/classes
inside the WAR.Usually in a WAR file structure you put the config files (
web.xml
,appengine-web.xml
) intoWEB-INF/
, but here you need to put intoWEB-INF/classes
.Example Maven configuration:
And your project structure can look like:
Content of
jersey-multipart-config.properties
with Jersey 2.x: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
andJersey 2.12
. It will not work withApp 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 calledjersey-multipart-config.properties
. Edit the file so it contains the linejersey.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.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.
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 ajersey-multipart-config.properties
file in the project's resources folder and add this line to it:Then, the code is the one you gave: