Friday, August 29, 2025

Smallest Working Quarkus 3 Application with Faces 4, OmniFaces 4, and CDI 4

For reference, here is the minimal Maven project structure for a Quarkus 3 application using Faces 4, OmniFaces 4, and CDI 4.

This is an alternative to the Smallest Working Quarkus 3 Application with Faces 4, OmniFaces 4, and CDI 4.

pom.xml

Below is the minimal Maven configuration, including the quarkus-maven-plugin setup required to produce a JAR:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"
>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>quarkus3-omnifaces4</artifactId>
    <version>1.0.0</version>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.quarkus</groupId>
                <artifactId>quarkus-bom</artifactId>
                <version>3.26.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.apache.myfaces.core.extensions.quarkus</groupId>
            <artifactId>myfaces-quarkus</artifactId>
            <version>4.1.1</version>
        </dependency>
        <dependency>
            <groupId>io.quarkiverse.omnifaces</groupId>
            <artifactId>quarkus-omnifaces</artifactId>
            <version>4.6.5</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>io.quarkus</groupId>
                <artifactId>quarkus-maven-plugin</artifactId>
                <version>3.26.0</version>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Currently, only MyFaces provides a Quarkus-compatible Faces 4.x implementation. Mojarra still has issue 5442 open on this. OmniFaces 4.x can be used via the Quarkus OmniFaces extension. CDI 4.x is already natively supported by Quarkus.

src/main/java/com/example/backing/ExampleBacking.java

The CDI managed bean representing a Jakarta Faces backing bean utilizing OmniFaces powerful @ViewScoped annotation with its memory-saving unload feature:

package com.example.backing;

import java.io.Serializable;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.inject.Inject;
import jakarta.inject.Named;

import org.omnifaces.cdi.ViewScoped;

import com.example.service.ExampleService;

@Named
@ViewScoped
public class ExampleBacking implements Serializable {

    private static final long serialVersionUID = 1L;

    private String input;
    private String output;

    @Inject
    private ExampleService service;

    public void submit() {
        output = service.process(input);
    }

    public String getInput() {
        return input;
    }

    public void setInput(String input) {
        this.input = input;
    }

    public String getOutput() {
        return output;
    }
}

src/main/java/com/example/service/ExampleService.java

The CDI service:

package com.example.service;

import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class ExampleService {

    public String process(String input) {
        return "Hello! You have typed: " + input;
    }
}

src/main/resources/META-INF/resources/index.xhtml

The Facelet file with a basic Jakarta Faces form:

<!DOCTYPE html>
<html lang="en"
    xmlns:f="jakarta.faces.core"
    xmlns:h="jakarta.faces.html"
>
    <h:head>
        <title>Hello!</title>
    </h:head>
    <h:body>
        <h1>Hello!</h1>
        <h:form>
            <h:outputLabel for="input" value="Type something: " />
            <h:inputText id="input" value="#{exampleBacking.input}" />
            <h:commandButton value="Submit" action="#{exampleBacking.submit}">
                <f:ajax execute="@form" render=":output" />
            </h:commandButton>
        </h:form>
        <h:outputText id="output" value="#{exampleBacking.output}" />
    </h:body>
</html>

Note that web resources, such as Facelets files, must to be placed in the src/main/resources/META-INF/resources folder as if it were a web fragment JAR project rather than src/main/webapp as in a WAR project!

Unlike the Spring Boot 3 approach, you don't need a configuration class like ExampleApplication or a beans.xml file.

Build and run it!

First cd into the folder where the pom.xml is located.

Now create the Thin JAR:

mvn clean package

Then execute the Thin JAR:

java -jar target/quarkus-app/quarkus-run.jar

Finally launch your default web browser on http://localhost:8080/index.xhtml:

browse http://localhost:8080/index.xhtml

How about a Fat JAR?

In Quarkiverse, this is called an Uber JAR. You need to provide an additional build argument:

mvn clean package -Dquarkus.package.jar.type=uber-jar

Then execute the Uber JAR:

java -jar target/quarkus3-omnifaces4-1.0.0-SNAPSHOT-runner.jar

You can add a property to the pom.xml to make this the default behavior when running the mvn clean package command.

<properties>
    <quarkus.package.jar.type>uber-jar</quarkus.package.jar.type>
</properties>