java.lang.IllegalArgumentException: o:graphicImage 'value' attribute must refer a #GraphicImageBean or #ApplicationScoped bean - jsf

Using the example of 'o:graphicImage': "The below one renders byte[] property taking a Long argument as resource in <ui:repeat> loop": https://showcase.omnifaces.org/components/graphicImage
Adding Omnifaces:
implementation("org.omnifaces:omnifaces:4.0.1")
Deployed only in WAR:
WEB-INF/lib/omnifaces-4.0.1.jar
XHTML:
<ui:repeat value="#{graphicImagesController.ids}" var="id">
<o:graphicImage value="#{graphicImagesController.getContent(id)}" lastModified="#{startup.time}"/>
</ui:repeat>
Java:
#Named("graphicImagesController")
#GraphicImageBean
public class GraphicImagesController {
private static final Logger LOGGER = LoggerFactory.getLogger(GraphicImagesController.class);
private static final Map<Long, String> IMAGES = Collections.unmodifiableMap(new TreeMap<Long, String>() {
private static final long serialVersionUID = 1L;
{
put(1L, "3862a9b4c41cacd3465d0edb80c2072d");
}
});
public byte[] getContent(Long id) throws IOException {
return Utils.toByteArray(Faces.getResourceAsStream("/Users/NOTiFY/IdeaProjects/NOTiFYmoto/images/moto/Laverda/1977/1000/Jota/" + IMAGES.get(id) + ".jpg"));
}
public Long[] getIds() {
LOGGER.info(">>>>> GraphicImagesController getIds IMAGES = {}", IMAGES);
LOGGER.info(">>>>> GraphicImagesController getIds IMAGES size = {}", IMAGES.size());
return IMAGES.keySet().toArray(new Long[IMAGES.size()]);
}
}
Terminal 'INFO':
INFO [com.notifymoto.controller.GraphicImagesController] (default task-1) >>>>> GraphicImagesController getIds IMAGES = {1=3862a9b4c41cacd3465d0edb80c2072d}
INFO [com.notifymoto.controller.GraphicImagesController] (default task-1) >>>>> GraphicImagesController getIds IMAGES size = 1
Terminal 'SEVERE': " o:graphicImage 'value' attribute must refer a #GraphicImageBean or #ApplicationScoped bean. Cannot find the right annotation on bean class"
SEVERE [jakarta.enterprise.resource.webcontainer.faces.application] (default task-1) Error Rendering View[/index.xhtml]: java.lang.IllegalArgumentException: o:graphicImage 'value' attribute must refer a #GraphicImageBean or #ApplicationScoped bean. Cannot find the right annotation on bean class 'class com.notifymoto.controller.GraphicImagesController'.
Powered by:
Mojarra 4.0.0.SP01
OmniFaces 4.0.1
PrimeFaces 12.0.3
WildFly Preview 27.0.1.Final
Jakarta EE 10.0.0
EAR = JAR + WAR (Gradle)
(2)
#BalusC Your comment "the JAR part of your EAR should be declaring OmniFaces as a provided dependency instead of as a runtime dependency". I can't understand the 'dependency' reference.
Looked at your 'stack overflow' response on "How to correctly use OmniFaces in an EAR":
How to correctly use OmniFaces in an EAR
I have:
libs/NOTiFYmoto.ear:
lib/
lib/gson-2.10.jar
lib/httpclient-4.5.13.jar
lib/httpcore-4.4.14.jar
lib/kotlin-stdlib-1.8.10.jar
lib/morphia-core-2.3.0.jar
lib/mongodb-driver-core-4.8.2.jar
lib/mongodb-driver-sync-4.8.2.jar
lib/bson-4.8.2.jar
lib/byte-buddy-1.12.17.jar
lib/classgraph-4.8.153.jar
NOTiFYmotoWAR.war
NOTiFYmotoJAR.jar
META-INF/application.xml
libs/NOTiFYmotoJAR.jar:
META-INF/
META-INF/MANIFEST.MF
META-INF/beans.xml
META-INF/persistence.xml
... .class
com/notifymoto/controller/GraphicImagesController.class
com/notifymoto/controller/GraphicImagesController$1.class
libs/NOTiFYmotoWAR.war:
META-INF/
META-INF/MANIFEST.MF
WEB-INF/
WEB-INF/lib/
... .jar
WEB-INF/lib/omnifaces-4.0.1.jar
Always with:
<o:graphicImage value="#{graphicImagesController.getContent(id)}" lastModified="#{startup.time}" />
Error:
SEVERE [jakarta.enterprise.resource.webcontainer.faces.application] (default task-1) Error Rendering View[/index.xhtml]: java.lang.IllegalArgumentException: o:graphicImage 'value' attribute must refer a #GraphicImageBean or #ApplicationScoped bean. Cannot find the right annotation on bean class 'class com.notifymoto.controller.GraphicImagesController'.

Your project structure is wrong.
Web tier dependencies need to go in /WEB-INF/lib of the WAR.
You have 2 options:
Move NOTiFYmotoJAR.jar into /WEB-INF/lib of the WAR.
Or, split all classes which have dependencies on JARs in /WEB-INF/lib (such as OmniFaces) from NOTiFYmotoJAR.jar into a new JAR and then put that new JAR into /WEB-INF/lib of the WAR. If there's actually nothing left in NOTiFYmotoJAR.jar after the split, then you probably don't need an EAR structure at all.

Related

Is it possible to inject a bean to phaselistener when using JSF 2.3, tomcat with weld cdi implementation?

I want to inject a #SessionScoped and a #RequestScoped beans into my PhaseListener implementation, but I got NullPointerException.
I use tomcat with weld implementation to achieve CDI. I started to migrate JSF 2.2 to 2.3, so I changed to CDI from FacesContext.
Well I replaced #ManagedBean to #Named and any other things to must do during migration like:
- add beans XML to every modules
- add BeanManager to context XML
- delete bean declarations from faces-config.xml
- add SPI BeanManager as resource-env-ref to web.xml
How can I inject any bean to PhaseListener implementations?
#Named
#SessionScoped
public class MyHandler implements Serializable {
..}
#Named
#RequestScoped
public class MyController extends MyParentController<Example> {
..}
public class MyPhaseListener implements PhaseListener {
private MyHandler myHandler;
private MyController myController;
#Inject
public void setMyHandler(MyHandler myHandler) {
this.myHandler= myHandler;
}
#Inject
public void setMyController (MyController myController) {
this.myController= myController;
}
...
public void afterPhase(PhaseEvent event) {
myHandler.method()
}
myHandler injected bean is null in afterPhase method.
I put CDI configuration file beans.xml into folder META-INF instead of WEB-INF
In beans.xml I had to change bean-discovery-mode from "annotated" to "all".
I forgot to add a class with #FacesConfig(version = Version.JSF_2_3) annotation( to enable EL resolution for CDI beans).
Also forgot to change faces-config.xml version to 2.3
Fortunately I solved the problem... A few things I had to do:
I put beans.xml into META-INF/, but beans.xml has to be under
WEB-INF.
In beans.xml I had to change bean-discovery-mode from "annotated" to
"all".
I forgot to add a class with #FacesConfig(version = Version.JSF_2_3)
annotation( to enable EL resolution for CDI beans).
Also forgot to change faces-config.xml version to 2.3.

Weld CDI: Producers in superclasses of alternatives are effective despite cdi-spec

Given
public class BeanContainer {
#Produces
Bean bean = new Bean();
}
and its alternative:
#Alternative
public class BeanContainerAlt extends BeanContainer {
#Produces
int producerInt = 10;
}
where Bean is
public class Bean {
boolean didPostConstruct = false;
#PostConstruct
public void postConstruct() {
didPostConstruct = true;
}
}
injected into MainClass:
public class MainClass {
#Inject
Bean bean;
#Inject
Integer producedInt;
}
Then:
Weld weld = new Weld()
.disableDiscovery()
.addBeanClass(MainClass.class)
.addBeanClass(BeanContainer.class)
.addBeanClass(BeanContainerAlt.class)
.alternatives(BeanContainerAlt.class);
WeldContainer container = weld.initialize();
final MainClass mainClass = container.select(MainClass.class).get();
assertFalse(mainClass.bean.didPostConstruct);
assertEquals(10, (long)mainClass.producedInt);
BeanContainer containerObject = container.select(BeanContainer.class).get();
assertEquals(BeanContainerAlt.class, containerObject.getClass());
gives no error. I would have expected that Bean.class would have to be added using addBeanClass to be able to satisfy the inject in MainClass. The explanation is that the Superclass of BeanContainerAlt whose Producers should imO not be effective, produces the Bean-Object.
Is that behavior intended or even according to the spec (I did not find it), is it probably defined in the weld-documentation?
The sourcecode can be found in
examplesrc
mvn clean install -Dtest=ReproProducersInSuperclasses
in that project should make it run
Indeed, the fields and methods annotated with #Producer are not inherited - as discussed in the accepted answer to Why are Producers not inherited in CDI
However, according to the CDI specification:
5.1.2. Enabled and disabled beans
A bean is said to be enabled if:
(E1) it is deployed in a bean archive, and
(E2) it is not a producer method or field of a disabled bean, and
(E3) it is not specialized by any other enabled bean, as defined in Specialization, and either
(E4) it is not an alternative, or it is a selected alternative of at least one bean archive or the application.
Otherwise, the bean is said to be disabled.
According to these definitions and code above:
BeanContainer is not an alternative (E4) and therefore is enabled managed bean
BeanContainerAlt is a selected alternative (E4) and therefore is enabled managed bean
Bean and int are enabled because they are not a producer method or field of a disabled bean (E2), as BeanContainer and BeanContainerAlt are both enabled (E4)
Therefore producer fields in both BeanContainer and BeanContainerAlt are used to resolve dependencies.
The test fails as shown below when BeanContainer is not deployed (E1):
WELD-001408: Unsatisfied dependencies for type Bean with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject
net.oneandone.iocunit.testalt.MainClass.bean
The test fails as shown below when BeanContainerAlt is not selected (E4):
WELD-001408: Unsatisfied dependencies for type Integer with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject
net.oneandone.iocunit.testalt.MainClass.producedInt

Producer is discover by Weld in Arquillian process

While running a unit test with Arquillian using Glassfish embedded plugin, I get the following CDI error :
2015-09-18 06:25:24,376 DEBUG | main | org.jboss.weld.Reflection | WELD-000620: interface com.SupportedLocales is not declared #Target(METHOD, FIELD, PARAMETER, TYPE). Weld will use this annotation, however this may make the application unportable.
sept. 18, 2015 6:25:24 AM com.sun.enterprise.v3.server.ApplicationLifecycle deploy
GRAVE: Exception during lifecycle processing
org.glassfish.deployment.common.DeploymentException: CDI deployment failure:WELD-001408: Unsatisfied dependencies for type Set<Locale> with qualifiers #SupportedLocales
at injection point [BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] #Inject protected com.MyClass(#SupportedLocales Set<Locale>)
at com.MyClass.<init>(MyClass.java:0)
Set(Locale) with qualifier #SupportedLocales is defined in a module deployed in the tested WebArchive. The Archive content is :
/WEB-INF/
/WEB-INF/lib/
/WEB-INF/lib/commons-lang3-3.3.2.jar
/WEB-INF/lib/commons-configuration-1.10.jar
/WEB-INF/lib/reflections-0.9.9-RC2.jar
/WEB-INF/lib/jcl-over-slf4j-1.7.10.jar
/WEB-INF/lib/slf4j-api-1.7.10.jar
/WEB-INF/lib/deltaspike-core-api-1.5.0.jar
/WEB-INF/lib/commons-util-1.0.0-SNAPSHOT.jar
/WEB-INF/lib/commons-io-2.4.jar
/WEB-INF/lib/guava-16.0.1.jar
/WEB-INF/lib/log4j-over-slf4j-1.7.10.jar
/WEB-INF/lib/javassist-3.18.2-GA.jar
/WEB-INF/lib/logback-classic-1.1.2.jar
/WEB-INF/lib/logback-core-1.1.2.jar
/WEB-INF/lib/jul-to-slf4j-1.7.10.jar
/WEB-INF/lib/commons-cdi-1.0.0-SNAPSHOT.jar
/WEB-INF/lib/xml-apis-1.0.b2.jar
/WEB-INF/lib/deltaspike-core-impl-1.5.0.jar
/WEB-INF/lib/dom4j-1.6.1.jar
/WEB-INF/lib/commons-codec-1.9.jar
/WEB-INF/lib/commons-lang-2.6.jar
/WEB-INF/lib/annotations-2.0.1.jar
/WEB-INF/lib/libphonenumber-7.0.3.jar
/WEB-INF/classes/
/WEB-INF/classes/com/
/WEB-INF/classes/com/timm/
/WEB-INF/classes/com/timm/common/
/WEB-INF/classes/com/timm/common/cdi/
/WEB-INF/classes/com/timm/common/cdi/web/
/WEB-INF/classes/com/timm/common/cdi/web/i18n/
/WEB-INF/classes/com/timm/common/cdi/web/i18n/ShiroCurrentLocale.class
/WEB-INF/beans.xml
This object is provided by a producer method located in "common-cdi" module. The same module provide CDI extension feature like ThreadScoped. This producer is not discovered by Weld during test startup and Weld does not discover beans from "commons-cdi" module. How is it possible? Can we provide CDI extension features and CDI bean in the same module ?
#SupportedLocales is declares in "commons-cdi" with:
#Qualifier
#Target({
ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD
})
#Retention(RetentionPolicy.RUNTIME)
public #interface SupportedLocales {
}
The producer is declared in "commons-cdi" with:
#Dependent
public class I18NProducer {
#Produces
#ApplicationScoped
#Default
#SupportedLocales
public Set<Locale> getSupportedLocales() {
Set<Locale> supportedLocales;
supportedLocales = new HashSet<Locale>();
supportedLocales.add(Locale.US);
return supportedLocales;
}
}
JUnit test case definition:
#RunWith(Arquillian.class)
public class LocaleInjectionTest {
#Deployment
public static Archive<?> deploy() {
final String moduleName = LocaleInjectionTest.class.getSimpleName();
PomEquippedResolveStage resolver = Maven.resolver().loadPomFromFile("pom.xml");
File[] libs = resolver.resolve("com.myname:commons-cdi").withTransitivity().asFile();
WebArchive testWar = ShrinkWrap
.create(WebArchive.class, moduleName + ".war")
.addClass(MyCurrentLocale.class)
.addAsLibraries(libs)
.addAsWebInfResource(ArchiveUtils.getResourceBeanXMLWithAlternativeAndDiscoveryModeAnnotated(MyCurrentLocale.class),
"beans.xml");
return testWar;
}
#Inject
private CurrentLocale bean;
#Test
public void testInjection() throws Exception {
...
}
}
MyCurrentLocale class definition:
#SessionScoped
#Alternative
public class MyCurrentLocale extends DefaultCurrentLocale implements Serializable {
#Inject
protected MyCurrentLocale(#SupportedLocales Set<Locale> supportedLocales) {
super(supportedLocales);
}
...
}
Is there something wrong in declaration ?
Looks like you're using GlassFish v3, so you'll need the beans.xml file in the jar as well as it is a bean archive too.

Deltaspike Data module: no bean matches the injection point

I am trying DeltaSpike Data Module on Wildfly i followed the things mentioned in the document, when I try to run a Servlet having a Repository i am getting a NullPointerException while using the repository
#Inject
private OrdersRepository orderRep;
List<OrderDto> dao = orderRep.findByRetailer("MyRetail"); // NullPointer
Code
#Repository(forEntity = Order.class)
#MappingConfig(OrderMapper.class)
#EntityManagerConfig(entityManagerResolver = MyDBResolver.class)
public abstract class OrdersRepository extends AbstractEntityRepository<OrderDto, String> {
#Query(named = Order.ORDER_BY_RETAILER, max = 1)
public abstract List<OrderDto> findByRetailer(String retailer);
}
...
Am I missing anything here ?
Try adding #Dependent to your repository classes.
CDI 1.1 used in WildFly has implicit bean archives by default, i.e. candidate bean classes require a bean defining annotation.

How to inject a CDI Bean in a ManagedBean?

I want to inject a CDI Bean in a ManagedBean either with the annotation #Inject or #Produce. The CDI Bean which I use is:
#Named
#Startup
#ApplicationScoped
public class BaseBean {
private List<String> custs;
public List<String> getCusts() {
return custs;
}
public void setCusts(List<String> emps) {
this.custs = emps;
}
public BaseBean(){
}
#PostConstruct
void init() {
custs = new ArrayList<String>();
custs.add("Cust1");
custs.add("Cust3");
custs.add("Cust2");
custs.add("Cust4");
}
}
The ManagedBean, in which I want to inject the CDI Bean is:
#SessionScoped
#ManagedBean
public class Hello implements Serializable {
#Inject
private BaseBean dBean;
private static final long serialVersionUID = 1L;
private List<String> customers;
private List<String> customersSelect;
public Hello() {
}
#PostConstruct
void init() {
// dBean = new BaseBean();
customers = dBean.getCusts();
}
public List<String> getCustomers() {
return customers;
}
public List<String> getCustomersSelect() {
return customersSelect;
}
public void setCustomersSelect(List<String> customersSelect) {
this.customersSelect = customersSelect;
}
}
In the init function however, it throws NullPointerException. If I use the annotation #Produces instead of #Inject, the result is the same: NullPointerException. Is anything wrong with the CDI Bean (improper annotations)? Do I try to inject it with a wrong way? Does my code lack of something? How can I get it work? Here is the JSF code:
<h:form id ="f">
<h:selectManyCheckbox layout="pageDirection" border="1" value="#{hello.customersSelect}">
<f:selectItems value="#{hello.customers}"></f:selectItems>
</h:selectManyCheckbox><br />
<h:commandButton action="response.xhtml" value="Click me" />
</h:form>
PS: If I use a Stateless Bean as BaseBean and I inject it with the annotation #EJB, it works with no problem.
UPDATE: I have tried it with the annotations #SessionScoped (javax.enterprise.context.SessionScoped) and #Named on the Hello class. Although I do not receive a NullPointerException, the h:selectManyCheckbox is empty. moreover, it strikes me, that when I add the beans.xml file under META-INF folder, I receive a StartException, although the file is there supposed to be. I think my application lacks the proper configuration to be capable of Dependency Injection. What is likely to need additional configuration?
UPDATE 2: This error appears when I add the beans.xml file in the WEB-INF folder. The beans.xml file is empty, it contains only the line :
<?xml version="1.0" encoding="UTF-8"?>
The error is:
Services which failed to start: service jboss.deployment.unit."JSF1.war".PARSE: org.jboss.msc.service.StartException in service jboss.deployment.unit."JSF1.war".PARSE: Failed to process phase PARSE of deployment "JSF1.war"
12:51:11,482 ERROR [org.jboss.as.server.deployment.scanner] (DeploymentScanner-threads - 1) {"JBAS014653: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"JBAS014671: Failed services" => {"jboss.deployment.unit.\"JSF1.war\".PARSE" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"JSF1.war\".PARSE: Failed to process phase PARSE of deployment \"JSF1.war\""}}}}
What #patlov is suggesting will work if you use #Named on your CDI beans. However, if you're working in an environment that supports CDI, do not use #ManagedBean. Instead, use CDI all the way. See this answer and I'm sure you could find numerous other ones that strongly advise against what you're trying to do.
Just switch from javax.faces.bean.SessionScoped to javax.enterprise.context.SessionScoped and everything will magically work. What you may run into is the absense of #ViewScoped from CDI however, in which case use something like JBoss Seam or Apache Deltaspike that implement it for you. As an added benefit, they will also automatically replace all of the JSF scopes with CDI scopes automatically if you already have existing code written for JSF.
Update:
This should be the content of your beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>
Make sure you have enabled CDI by putting a WEB-INF/beans.xml file in your application.
If you are using #ManagedBean use #ManagedProperty to inject properties:
#ManagedProperty(value = "#{baseBean}")
private BaseBean dBean;
// getter and setter

Resources