2

My intention is to deploy an existing WAR to embedded Jetty 9.4.5.

Unfortunately I get the following error when trying to open a page (JSP):

An error occurred at line: [52] in the generated java file: [/tmp/embedded-jetty-jsp/jsp/org/apache/jsp/WEB_002dINF/jsp/MainLayout_jsp.java]
Type mismatch: cannot convert from HashSet<?> to Set<String>

An error occurred at line: [52] in the generated java file: [/tmp/embedded-jetty-jsp/jsp/org/apache/jsp/WEB_002dINF/jsp/MainLayout_jsp.java]
Cannot instantiate the type HashSet<?>

An error occurred at line: [52] in the generated java file: [/tmp/embedded-jetty-jsp/jsp/org/apache/jsp/WEB_002dINF/jsp/MainLayout_jsp.java]
Syntax error on token "<", ? expected after this token

The line in question in Java is as follows:

private static final java.util.Set<java.lang.String> _jspx_imports_packages = new java.util.HashSet<>();

It seems that Jasper tried to compile the code as Java 1.6 or below so the diamond operator cannot be interpreted (I am having Java 1.8.0_141).

I tried to set the version but no success:

ServletHolder holderJsp = new ServletHolder("jsp",JspServlet.class);
holderJsp.setInitOrder(0);
holderJsp.setInitParameter("logVerbosityLevel","DEBUG");
holderJsp.setInitParameter("compilerTargetVM","1.7");
holderJsp.setInitParameter("compilerSourceVM","1.7");
holderJsp.setInitParameter("keepgenerated","true");
webAppContext.addServlet(holderJsp,"*.jsp");

The code that starts Jetty is

public class JettyRunner {

  private static File getScratchDir() throws IOException {
     File tempDir = new File(System.getProperty("java.io.tmpdir"));
     File scratchDir = new File(tempDir.toString(), "embedded-jetty-jsp");

     if (!scratchDir.exists()) {
        if (!scratchDir.mkdirs()) {
           throw new IOException("Unable to create scratch directory: " + scratchDir);
        }
     }
     return scratchDir;
  }

  private static List<ContainerInitializer> jspInitializers() {
     JettyJasperInitializer sci = new JettyJasperInitializer();
     ContainerInitializer initializer = new ContainerInitializer(sci, null);
     List<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>();
     initializers.add(initializer);
     return initializers;
  } 


  public static void main(String[] args) {
     Server server = new Server(8080);

     WebAppContext webAppContext = new WebAppContext();
     File warFile = new File("existing.war");
     webAppContext.setWar(warFile.getAbsolutePath());
     webAppContext.setContextPath("/acme");

     webAppContext.setConfigurations(new Configuration[] {
              new AnnotationConfiguration(),
              new WebInfConfiguration(),
              new WebXmlConfiguration(),
              new MetaInfConfiguration(),
              new FragmentConfiguration(),
              new EnvConfiguration(),
              new PlusConfiguration(),
              new JettyWebXmlConfiguration()
     });

     webAppContext.setAttribute("javax.servlet.context.tempdir", getScratchDir());
     webAppContext.setAttribute("org.eclipse.jetty.containerInitializers", jspInitializers());
     webAppContext.setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager());
     webAppContext.addBean(new ServletContainerInitializersStarter(webAppContext), true);

     ServletHolder holderJsp = new ServletHolder("jsp",JspServlet.class);
     holderJsp.setInitOrder(0);
     holderJsp.setInitParameter("logVerbosityLevel","DEBUG");
     holderJsp.setInitParameter("compilerTargetVM","1.7");
     holderJsp.setInitParameter("compilerSourceVM","1.7");
     holderJsp.setInitParameter("keepgenerated","true");
     webAppContext.addServlet(holderJsp,"*.jsp");

     webAppContext.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",".*/[^/]*jstl.*\\.jar$");
     org.eclipse.jetty.webapp.Configuration.ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);
     classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration");
     classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", "org.eclipse.jetty.annotations.AnnotationConfiguration");

     HashLoginService hashLoginService = new HashLoginService();
     hashLoginService.setName("Test Realm");
     hashLoginService.setConfig("jetty-realm.properties");

     webAppContext.getSecurityHandler().setLoginService(hashLoginService);

     server.setHandler(webAppContext);          

     // Start Jetty
     server.start();
     server.join();
  }

}

Any hint would be highly appreciated!
Thanks, V.

--------------------------- UPDATE 1 ---------------------------
I set the server.setDumpAfterStart(true); (thanks @JoakimErdfelt for the hint!) and commented out the code where I set the compilerTargetVM etc. (so I don't add the JspServlet to webAppContext!) and I can see that

|   += org.eclipse.jetty.server.session.SessionHandler483422889==dftMaxIdleSec=1800 - STARTED
|   |   += org.eclipse.jetty.security.ConstraintSecurityHandler@7c75222b - STARTED
|   |   |   +- org.eclipse.jetty.security.DefaultAuthenticatorFactory@4c203ea1
|   |   |   += org.eclipse.jetty.servlet.ServletHandler@27f674d - STARTED
|   |   |   |   += jsp@19c47==org.eclipse.jetty.jsp.JettyJspServlet,jsp=null,order=0,inst=true - STARTED
|   |   |   |   |   +- fork=false
|   |   |   |   |   +- compilerSourceVM=1.7
|   |   |   |   |   +- logVerbosityLevel=DEBUG
|   |   |   |   |   +- compilerTargetVM=1.7
|   |   |   |   |   +- scratchdir=/tmp/embedded-jetty-jsp/jsp
|   |   |   |   |   +- xpoweredBy=false

So the Java source is set to 1.7 but still the diamond operator cannot be interpreted by the JVM!
Bummer... Any idea?
Thank you very much!

Viktor
  • 1,325
  • 2
  • 19
  • 41
  • A server dump might help. Add `server.setDumpAfterStart(true);` before your `server.start()`. Edit your question and add the dump to it please. – Joakim Erdfelt Feb 14 '18 at 15:40
  • Thanks for the hint, I am updating my post! – Viktor Feb 15 '18 at 08:23
  • The dump shows that you are using the proper `JettyJspServlet`, but your code is using `JspServlet`. Assumption: Your code isn't running, the configuration is arriving via the default descriptor definition. – Joakim Erdfelt Feb 15 '18 at 12:09
  • I had hoped you would include the entire dump, so I could see the list of JARs in your webapp (there are old reports of similar issues to yours, and it was due to a bad WAR file that included JARs that cause conflicts with JSP). – Joakim Erdfelt Feb 15 '18 at 12:10
  • Sorry, I uploaded the log to https://www.protectedtext.com/vikhor_jetty (the password is 'vikhor_jetty'). Also I alter the `new ServletHolder("jsp",JspServlet.class);` to `new ServletHolder("jsp",JettyJspServlet.class);`. Thanks! – Viktor Feb 15 '18 at 14:53

1 Answers1

0

Your WAR has WEB-INF/lib/ entries that are conflicting with the updated version of JSP.

Remove the following entries from your WAR.

WEB-INF/lib/jstl-1.1.2.jar
WEB-INF/lib/standard-1.1.2.jar

Those jars should never have been included in your WAR file in the first place.

Those are provided by the JSP Container.

Also, get rid of this ...

webAppContext.setConfigurations(new Configuration[] {
          new AnnotationConfiguration(),
          new WebInfConfiguration(),
          new WebXmlConfiguration(),
          new MetaInfConfiguration(),
          new FragmentConfiguration(),
          new EnvConfiguration(),
          new PlusConfiguration(),
          new JettyWebXmlConfiguration()
 });

... and add this instead (before you create the WebAppContext) ...

    Configuration.ClassList classlist = Configuration.ClassList
            .setServerDefault( server );
    classlist.addAfter(
            "org.eclipse.jetty.webapp.FragmentConfiguration",
            "org.eclipse.jetty.plus.webapp.EnvConfiguration",
            "org.eclipse.jetty.plus.webapp.PlusConfiguration");

    classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
                        "org.eclipse.jetty.annotations.AnnotationConfiguration");

As its inappropriate to "set" the entire configuration list, use the modification routines instead.

Example taken from https://github.com/eclipse/jetty.project/blob/jetty-9.4.8.v20171121/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java#L186-L195

Joakim Erdfelt
  • 46,896
  • 7
  • 86
  • 136
  • Nice one! I could progress I have a different exception now. :) Thanks for the help! – Viktor Feb 16 '18 at 08:12
  • Hi @JoakimErdfelt, I am afraid I have to reopen this issue as if I remove the jstl and standard JAR files from the WAR (however they are still in the classpath but not in the WAR) then I get the `The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application` . I presume it means that Jetty cannot find the JSTL JAR. So this latest exception occurs earlier than the original one (detailed in the ticket description above). – Viktor Feb 19 '18 at 11:45
  • That message is because you have other JSTL jars in your `WEB-INF/lib` that we both missed. Remove those too. – Joakim Erdfelt Feb 20 '18 at 00:53