0

I have been following the Google Guestbook tutorial for AppEngine, and successfully completed the tutorial. I then went on to add my own part (uploading an image to the datastore) just for a challenge, but have run into a problem. My code compiles and deploys fine, but upon submitting a .jpg to the following form,

<form action="/image" method="post" enctype="multipart/form-data">
    <div><input type="text" name="imageName"></input></div>
    <div><input type="file" name="image" accept="image/*"></input></div>
    <div><input type="submit" value="Post Image"/></div>
</form>

I receive the following error

    java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getPart(Ljava/lang/String;)Ljavax/servlet/http/Part;
        at com.example.guestbook.ImageServlet.doPost(ImageServlet.java:49)
...

My servlet dependency in my pom is as follows:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>

web.xml:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
            http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <servlet>
      <servlet-name>sign</servlet-name>
      <servlet-class>com.example.guestbook.SignGuestbookServlet</servlet-class>
    </servlet>
    <servlet>
      <servlet-name>image</servlet-name>
      <servlet-class>com.example.guestbook.ImageServlet</servlet-class>
    </servlet>

    <servlet-mapping>
      <servlet-name>sign</servlet-name>
      <url-pattern>/sign</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
      <servlet-name>image</servlet-name>
      <url-pattern>/image</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>guestbook.jsp</welcome-file>
    </welcome-file-list>

    <filter>
      <filter-name>ObjectifyFilter</filter-name>
      <filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
    </filter>
    <filter-mapping>
      <filter-name>ObjectifyFilter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
    <listener>
      <listener-class>com.example.guestbook.OfyHelper</listener-class>
    </listener>
</web-app>

and the servlet code that services the request is:

@MultipartConfig
public class ImageServlet extends HttpServlet {

  // Process the http POST of the form
  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {

    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();  // Find out who the user is.

    String imageName = req.getParameter("imageName");
    try
    {
        Part part = req.getPart("image");
        InputStream is = part.getInputStream();
        byte[] bytes = null;
        is.read(bytes);
        Blob image = new Blob(bytes);

        Image newImage = new Image(imageName, image);

        // Use Objectify to save the greeting and now() is used to make the call synchronously as we
        // will immediately get a new page using redirect and we want the data to be present.
        ObjectifyService.ofy().save().entity(newImage).now();
    }
    catch(ServletException e)
    {
        e.printStackTrace();
    }

    resp.sendRedirect("/guestbook.jsp");
  }
}

with the "Image" model being:

@Entity
public class Image {
  @Id public Long id;

  public String imageName;
  public Blob image;

  /**
   * Simple constructor
   **/
  public Image() {
  }

  /**
   * Takes all important fields
   **/
  public Image(String name, Blob newImage) {
    imageName = name;
    image = newImage;
  }

}

I originally had a problem where the servlet version provided by the tutorial pom didn't support "getPart()" (2.7 I believe), but I updated it to 3.1 and am still greeted with the NoSuchMethodError. I guess there's a chance there could still be some artefact lying around which is still using the outdated servlet version, but personally I'm quite stumped.

Sam Holden
  • 105
  • 1
  • 7
  • GAE is Servlet 2.5. Supplying a Servlet 3.1 JAR along webapp doesn't magically turn target runtime in a Servlet 3.1 compatible one (moreover, you should never supply target runtime provided libraries along with webapp). Just follow file upload instructions for Servlet 2.5 users (with Apache Commons FileUpload): http://stackoverflow.com/q/2422468 Alternatively, throw away that jurassic resource/tutorial/book you're using to learn Servlets and lookup more (r|d)ecent ones. – BalusC Mar 04 '16 at 15:58
  • @BalcusC Yep, just noticed this myself when I deleted the 2.5 jar from local maven repo and it re-downloaded. Will look into this now, thanks. – Sam Holden Mar 04 '16 at 16:15
  • @BalcusC I've followed the answer as you linked, but I now get the error `"java.io.FileOutputStream is a restricted class. Please see the Google App Engine developer's guide for more details." ` on the line: `List items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(req);` That answer does not seem to be an answer to this question – Sam Holden Mar 04 '16 at 16:35
  • GAE is a nasty beast. Is this helpful as supplement? http://stackoverflow.com/q/1513603 – BalusC Mar 04 '16 at 16:37
  • Works like a charm thanks :) come to think of it I tried this approach last night but had a different bug in my code (which I've since fixed) which led me to believe this didn't work. Thanks again for the quick replies – Sam Holden Mar 04 '16 at 16:44

0 Answers0