Websocket + Pretty Faces = AbstractMethodError
Asked Answered
G

2

0

I'm building a simple JSF 2.3 app in tomcat 8.5. I got the websocket working, and then I added Pretty Faces.

If I use them separately, they both work. I mean, if I remove Pretty Faces' dependencies from the pom, my websocket works. And if I keep the dependencies, and remove the <f:websocket> from my view, Pretty Faces work (redirects ok)!

But, if I try to use Pretty Faces, while I have a <f:websocket> in a view, AbstractMethodError appears when I navigate to it. Literally, if I comment the tag, everything else works.

I use mojarra. In my pom, I'm using the dependecies from https://github.com/javaserverfaces/mojarra/blob/master/README.md, and the default ones for Pretty Faces.

I'm guessing the problem is either that I have conflicting dependencies, from what I read in this BalusC answer, or that Pretty Faces and Websocket conflict somehow.

Any help would be appreciated. Thanks in advance.

Here the dependencies

<!-- Java EE containers -->
<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-web-api</artifactId>
    <version>8.0</version>
    <scope>provided</scope>
</dependency>

<!-- Servlet Containers -->
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.faces</artifactId>
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>org.jboss.weld.servlet</groupId>
    <artifactId>weld-servlet-shaded</artifactId>
    <version>3.0.0.Final</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<dependency> <!-- Optional, only when <f:websocket> is used. -->
    <groupId>org.glassfish</groupId>
    <artifactId>javax.json</artifactId>
    <version>1.1</version>
</dependency>

<!-- Pretty Faces -->
<dependency>
    <groupId>org.ocpsoft.rewrite</groupId>
    <artifactId>rewrite-servlet</artifactId>
    <version>3.4.2.Final</version>
</dependency>
<dependency>
    <groupId>org.ocpsoft.rewrite</groupId>
    <artifactId>rewrite-config-prettyfaces</artifactId>
    <version>3.4.2.Final</version>
</dependency>

Here the exception

Nov 06, 2019 1:49:39 AM com.sun.faces.context.ExceptionHandlerImpl log
FATAL: JSF1073: java.lang.AbstractMethodError caught during processing of RENDER_RESPONSE 6 : UIComponent-ClientId=, Message=null
Nov 06, 2019 1:49:39 AM com.sun.faces.context.ExceptionHandlerImpl log
FATAL: No associated message
java.lang.AbstractMethodError
    at javax.faces.application.ViewHandlerWrapper.getWebsocketURL(ViewHandlerWrapper.java:328)
    at javax.faces.application.ViewHandlerWrapper.getWebsocketURL(ViewHandlerWrapper.java:328)
    at com.sun.faces.push.WebsocketChannelManager.register(WebsocketChannelManager.java:151)
    at com.sun.faces.push.WebsocketChannelManager.register(WebsocketChannelManager.java:142)
    at com.sun.faces.push.WebsocketChannelManager$Proxy$_$$_WeldClientProxy.register(Unknown Source)
    at com.sun.faces.renderkit.html_basic.WebsocketRenderer.encodeEnd(WebsocketRenderer.java:115)
    at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:949)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1912)
    at javax.faces.render.Renderer.encodeChildren(Renderer.java:176)
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:918)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1905)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1908)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1908)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:491)
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:194)
    at org.ocpsoft.rewrite.faces.RewriteViewHandler.renderView(RewriteViewHandler.java:196)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:126)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:223)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:671)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:226)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:728)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:470)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:395)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:316)
    at org.ocpsoft.rewrite.servlet.impl.HttpRewriteResultHandler.handleResult(HttpRewriteResultHandler.java:42)
    at org.ocpsoft.rewrite.servlet.RewriteFilter.rewrite(RewriteFilter.java:297)
    at org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:198)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:660)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:798)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:808)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
Gladiate answered 6/11, 2019 at 1:33 Comment(0)
N
4

Update:

As per Lincoln's comment the new release PrettyFaces 3.4.3 supportes JSF 2.3. Beside other changes it now makes the RewriteViewHandler extend ViewHandlerWrapper as suggested by BalusC.


Background:

It looks like PrettyFaces 3.4.2 is not fully compatible with JSF 2.3.

The non abstract class org.ocpsoft.rewrite.faces.RewriteViewHandler.RewriteViewHandler extends javax.faces.application.ViewHandler but does not override the abstract method getWebsocketURL.

You can easily reproduce this with pretty faces and JSF 2.3 API on class path:

package my.pkg;

import org.ocpsoft.rewrite.faces.RewriteViewHandler;

public class PrettyFacesTest {
    public static void main(String[] args) {
        new RewriteViewHandler(null).getWebsocketURL(null, null);
    }
}

Result:

Exception in thread "main" java.lang.AbstractMethodError: org.ocpsoft.rewrite.faces.RewriteViewHandler.getWebsocketURL(Ljavax/faces/context/FacesContext;Ljava/lang/String;)Ljava/lang/String;
    at my.pkg.PrettyFacesTest.main(PrettyFacesTest.java:7)

The RewriteViewhandler is registered in the rewrite-integration-faces-3.4.2.Final.jar/META-INF/faces-config.xml:

<application>
    <navigation-handler>org.ocpsoft.rewrite.faces.RewriteNavigationHandler</navigation-handler>
    <view-handler>org.ocpsoft.rewrite.faces.RewriteViewHandler</view-handler>
</application>

I'm not sure if there's chance to prevent this registration. If so you could create a CustomRewriteViewHandler that extends RewriteViewHandler, overrides getWebsocketURL and delegates that call to super.parent:

import javax.faces.application.ViewHandler;
import javax.faces.context.FacesContext;

import org.ocpsoft.rewrite.faces.RewriteViewHandler;

public class CustomRewriteViewHandler extends RewriteViewHandler {
    public CustomRewriteViewHandler(ViewHandler viewHandler) {
        super(viewHandler);
    }

    @Override
    public String getWebsocketURL(FacesContext context, String channel) {
        return super.parent.getWebsocketURL(context, channel);
    }
}

You'd then register this CustomRewriteViewHandler instead of the original one:

<application>
    <view-handler>my.pkg.CustomRewriteViewHandler</view-handler>
</application>

As BalusC describes here you cannot block parts of faces-config.xml from the included jar. Instead you can set <faces-config ... metadata-complete="true"> which results in none faces-config.xml nor annotations in any included jars being processed so coming at the cost that you'd need to redefine all the 3d party stuff needed in your own faces.config.xml.

Neocene answered 6/11, 2019 at 7:36 Comment(9)
Ah yes you're right! Thank you. I downloaded the source from github and it looks like the module rewrite-integration-faces is using jsf < 2.3, so the method getWebsocketURL doesn't even exist in ViewHandler. I upgraded jsf there, and overrode it, but am unable to build the whole thing in Eclipse. Will post later if I get it.Gladiate
Getting and modifying the source is a way out of this either, yes. Beware you'll have to ensure that all build environments grab that modified jar.Neocene
Yes, but trying to build the rewrite project is already giving me a headache. So maybe I'll try option 2 from the BalusC answer you suggested.Gladiate
Correct solution for PrettyFaces would be to extend from ViewHandlerWrapper instead of ViewHandler.Hokeypokey
Hey all, thanks for doing the problem solving on this one. Can you please try upgrading to Rewrite/PrettyFaces 3.4.3.Final and let me know if it resolves your issue? I've incorporated what should be basic support for JSF 2.3 / EE7 / EE8 APIs. Release will hit Maven Central shortly. (Might take an overnight cycle but usually syncs in a few hours.)Kuska
@Kuska thanks for your upgrade. I did not (quickly) find your github and issue repository, else I'd have also suggested to report an issue or feature request to support JSF 2.3.Neocene
@Neocene no worries! I have been pretty consumed with another project for a while, so in the end I'm sorry for not keeping up with the new APIs sooner :) Thanks again for putting together the patch / fix. It was right on, but I just took a different approach for updating the API dependencies in the pom to keep things a bit more consistent with the project's historical style.Kuska
The project's test suite really needs to be updated as I think several of the containers no longer run at all for one reason or another... dependency rot.Kuska
@Kuska btw. it was onzinsky who forked and committed changes. I analyzed and proposed a workaround only.Neocene
G
1

As @Selaron detected, the problem was that PrettyFaces does not support JSF 2.3's Websocket, since the class RewriteViewHandler does not implement the method getWebsocketURL. Here's his solution to the problem.

Once he pointed it out, I forked PrettyFaces (ocpsoft/rewrite) and discovered there was no support for JSF 2.3 at all. So I tried and upgrade to JSF 2.3, which seemed cleaner (at least to me) than @Selaron's answer.

Here's the commit of the thing working. I won't get into the specifics of what I had to change (which are explained in the commit).

One last thing. As I mentioned in my question, the only two dependencies I used to include in my pom.xml for PrettyFaces are the default ones.

But when I build the project in my local environment, I needed to add some more.

Here they are

<dependency>
    <groupId>org.ocpsoft.rewrite</groupId>
    <artifactId>rewrite-impl-servlet</artifactId>
    <version>3.4.3-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.ocpsoft.rewrite</groupId>
    <artifactId>rewrite-config-prettyfaces</artifactId>
    <version>3.4.3-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.ocpsoft.rewrite</groupId>
    <artifactId>rewrite-api-servlet</artifactId>
    <version>3.4.3-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.ocpsoft.rewrite</groupId>
    <artifactId>rewrite-annotations-impl</artifactId>
    <version>3.4.3-SNAPSHOT</version>
</dependency>

Cloning/downloading from my branch of ocpsoft/rewrite, installing the project locally, and adding those dependencies into your pom.xml should allow you to make PrettyFaces + JSF 2.3's websocket to work.

PS - I am reticent to mark any of the answers as accepted right now. (I'll give a try to @Selaron's and decide then).

Gladiate answered 8/11, 2019 at 2:12 Comment(3)
The correct solution is to let RewriteViewHandler extend from ViewHandlerWrapper instead of ViewHandler. Actually all JSF libraries which try to wrap an existing JSF artifact named "Foo" must extend from "FooWrapper" instead of from Foo (note the "Wrapper" suffix, this is mandatory, they all in turn implement FacesWrapper). This will ensure that you don't need to manually add yet another bunch of missing methods in your non-wrapper class when you upgrade to next JSF API version which happens to have added new methods to Foo. Instead, the JSF API will add these methods to the FooWrapper class!Hokeypokey
Thanks @BalusC. I read your first comment to @Selaron's answer, and already tried that, but I got Unable to create a new instance of 'org.ocpsoft.rewrite.faces.RewriteViewHandler'. I will try to solve it later.Gladiate
Hi @onzinsky, I updated my answer due to Lincoln's comment. PrettyFaces 3.4.3 upgraded to support JSF 2.3 and thus should solve your problem.Neocene

© 2022 - 2024 — McMap. All rights reserved.