Неудовлетворенная зависимость при использовании аннотации OmniFaces @Param. Нет подходящего компонента типа java.lang.String
Я пытаюсь использовать CDI над устаревшими аннотациями ManagedBean/ManagedProperty и сталкиваюсь с этим исключением в очень простом веб-приложении:
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=)}
Я пытаюсь последовать примеру @Param в витрине OmniFaces по адресу http://showcase.omnifaces.org/cdi/Param.
Я помещаю на страницу http://localhost:8080/jsfSpringBootApp/nav.xhtml?message=My+message+from+MessageSource. Насколько я понимаю, bean-компонент NavigationController должен быть создан при переходе к nav.xhtml и что поле сообщения будет заполнено значением, взятым из параметра запроса.
IntellliJ также жалуется на аннотацию @Param:
Не удается найти компонент, отвечающий требованиям @Param
Спасибо за любую помощь. Я застрял в том, что попробовать дальше.
Весь проект находится по адресу https://david_maffitt@bitbucket.org/david_maffitt/jsfspringbootapp.git.
Содержимое nav.xhtml
<?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>
Содержимое NavigationController.java является пакетом 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;
}
}
Pom.xml является
<?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>
Я обнаружил, что мне пришлось добавить зависимость для cdi-api, потому что я развертываю на tomcat 9.0.13, в котором не запечен cdi. Pom получен из проекта joinfaces.
3 ответа
Я смотрю глубже: проект основан на Joinfaces, это означает, что основой проекта является загрузка Spring. Итак, после использовали CDI для DI. Измените аннотации CDI на Spring DI - @Inject на @Autowired. Объединение двух разных принципов DI не очень хорошая идея.
Вы должны сделать изменения в наборе bean.xml bean-discovery-mode="all">
https://github.com/armdev/reactive-javaserver-faces/blob/master/reactive-jsf/src/main/webapp/WEB-INF/beans.xml
OmniFaces @Param
аннотация - это аннотация, основанная на CDI (реализация). И хотя весна может использовать @Named
а также @Inject
в качестве замены @Component
а также @Autowired
как упомянуто в чем разница между @Inject и @Autowired в Spring Framework? Какой использовать при каких условиях?, (для которого вам действительно нужно добавить 'CDI'api), он все еще не делает Spring настоящим контейнером CDI DI.
Это означает, что @Param
не будет использоваться / интерпретироваться Spring, как это было задумано OmniFaces/CDI, и Spring пытается найти настоящий бин с помощью @Param
аннотация, конечно, не существует. Следовательно, вы получаете ошибку, которую получаете.
То, что является лучшим решением, выходит за рамки этого вопроса, поскольку оно "главным образом основано на мнении", но в основном они сводятся к двум вариантам.
- Отбросьте Spring (загрузку) для DI, поскольку JSF 2.4 потребует CDI и встроенный пользователем Tomcat (или java-ee) другим способом, как описано в https://www.c2b2.co.uk/middleware-blog/how-to-create-microservices-with-tomcat.php (использование микросервисов не требуется!)
- Полностью используйте spring, переключитесь на Spring MVC и отбросьте JSF и Omnifaces
Я не буду утверждать, что первое имеет мое предпочтение здесь... Хммм только что сделал...