title: How to add javax.activation.DataSource to App Engine devserver?
body: <p><strong>tl;dr:</strong> How do I add the <code>javax.activation.DataSource</code> dependency to a server run through the App Engine Maven plugin?</p>
  
  <p>I'm using the <a href="https://cloud.google.com/appengine/docs/standard/java/tools/maven" rel="noreferrer">App Engine Maven plugin</a> to deploy to a local App Engine server, and I'm trying to use the Blobstore API to upload a file. I'm using Java 11.</p>
  
  <p><strong>pom.xml</strong></p>
  
  <pre><code>&lt;project xmlns="http://maven.apache.org/POM/4.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  
    &lt;groupId&gt;io.happycoding&lt;/groupId&gt;
    &lt;artifactId&gt;blobstore-test&lt;/artifactId&gt;
    &lt;version&gt;1&lt;/version&gt;
    &lt;packaging&gt;war&lt;/packaging&gt;
  
    &lt;properties&gt;
      &lt;!-- App Engine currently supports Java 8 --&gt;
      &lt;maven.compiler.source&gt;1.8&lt;/maven.compiler.source&gt;
      &lt;maven.compiler.target&gt;1.8&lt;/maven.compiler.target&gt;
      &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
      &lt;failOnMissingWebXml&gt;false&lt;/failOnMissingWebXml&gt;
    &lt;/properties&gt;
  
    &lt;dependencies&gt;
      &lt;dependency&gt;
        &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
        &lt;artifactId&gt;javax.servlet-api&lt;/artifactId&gt;
        &lt;version&gt;4.0.1&lt;/version&gt;
        &lt;scope&gt;provided&lt;/scope&gt;
      &lt;/dependency&gt;
  
      &lt;dependency&gt;
        &lt;groupId&gt;org.apache.taglibs&lt;/groupId&gt;
        &lt;artifactId&gt;taglibs-standard-spec&lt;/artifactId&gt;
        &lt;version&gt;1.2.5&lt;/version&gt;
      &lt;/dependency&gt;
  
      &lt;dependency&gt;
        &lt;groupId&gt;com.google.appengine&lt;/groupId&gt;
        &lt;artifactId&gt;appengine-api-1.0-sdk&lt;/artifactId&gt;
        &lt;version&gt;1.9.59&lt;/version&gt;
      &lt;/dependency&gt;
  
    &lt;/dependencies&gt;
  
    &lt;build&gt;
      &lt;plugins&gt;
        &lt;plugin&gt;
          &lt;groupId&gt;com.google.appengine&lt;/groupId&gt;
          &lt;artifactId&gt;appengine-maven-plugin&lt;/artifactId&gt;
          &lt;version&gt;1.9.71&lt;/version&gt;
        &lt;/plugin&gt;
      &lt;/plugins&gt;
    &lt;/build&gt;
  &lt;/project&gt;
  </code></pre>
  
  <p><strong>index.jsp</strong></p>
  
  <pre><code>&lt;%@ page import="com.google.appengine.api.blobstore.BlobstoreServiceFactory" %&gt;
  
  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;head&gt;
      &lt;meta charset="UTF-8"&gt;
    &lt;/head&gt;
    &lt;body&gt;
  
      &lt;form action="&lt;%= BlobstoreServiceFactory.getBlobstoreService().createUploadUrl("/submit") %&gt;" 
        method="POST"
        enctype="multipart/form-data"&gt;
  
        Enter some text:
        &lt;br/&gt;
        &lt;textarea name="text"&gt;&lt;/textarea&gt;
        &lt;br/&gt;
        Select a file:
        &lt;input type="file" name="image"&gt;
        &lt;br/&gt;
        &lt;input type="submit" value="Submit"&gt;
      &lt;/form&gt;
  
    &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p><strong>SubmitServlet.java</strong></p>
  
  <pre><code>package io.happycoding.servlets;
  
  import javax.servlet.annotation.WebServlet;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  @WebServlet("/submit")
  public class SubmitServlet extends HttpServlet {
  
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
      System.out.println("data submitted");
    }
  }
  </code></pre>
  
  <p><strong>Command to run the local server:</strong> <code>mvn appengine:devserver</code></p>
  
  <p>I can successfully run a local server, and I can see that the form is rendered correctly, including the Blobstore URL.</p>
  
  <p>However, when I submit the form, I get this error:</p>
  
  <pre><code>java.lang.NoClassDefFoundError: javax/activation/DataSource
      at com.google.appengine.api.blobstore.dev.UploadBlobServlet.handleUpload(UploadBlobServlet.java:171)
      at com.google.appengine.api.blobstore.dev.UploadBlobServlet.access$000(UploadBlobServlet.java:69)
      at com.google.appengine.api.blobstore.dev.UploadBlobServlet$1.run(UploadBlobServlet.java:115)
      at java.base/java.security.AccessController.doPrivileged(Native Method)
      at com.google.appengine.api.blobstore.dev.UploadBlobServlet.doPost(UploadBlobServlet.java:112)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
      at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:867)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1623)
      at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:134)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
      at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
      at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
      at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:48)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
      at com.google.appengine.tools.development.jetty9.StaticFileFilter.doFilter(StaticFileFilter.java:123)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
      at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:366)
      at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:349)
      at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
      at com.google.appengine.tools.development.DevAppServerRequestLogFilter.doFilter(DevAppServerRequestLogFilter.java:44)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1602)
      at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:540)
      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
      at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
      at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
      at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
      at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1588)
      at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
      at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345)
      at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
      at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480)
      at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1557)
      at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
      at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247)
      at com.google.appengine.tools.development.jetty9.DevAppEngineWebAppContext.doScope(DevAppEngineWebAppContext.java:94)
      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
      at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
      at com.google.appengine.tools.development.jetty9.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:595)
      at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
      at org.eclipse.jetty.server.Server.handle(Server.java:502)
      at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)
      at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
      at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
      at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
      at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
      at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)
      at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310)
      at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
      at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
      at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
      at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
      at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
      at java.base/java.lang.Thread.run(Thread.java:834)
  Caused by: java.lang.ClassNotFoundException: javax.activation.DataSource
      at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
      at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
      at com.google.appengine.tools.development.DevAppServerClassLoader.loadClass(DevAppServerClassLoader.java:108)
      at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
      ... 57 more
  </code></pre>
  
  <p>Some Googling reveals quite a few questions about this problem:</p>
  
  <ul>
  <li><a href="https://stackoverflow.com/q/52921879/873165">Migration to JDK 11 has error occure “java.lang.NoClassDefFoundError: javax/activation/DataSource”</a></li>
  <li><a href="https://stackoverflow.com/q/46920461/873165">java.lang.NoClassDefFoundError: javax/activation/DataSource on wsimport Intellij java 9</a></li>
  <li><a href="https://stackoverflow.com/q/46493613/873165">What is the replacement for javax.activation package in java 9?</a></li>
  <li><a href="https://stackoverflow.com/q/8186395/873165">NoClassDefFoundError: javax/activation/DataSource</a></li>
  </ul>
  
  <p>The answers to these questions suggest adding a combination of these dependencies:</p>
  
  <pre><code>&lt;dependency&gt;
    &lt;groupId&gt;javax.activation&lt;/groupId&gt;
    &lt;artifactId&gt;javax.activation-api&lt;/artifactId&gt;
    &lt;version&gt;1.2.0&lt;/version&gt;
  &lt;/dependency&gt;
  
  &lt;dependency&gt;
      &lt;groupId&gt;javax.activation&lt;/groupId&gt;
      &lt;artifactId&gt;activation&lt;/artifactId&gt;
      &lt;version&gt;1.1.1&lt;/version&gt;
  &lt;/dependency&gt;
  
  &lt;dependency&gt;
      &lt;groupId&gt;com.sun.activation&lt;/groupId&gt;
      &lt;artifactId&gt;javax.activation&lt;/artifactId&gt;
      &lt;version&gt;1.2.0&lt;/version&gt;
  &lt;/dependency&gt;
  </code></pre>
  
  <p>I've tried adding each of these, and I've tried adding all of them. But no matter what, I still get the above error.</p>
  
  <p>I understand <strong>why</strong> this is happening: Java 8 included the <code>javax.activation.DataSource</code> class, and it was subsequently removed. So since I'm using Java 11, that class is missing. But none of the dependencies I've tried so far seem to provide the missing class, possibly because I'm using the App Engine Maven plugin instead of running my own server?</p>
  
  <p>How do I add this dependency to a project that uses the App Engine Maven plugin?</p>