0

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://david_maffitt@bitbucket.org/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.

Maffitt
  • 13
  • 5
  • `@Param` is CDI annotation and although spring recognizes `@Named` and `@Inject` it is **not** it is not a CDI container but still Spring. Switching from Spring to real cdi most likely solves the problem – Kukeltje Dec 15 '18 at 18:37
  • 1
    You are using joinfaces, it means base is spring boot, but also you are using CDI as DI. It is anti pattern I think, prefer to use Spring DI.. – Armen Arzumanyan Dec 16 '18 at 21:06

3 Answers3

-1

You should do change in bean.xml set bean-discovery-mode="all"> https://github.com/armdev/reactive-javaserver-faces/blob/master/reactive-jsf/src/main/webapp/WEB-INF/beans.xml

Armen Arzumanyan
  • 1,939
  • 3
  • 30
  • 56
  • Although OP states CDI is used for injection, OP is not using CDI for injection but Spring (see the error). So it has nothing to do with the discovery of beans or not. And a `@Param` annotatuon is not about a real bean even... – Kukeltje Dec 16 '18 at 20:00
-1

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.

Armen Arzumanyan
  • 1,939
  • 3
  • 30
  • 56
  • Wrong again, current versions of Spring threat the cdi annotations identical to its own ones. And changing them still won't make spring understand `@Param`. Only way to make this work is to not use spring for DI but real cdi or use a 'similar' annotation instead that is pure spring (which I do not know since I don't use spring – Kukeltje Dec 16 '18 at 21:52
  • Disagree , Spring DI is different than CDI. For merging together , project must be reconfigured as my prevoius answer, but it is anti pattern and it is adding fail layer. I saw lot of projects, where CDI and Spring used together, it was projects which you can not upgrade and support. We should understand what CDI and Spring behavior changes with every new version. – Armen Arzumanyan Dec 17 '18 at 10:50
  • Also JSF by itself does not need merge with Spring. – Armen Arzumanyan Dec 17 '18 at 10:53
  • No, wrong again.. I'm not talking about 'merging'. OP uses Spring for DI and added the CDI API to get the spring to recognize the `@Inject` and `@Named`, as annotations see https://stackoverflow.com/questions/7142622 **that** is what OP is doing. That works but you cannot user other real CDI annotations like the OmniFaces `@Param` So the expectation of the OP is wrong. Switching to Spring annotations does not make the @Param from Omnifaces work. So OP needs a spring replacement for that too – Kukeltje Dec 17 '18 at 11:18
-1

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...

Kukeltje
  • 12,223
  • 4
  • 24
  • 47