B4J Library jServer (5) based on Jetty 12.1

This is a beta version.

Download link:

Copy the files to the internal libraries folder (keep the inner jserver folder). The files are different than jServer(4) files so both will work together.
The library is named jServer5. It will be renamed to jServer with the next release of B4J.

Java 17+ is required.

There is a new optional event for WebSocket handlers:
B4X:
'Return False to reject the upgrade request.
Private Sub WebSocket_Upgrade (UpgradeRequest As ServletRequest) As Boolean
    Return True
End Sub
You can use it to create a http session and to reject upgrade requests.

WebSocket.Flush is no longer needed and the method doesn't do anything.

If you used JavaObject to access Jetty APIs then they might need to be updated. Other than that, existing projects should work with no changes.

Standalone package declarations:
B4X:
#PackagerProperty: AdditionalModuleInfoString = provides org.slf4j.spi.SLF4JServiceProvider with org.eclipse.jetty.logging.JettyLoggingServiceProvider;
#PackagerProperty: AdditionalModuleInfoString = exports anywheresoftware.b4j.object;
#PackagerProperty: AdditionalModuleInfoString = provides org.eclipse.jetty.io.ssl.ALPNProcessor.Server with org.eclipse.jetty.alpn.java.server.JDK9ServerALPNProcessor;
#PackagerProperty: AdditionalModuleInfoString = provides org.eclipse.jetty.http.HttpFieldPreEncoder with org.eclipse.jetty.http.Http10FieldPreEncoder, org.eclipse.jetty.http.Http11FieldPreEncoder;
#PackagerProperty: AdditionalModuleInfoString = uses org.eclipse.jetty.util.security.CredentialProvider;
#PackagerProperty: AdditionalModuleInfoString = uses org.eclipse.jetty.io.ssl.ALPNProcessor.Server;
#PackagerProperty: IncludedModules = jdk.charsets, jdk.crypto.ec
#CustomBuildAction: After Packager, %WINDIR%\System32\robocopy.exe, www temp\build\bin\www /E
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
jServer users - please try the new version. It will be the default version starting with the next B4J update.

I noticed a behavioral change related to the combination of ServletRequest.GetParameter + req.GetInputStream + application/x-www-form-urlencoded content type, where you cannot get the input stream without consuming it, and then get a query parameter with GetParameter as it will consume the input stream.
 

aeric

Expert
Licensed User
Longtime User
So far I get an error with the www folder.

My code:
B4X:
srvr.StaticFilesFolder = staticfiles.Folder
srvr.SetStaticFilesOptions(CreateMap("dirAllowed": staticfiles.Browsable))
srvr.Start

Error:
B4X:
Waiting for debugger to connect...
Program started.
GET: Index->
POST: Index->/modal
GET: Index->/api/*
PUT: Index->/api/*
SSL is enabled
2026-07-15 13:02:22.835:INFO :oejs.Server:main: jetty-12.1.10; built: 2026-05-31T04:45:52.925Z; git: 986024525891c2c20ff08c58ba300dc3b9847586; jvm 19.0.2+7-44
2026-07-15 13:02:22.873:INFO :oejs.RequestLogWriter:main: Opened C:\B4X\Development\EndsMeet\beta\Objects\logs\b4j-2026_07_15.request.log
Error occurred on line: 249 (EndsMeet)
java.lang.IllegalArgumentException: Base Resource is not valid: file:///C:/B4X/DEVELO~1/EndsMeet/beta/Objects/www
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:894)
    at org.eclipse.jetty.ee11.servlet.ServletContextHandler.startContext(ServletContextHandler.java:1343)
    at org.eclipse.jetty.ee11.servlet.ServletContextHandler.lambda$doStart$0(ServletContextHandler.java:1066)
    at org.eclipse.jetty.server.handler.ContextHandler$ScopedContext.call(ContextHandler.java:1665)
    at org.eclipse.jetty.ee11.servlet.ServletContextHandler.doStart(ServletContextHandler.java:1063)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:92)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:170)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:121)
    at org.eclipse.jetty.server.Handler$Abstract.doStart(Handler.java:545)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:92)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:170)
    at org.eclipse.jetty.server.Server.start(Server.java:689)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:121)
    at org.eclipse.jetty.server.Handler$Abstract.doStart(Handler.java:545)
    at org.eclipse.jetty.server.Server.doStart(Server.java:630)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:92)
    at anywheresoftware.b4j.object.ServerWrapper.Start(ServerWrapper.java:274)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:676)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:240)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:117)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:104)
    at com.puterise.main.main(main.java:29)
 

aeric

Expert
Licensed User
Longtime User
What is the output of Log(staticfiles.Folder) ?
Are you sure that it exists? I get this error with non-existent folders.
C:\B4X\DEVELO~1\EndsMeet\beta\Objects\www

Sorry, I didn't created it.
Once I created it, the error is gone.
 

Cableguy

Expert
Licensed User
Longtime User
@alwaysbusy ... How difficult would it be to "upgrade" ABM from jServer 4 to JServer 5?
 

Cableguy

Expert
Licensed User
Longtime User
@Cableguy I'll check it later and come back about it. I know there are things with java-object that will not work any more (e.g. getpolicy I think it's called, does not exist anymore)
no worries, as it is an encapsulated server, It can, if it must, stay with jServer4
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
I know there are things with java-object that will not work any more (e.g. getpolicy I think it's called, does not exist anymore)
Most of the APIs are still there, in some cases the package name has changed. FWIW, jServer 5 is based on Jetty 12.1 + Jakarta EE 11 (Servlet 6.1) as the servlets implementation.
 

Chris2

Active Member
Licensed User
Longtime User
Is it expected that this works 'out of the box' with jRDC2?

I've jumped right in and am testing an app based (but modified) on jRDC2 with jServer5. Specifically the app was originally based on @OliverA's version with SQLite support.

At first I got the same error as @aeric above which is resolved by creating the www folder - I still thought it worth mentioning again though because I've never had to do this with previous jServer versions.

But then I get the following error in RDCHandler.Handle at the line
RDCHandler.Handle:
Dim method As String = req.GetParameter("method")
Error occurred on line: 22 (RDCHandler)
org.eclipse.jetty.http.HttpException$IllegalStateException: 400: Unable to parse form content
at org.eclipse.jetty.ee11.servlet.ServletApiRequest.extractContentParameters(ServletApiRequest.java:1094)
at org.eclipse.jetty.ee11.servlet.ServletApiRequest.getParameters(ServletApiRequest.java:1050)
at org.eclipse.jetty.ee11.servlet.ServletApiRequest.getParameter(ServletApiRequest.java:1019)
at anywheresoftware.b4j.object.JServlet$ServletRequestWrapper.GetParameter(JServlet.java:260)
at newfoundenergy.atlas.rdc.rdchandler._handle(rdchandler.java:1133)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:632)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:117)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:104)
at anywheresoftware.b4j.object.JServlet$Handle.run(JServlet.java:158)
at anywheresoftware.b4j.object.JServlet.Handle(JServlet.java:138)
at anywheresoftware.b4j.object.JServlet.doPost(JServlet.java:104)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:653)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.eclipse.jetty.ee11.servlet.ServletHolder.handle(ServletHolder.java:754)
at org.eclipse.jetty.ee11.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1668)
at anywheresoftware.b4j.object.JServlet$Handle.run(JServlet.java:163)
at anywheresoftware.b4j.object.JServlet.Handle(JServlet.java:138)
at anywheresoftware.b4j.object.JServlet.doFilter(JServlet.java:96)
at org.eclipse.jetty.ee11.servlet.FilterHolder.doFilter(FilterHolder.java:205)
at org.eclipse.jetty.ee11.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1640)
at org.eclipse.jetty.ee11.servlets.DoSFilter.doFilterChain(DoSFilter.java:464)
at org.eclipse.jetty.ee11.servlets.DoSFilter.doFilter(DoSFilter.java:318)
at org.eclipse.jetty.ee11.servlets.DoSFilter.doFilter(DoSFilter.java:283)
at org.eclipse.jetty.ee11.servlet.FilterHolder.doFilter(FilterHolder.java:205)
at org.eclipse.jetty.ee11.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1640)
at anywheresoftware.b4j.object.JServlet$Handle.run(JServlet.java:163)
at anywheresoftware.b4a.keywords.SimpleMessageLoop.runMessageLoop(SimpleMessageLoop.java:47)
at anywheresoftware.b4a.StandardBA.startMessageLoop(StandardBA.java:43)
at anywheresoftware.b4a.shell.ShellBA.startMessageLoop(ShellBA.java:121)
at anywheresoftware.b4a.keywords.Common.StartMessageLoop(Common.java:183)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:309)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:117)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:104)
at newfoundenergy.atlas.rdc.main.main(main.java:34)
Caused by: java.util.concurrent.CompletionException: org.eclipse.jetty.util.Utf8StringBuilder$Utf8IllegalArgumentException: CharacterCodingException@18b0930f: Invalid UTF-8
at java.base/java.util.concurrent.CompletableFuture.reportJoin(CompletableFuture.java:413)
at java.base/java.util.concurrent.CompletableFuture.join(CompletableFuture.java:2118)
at org.eclipse.jetty.io.content.ContentSourceCompletableFuture.join(ContentSourceCompletableFuture.java:234)
at org.eclipse.jetty.server.FormFields.getFields(FormFields.java:144)
at org.eclipse.jetty.ee11.servlet.ServletApiRequest.extractContentParameters(ServletApiRequest.java:1090)
... 50 more
Caused by: org.eclipse.jetty.util.Utf8StringBuilder$Utf8IllegalArgumentException: CharacterCodingException@18b0930f: Invalid UTF-8
at org.eclipse.jetty.util.Utf8StringBuilder.errorActionReport(Utf8StringBuilder.java:145)
at org.eclipse.jetty.util.Utf8StringBuilder.handleUnmappableCharacter(Utf8StringBuilder.java:177)
at org.eclipse.jetty.util.Utf8StringBuilder.appendByte(Utf8StringBuilder.java:397)
at org.eclipse.jetty.util.Utf8StringBuilder.append(Utf8StringBuilder.java:271)
at org.eclipse.jetty.server.FormFields.parse(FormFields.java:421)
at org.eclipse.jetty.server.FormFields.parse(FormFields.java:40)
at org.eclipse.jetty.io.content.ContentSourceCompletableFuture.parse(ContentSourceCompletableFuture.java:126)
at org.eclipse.jetty.server.FormFields.from(FormFields.java:337)
... 52 more
Caused by: CharacterCodingException@18b0930f: Invalid UTF-8
at org.eclipse.jetty.util.Utf8StringBuilder$Utf8IllegalArgumentException.<init>(Utf8StringBuilder.java:543)
... 60 more
java.lang.RuntimeException: timeout waiting for handler to start
the error continues with many more 'Invalid UTF-8' errors. I haven't changed anything in the files that house the queries and DB connection details - they are UTF-8 encoded. This error does not occur with jServer 4.10.

Update: having thought about this more after reading what I've written above, it's in RDCHandler so this issue must be comming from a client.... I'll investigate more.
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
At first I got the same error as @aeric above which is resolved by creating the www folder - I still thought it worth mentioning again though because I've never had to do this with previous jServer versions.
Fixed in v5.01. The folder will be created if doesn't exist.

The other issue does look like a rogue client. If you are able to reproduce it then please post more information.
 

Chris2

Active Member
Licensed User
Longtime User
Fixed in v5.01. The folder will be created if doesn't exist.
👍

The other issue does look like a rogue client. If you are able to reproduce it then please post more information.
I've gone back to @OliverA's Modded jRDC2 w/SQLite support , modifying only to change the SQLite jdbc driver version in use, and to hard code the database file path for ease (see RDCConnector.Initialize, filePath & fileName).
Then I've created a basic client app to test the RDC connection and then run a basic 'SELECT * from Table1' query.

With jServer 4.10 all works OK, but with jServer5 the RDC connection test works, but the query fails with the same error I noted above in the jRDC server at
B4X:
Dim method As String = req.GetParameter("method")
Waiting for debugger to connect...
Program started.
SQLite DB's path: D:\B4J\JServer5Tests\Basic\DB, file name: test.db, create flag: true
Fetching IP address via getLocalHostLANAddress
2026-07-25 11:30:35.268:INFO :eek:ejs.Server:main: jetty-12.1.10; built: 2026-05-31T04:45:52.925Z; git: 986024525891c2c20ff08c58ba300dc3b9847586; jvm 17.0.16+8
2026-07-25 11:30:35.289:INFO :eek:ejs.RequestLogWriter:main: Opened D:\B4J\JServer5Tests\Basic\jRDC2SQLite\Objects\logs\b4j-2026_07_25.request.log
2026-07-25 11:30:35.314:INFO :eek:ejs.DefaultSessionIdManager:main: Session workerName=node0
2026-07-25 11:30:35.323:INFO :eek:ejsh.ContextHandler:main: Started oeje11s.ServletContextHandler@f58853c{ROOT,/,b=file:///D:/B4J/JServer5Tests/Basic/jRDC2SQLite/Objects/www/,a=AVAILABLE,h=oeje11s.SessionHandler@1224144a{STARTED}}
2026-07-25 11:30:35.327:INFO :eek:eje11s.ServletContextHandler:main: Started oeje11s.ServletContextHandler@f58853c{ROOT,/,b=file:///D:/B4J/JServer5Tests/Basic/jRDC2SQLite/Objects/www/,a=AVAILABLE,h=oeje11s.SessionHandler@1224144a{STARTED}}
2026-07-25 11:30:35.357:INFO :eek:ejs.AbstractConnector:main: Started oejs.ServerConnector@56dc1551{HTTP/1.1, (http/1.1)}{0.0.0.0:17178}
2026-07-25 11:30:35.357:INFO :eek:ejs.Server:main: Started oejs.Server@74f6c5d8{STARTING}[12.1.10,sto=0] @91ms
Emulated network latency: 100ms
Modified jRDC is running (version = 2.23)
Note: jRDC is running without V1 support
Bound to: 192.168.1.219:17178
Error occurred on line: 14 (RDCHandler)
org.eclipse.jetty.http.HttpException$IllegalStateException: 400: Unable to parse form content
at org.eclipse.jetty.ee11.servlet.ServletApiRequest.extractContentParameters(ServletApiRequest.java:1094)
at org.eclipse.jetty.ee11.servlet.ServletApiRequest.getParameters(ServletApiRequest.java:1050)
at org.eclipse.jetty.ee11.servlet.ServletApiRequest.getParameter(ServletApiRequest.java:1019)
at anywheresoftware.b4j.object.JServlet$ServletRequestWrapper.GetParameter(JServlet.java:260)
at b4j.example.rdchandler._handle(rdchandler.java:702)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:632)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:117)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:104)
at anywheresoftware.b4j.object.JServlet$Handle.run(JServlet.java:158)
at anywheresoftware.b4a.keywords.SimpleMessageLoop.runMessageLoop(SimpleMessageLoop.java:47)
at anywheresoftware.b4a.StandardBA.startMessageLoop(StandardBA.java:43)
at anywheresoftware.b4a.shell.ShellBA.startMessageLoop(ShellBA.java:121)
at anywheresoftware.b4a.keywords.Common.StartMessageLoop(Common.java:183)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:309)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:117)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:104)
at b4j.example.main.main(main.java:34)
Caused by: java.util.concurrent.CompletionException: org.eclipse.jetty.util.Utf8StringBuilder$Utf8IllegalArgumentException: CharacterCodingException@589da3f3: Invalid UTF-8
at java.base/java.util.concurrent.CompletableFuture.reportJoin(CompletableFuture.java:413)
at java.base/java.util.concurrent.CompletableFuture.join(CompletableFuture.java:2118)
at org.eclipse.jetty.io.content.ContentSourceCompletableFuture.join(ContentSourceCompletableFuture.java:234)
at org.eclipse.jetty.server.FormFields.getFields(FormFields.java:144)
at org.eclipse.jetty.ee11.servlet.ServletApiRequest.extractContentParameters(ServletApiRequest.java:1090)
... 33 more
Caused by: org.eclipse.jetty.util.Utf8StringBuilder$Utf8IllegalArgumentException: CharacterCodingException@589da3f3: Invalid UTF-8
at org.eclipse.jetty.util.Utf8StringBuilder.errorActionReport(Utf8StringBuilder.java:145)
at org.eclipse.jetty.util.Utf8StringBuilder.handleUnmappableCharacter(Utf8StringBuilder.java:177)
at org.eclipse.jetty.util.Utf8StringBuilder.appendByte(Utf8StringBuilder.java:397)
at org.eclipse.jetty.util.Utf8StringBuilder.append(Utf8StringBuilder.java:271)
at org.eclipse.jetty.server.FormFields.parse(FormFields.java:421)
at org.eclipse.jetty.server.FormFields.parse(FormFields.java:40)
at org.eclipse.jetty.io.content.ContentSourceCompletableFuture.parse(ContentSourceCompletableFuture.java:126)
at org.eclipse.jetty.server.FormFields.from(FormFields.java:337)
... 35 more
Caused by: CharacterCodingException@589da3f3: Invalid UTF-8
at org.eclipse.jetty.util.Utf8StringBuilder$Utf8IllegalArgumentException.<init>(Utf8StringBuilder.java:543)
... 43 more

My test apps and SQLite database are attached if someone else can give this a go in case I'm doing something stupid please. Thanks.

Edit:
Re-uploaded the SQLiuteTestDB.zip, this time with the SQLite database included. When testing you'll need to adjust the database path in RDCConnector.Initialize to suit where you put the DB.
You'll also need to adjust the '#AdditionalJar: sqlite-jdbc-3.46.0.0' if you're using a different version.
 

Attachments

  • jRDCSQlite.zip
    10.1 KB · Views: 12
  • BasicJRDC2ClientTest.zip
    4.6 KB · Views: 14
  • SQLiteTestDB.zip
    449 bytes · Views: 4
Last edited:
Top