RE: Unable to use Java 8 Language features in JSP

Zak Thompson, modified 7 Years ago. Junior Member Posts: 70 Join Date: 6/13/16 Recent Posts
I'm trying to use Java 8 streams within my init JSP, but running into errors. It seems that using lambdas or method references within a JSP breaks the JSP compiler. According to this LPS case, the issue was resolved on DXP fix pack 3,
I am currently on the latest fix pack (35) on my local development environment. I wasn't sure if there were any additional steps that I had to take to get this to work, or if this is in fact a regression bug.


        //works (manual functional interface)
         Arrays.stream(portletPreferences.getValues("selectedVocabularyIds", new String[]{}))
				.map(new Function<string, long>() {
					@Override
					public Long apply(final String value) {
						return Long.parseLong(value);
					}
				}).collect(Collectors.toList());

		//doesn't work (lambda)
		Arrays.stream(portletPreferences.getValues("selectedVocabularyIds", new String[]{}))
				.map(id -&gt; Long.parseLong(id))
				.collect(Collectors.toList());

		//doesn't work (method reference)
		Arrays.stream(portletPreferences.getValues("selectedVocabularyIds", new String[]{}))
				.map(Long::parseLong)
				.collect(Collectors.toList());
</string,>


Exception Generated (for both lambda and method reference):

java.io.IOException: unexpected tag: 18
	at org.apache.jasper.compiler.SmapUtil$SDEInstaller.copyConstantPool(SmapUtil.java:459)
	at org.apache.jasper.compiler.SmapUtil$SDEInstaller.addSDE(SmapUtil.java:304)
	at org.apache.jasper.compiler.SmapUtil$SDEInstaller.<init>(SmapUtil.java:257)
	at org.apache.jasper.compiler.SmapUtil$SDEInstaller.install(SmapUtil.java:246)
	at org.apache.jasper.compiler.SmapUtil.installSmap(SmapUtil.java:167)
	at org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:406)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:453)
	at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:625)
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:375)
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:473)
	at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:377)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    ........
    15:37:44,371 ERROR [http-apr-8080-exec-2][PortletRequestDispatcherImpl:265] Unable to dispatch request: PWC6033: Error in Javac compilation for JSP
</init>
thumbnail
Olaf Kock, modified 7 Years ago. Liferay Legend Posts: 6441 Join Date: 9/23/08 Recent Posts
As you're on DXP, you might want to open a support ticket. That's what it's there for. And the support staff loves you when you already come with an LPS reference, steps to reproduce, and are on the latest FP.
thumbnail
Minhchau Dang, modified 7 Years ago. Liferay Master Posts: 598 Join Date: 10/22/07 Recent Posts
If your JSP is inside a module, it should work. If the JSP is inside a regular war you deploy to the application server, you also have to modify the entry web.xml for the JspServlet and set compilerSourceVM and compilerTargetVM (as documented in the Jasper How To) if you wish to use JDK 8 features in your JSPs, since it defaults to JDK 7.
Zak Thompson, modified 7 Years ago. Junior Member Posts: 70 Join Date: 6/13/16 Recent Posts
@Olaf

This code was part of an existing front end web portlet, I am going to try to recreate on a vanilla portlet to confirm its an issue with the runtime and not a configuration error, before submitting a ticket

@Minhchau

This code is part of a OSGI module and not a WAR plugin
thumbnail
Minhchau Dang, modified 7 Years ago. Liferay Master Posts: 598 Join Date: 10/22/07 Recent Posts
I don't think it's a regression, since the code change that was submitted in LPS-66641 still exists (reference). It's more likely that it was never fixed and closed erroneously due to improper testing.

It's the same error as SMAP broken in Java 8 for JSP compile, so I'm guessing that we also needed to update a dependency in order to fix it.
Zak Thompson, modified 7 Years ago. Junior Member Posts: 70 Join Date: 6/13/16 Recent Posts
Minhchau Dang:
I don't think it's a regression, since the code change that was submitted in LPS-66641 still exists (reference). It's more likely that it was never fixed and closed erroneously due to improper testing.

It's the same error as SMAP broken in Java 8 for JSP compile, so I'm guessing that we also needed to update a dependency in order to fix it.



I think that would make the most sense. The code seems happy with Arrays.stream and Collectors.toList, so it is definitely compiling against Java 8, as Arrays.stream and the collector class did not exist in Java 7. My best guess is that its compiling against 1.8, but the parser in the dependency does not know how to handle the new lambda and method reference syntax.
Lilian Holden, modified 6 Years ago. New Member Post: 1 Join Date: 11/1/18 Recent Posts
Steps to reproduce:
  1. Deploy the attached bundle
  2. Add the Liferay Sample portlet to the page
Expected behavior is that the portlet will show abc. Actual behavior is that the portlet says "Liferay Sample is temporarily unavailable." and there is an error in the server log:
Error in Javac compilation for JSPPWC6197: An error occurred at line: 4 in the jsp file: /view.jsp
PWC6199: Generated servlet error: lambda expressions are not supported in -source 1.7 (use -source 8 or higher to enable lambda expressions)
Apkjunky
Jan Tošovský, modified 6 Years ago. Liferay Master Posts: 576 Join Date: 7/22/10 Recent Posts
Seeing Jasper in stacktrace I expect you run LR on Tomcat. There is default source/target Java version value used for compiling JSP pages, which can be overridden in /conf/web.xml. Java 8 is default source/target since Tomcat 9 so I suppose you use Tomcat 8.x version. Here you have to add these lines to the proper section inside web.xml:

<init-param>
   <param-name>compilerSourceVM</param-name>
   <param-value>1.8</param-value>
</init-param>
<init-param>
   <param-name>compilerTargetVM</param-name>
   <param-value>1.8</param-value>
</init-param>