Unsatisfied dependency when using OmniFaces @Param annotation. No qualifying bean of type java.lang.String

490 Views Asked by At

I am attempting to use CDI over the deprecated ManagedBean/ManagedProperty annotations and run into this exception in a very simple web app:

Error creating bean with name 'navigationController': Unsatisfied dependency expressed through field 'message'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.inject.Inject(), @org.omnifaces.cdi.Param(validatorAttributes=[], validatorMessage=, validators=[], converter=, pathIndex=-1, converterAttributes=[], converterClass=interface javax.faces.convert.Converter, label=, overrideGlobalBeanValidationDisabled=false, required=false, disableBeanValidation=false, name=, validatorClasses=[], converterMessage=, requiredMessage=)}

I am attempting to follow the example of @Param in the OmniFaces showcase at http://showcase.omnifaces.org/cdi/Param.

I PUT to a page with http://localhost:8080/jsfSpringBootApp/nav.xhtml?message=My+message+from+MessageSource. It is my understanding that the NavigationController bean should be created on navigation to nav.xhtml and that the message field will be populated with the value taken from the request parameter.

IntellliJ also complains about the @Param annotation:

Cannot find bean qualified with @Param

Thank you for any help. I am stuck at what to try next.

The entire project is at https://[email protected]/david_maffitt/jsfspringbootapp.git.

The contents of nav.xhtml are

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:p="http://primefaces.org/ui">

<h:body >
<f:view>

    <p:panel id="myPanelId" header="My Panel" style="margin-bottom:20px">
        <h:outputText value="My text output." />
        <h:outputText value="My text output from params: #{navigationController.action}" />
    </p:panel>

</f:view>
</h:body>
</html>

The contents of NavigationController.java are package org.nrg.cap.jsfWebApp;

import org.omnifaces.cdi.Param;

import javax.enterprise.context.RequestScoped;
import javax.faces.annotation.ManagedProperty;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.Serializable;

//@Component
//@Scope("request")
@Named
@RequestScoped
public class NavigationController implements Serializable {

    @Inject @Param
    private String message;


    public String showPage() {
        return ("fubar".equals(message))? "fubar": "snafu";
    }

    public void setAction(String message) {
        this.message = message;
    }
    public String getAction() {
        return message;
    }
}

The pom.xml is

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.nrg.cap</groupId>
    <artifactId>jsfSpringBootApp</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JSF Spring Boot WebApp</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>

        <joinfaces.version>4.0.0</joinfaces.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.joinfaces</groupId>
                <artifactId>joinfaces-dependencies</artifactId>
                <version>${joinfaces.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.joinfaces</groupId>
            <artifactId>primefaces-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.joinfaces</groupId>
            <artifactId>omnifaces3-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <version>2.0.SP1</version>
        </dependency>
    </dependencies>

</project>

I found that I had to add the dependency for cdi-api because I am deploying to tomcat 9.0.13 which doesn't have cdi baked in. The pom is derived from the joinfaces project.

3

There are 3 best solutions below

1
On
4
On

I look deeper: project based on Joinfaces, it means base of project is a Spring boot. So , after used CDI for DI. Change CDI annotations to Spring DI - @Inject to @Autowired. Joining two different DI principles is not good idea.

0
On

The OmniFaces @Param annotation is a CDI (implementation) based annotation. And although Spring can use @Named and @Inject as replacement for @Component and @Autowired like mentioned in What is the difference between @Inject and @Autowired in Spring Framework? Which one to use under what condition?, (for which you indeed need to add a 'CDI'api) it still does not make Spring a real CDI DI container.

This means that @Param won't be used/interpreted by Spring as it was intended by OmniFaces/CDI and Spring tries to find a real bean with the @Param annotation which ofcourse is not existing. You consequently get te error you get.

What the best solution is, is beyond the scope of this question since it is 'primarily opinion based' but basically they boil down to two options.

I won't state the first has my preference here... Hmmm just did...