CDI cross BDA bean injection in Wildfly 8.1 - cdi

I have an EAR file with the following structure:
lib
jar.jar
Test1
Test2
ejb.jar
Test1Impl
war.war
Test2Impl
TestServlet
The jar.jar contains two interfaces
Test1
Test2
The TestServlet injects Test1 which resolves to Test1Impl only if I have a manifest Class-Path entry in war.war to ejb.jar.
Test1Impl injects Test2 which resolves to Test2Impl only if I have a manifest Class-Path entry in ejb.jar to war.war.
The tip entry Matching the classloader structure for the deployment of the Weld documentation explains why I need the manifest entries.
How is this cross BDA injection supposed to work normally? Adding Class-Path manifest entries seems a bit stupid because actually I don't want the implementations to be visible. I only want that the beans from other subdeployments to be visible. Is there any way to do that?
Here the implementations
public class Test1Impl implements Test1 {
#Inject
private Test2 test2;
public void hello() {
System.out.println(test2.getString());
}
}
public class Test2Impl implements Test2 {
public String getString() {
return "Hello";
}
}
#WebServlet(urlPatterns = "/test")
public class TestServlet implements Servlet {
#Inject
private Test1 test;
public void init(ServletConfig config) throws ServletException {
}
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
test.hello();
}
public String getServletInfo() {
return null;
}
public void destroy() {
}
}
And here the application.xml
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/application_7.xsd"
version="7">
<description>The EAR</description>
<display-name>ear</display-name>
<module>
<ejb>ejb.jar</ejb>
</module>
<module>
<web>
<web-uri>war.war</web-uri>
<context-root>/</context-root>
</web>
</module>
<library-directory>lib</library-directory>
</application>

As described in the CDI reference in the section Using CDI Beans from outside the deployment a jboss-deployment-structure.xml with the appropriate dependencies is required.
Although doing this fixed my problems, I think that the CDI spec should define a portable way for doing this for enterprise applications.

Related

ApplicationScoped bean not injected in JSF 2.3 FacesConverter

I have following FacesConverter:
#FacesConverter(forClass = Onderwerp.class, managed = true)
public class OnderwerpConverter implements Converter<Onderwerp> {
#Inject
private Web web;
#Override
public Onderwerp getAsObject(FacesContext context, UIComponent component, String value) {
log.trace("Converting to object from string: " + value);
return web.getAllActiveOnderwerpen().stream().filter(o -> o.getId().equals(Long.parseLong(value))).findFirst().get();
}
#Override
public String getAsString(FacesContext context, UIComponent component, Onderwerp onderwerp) {
log.trace("Converting to string from object: " + onderwerp);
return onderwerp.getId().toString();
}
}
The referenced CDI bean is:
#Named
#ApplicationScoped
public class Web { ... }
Faces-config.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd" version="2.3">
Now whatever kind of bean I inject via #Inject it is always null. It seems the injection feature in 2.3 is not working (yet), or I am missing something :)
I'm using Mojarra 2.3.0 on EAP 7.0. Also tested without success using 2.3.3 on EAP 7.0 and 7.1.
My current workaround is replacing the code where I need the injected CDI bean like this:
return CDI.current().select(Web.class).get().getAllActiveOnderwerpen().stream().filter(o -> o.getId().equals(Long.parseLong(value))).findFirst().get();
This works fine, but is kinda ugly of course :)
Anyone has experienced this behavior?
I had the same issue and I foud the solution.
You must create a config bean indicating JSF version:
import javax.faces.annotation.FacesConfig;
import javax.faces.annotation.FacesConfig.Version;
#FacesConfig(
// Activates CDI build-in beans
version=Version.JSF_2_3
)
public class ConfigBean {
}

WildFly does not run my LiquibaseProcucer CDI

I'm trying to run my LiquibaseProducer in WildFly 9.0.2. This is my Producer class:
package nl.itris.mjop.database;
import liquibase.integration.cdi.*;
import liquibase.integration.cdi.annotations.*;
import liquibase.resource.*;
import **********
#Singleton
#Startup
#Dependent
public class LiquibaseProcducer {
#Resource(lookup="java:jboss/datasources/PostgresDS")
private static DataSource myDataSource;
#Produces #LiquibaseType
public CDILiquibaseConfig createConfig() {
System.out.println("============= liquibase createConfig entry =============");
CDILiquibaseConfig config = new CDILiquibaseConfig();
config.setChangeLog("liquibase/parser/core/xml/simpleChangeLog.xml");
System.out.println("============= liquibase createConfig exit =============");
return config;
}
#Produces #LiquibaseType
public DataSource createDataSource() throws SQLException {
System.out.println("============= liquibase createDataSource entry =============");
return getDataSource();
}
#Produces #LiquibaseType
public ResourceAccessor create() {
System.out.println("============= liquibase create entry =============");
return new ClassLoaderResourceAccessor(getClass().getClassLoader());
}
public static DataSource getDataSource() {
if (myDataSource == null) {
/* Workaround for failing #Resource(lookup="java:jboss/datasources/PostgresDS") */
try {
System.out.println("============= liquibase datasource lookup via initial context workaround =============");
InitialContext ctx = new InitialContext();
myDataSource = (DataSource) ctx.lookup("java:jboss/datasources/PostgresDS");
} catch(NamingException ne) {
ne.printStackTrace();
}
}
return myDataSource;
}
}
When I (re) deploy my WAR file in WildFly, this producer is not doing anything! I do not see any error messages in my log files, I do not see any system.out messages that I put in the producer methods.
The producer class seems to be loaded and recognized by WildFly hence this log fragment:
2016-11-30 10:58:53,662 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-7) JNDI bindings for session bean named LiquibaseProcducer in deployment unit deployment "mjop-elements.war" are as follows:
java:global/mjop-elements/LiquibaseProcducer!nl.itris.mjop.database.LiquibaseProcducer
java:app/mjop-elements/LiquibaseProcducer!nl.itris.mjop.database.LiquibaseProcducer
java:module/LiquibaseProcducer!nl.itris.mjop.database.LiquibaseProcducer
java:global/mjop-elements/LiquibaseProcducer
java:app/mjop-elements/LiquibaseProcducer
java:module/LiquibaseProcducer
I'm out of options. Why is my producer not executed? What am I doing wrong?
Any help is appreciated!
My beans.xml is like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>

Jersey Restful Web Service - MessageBodyProviderNotFoundException

I'm new to Java Web Services and I'm struggling with a basic problem.
After finding a bunch of outdated examples I managed to get something working with XML however the same code wont work when I ask it to return JSON.
Initially I thought it was a missing JSON formatter but JAXB should be taking care of the conversion from POJO to JSON so I don't believe that's the problem.
The error being thrown within Tomcat is:
javax.servlet.ServletException: org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/json, type=class resttest.model.Todo, genericType=class resttest.model.Todo
WEB.XML
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>testtest</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>resttest.jaxb;resttest.model</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Todo.java
package resttest.model;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Todo {
public Todo(){};
private String summary;
private String description;
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
TodoResource.Java
package resttest.jaxb;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import resttest.model.Todo;
#Path("/todo")
public class TodoResource {
#GET
#Produces("application/json")
public Todo getTodo() {
Todo todo = new Todo();
todo.setSummary("This is my first todo");
todo.setDescription("This is my first todo");
return todo;
}
}
Any ideas why the JSON isn't being returned and the error thrown?
I searched a lot of the responses myself and this is what I ended up doing. In addition to your TodoResource class, you need a class that extends Application, and class such as the MOXyJsonContextResolver class below to implement the ContextResolver interface. These help define the Jersey context along with a selected Json converter and optional customizations to the Json output. Put the classes in the same package as your resource class and Jersey will find it. MOXy is now the default for Jersey (I use 2.5.1) and the only json converter that I could get working without receiving your error. Also, make sure you have the MOXy jar included in your build or maven pom.xml (jersey-media-moxy-2.5.1.jar).
Note: nothing is in my application's web.xml. That was in the older documentation examples and not needed as of Jersey 2.5.1.
#javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {
public ApplicationConfig() {
this.initMethods();
}
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<Class<?>>();
addRestResourceClasses(resources);
return resources;
}
private void initMethods() {
try {
...some classes you might need instantiated, etc, for your resource class
} catch (Exception e) {
e.printStackTrace();
}
}
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(MOXyJsonContextResolver.class);
}
}
And here is the MOXyJsonContextResolver.class that I used to customize the Json response:
public class MOXyJsonContextResolver implements ContextResolver<MoxyJsonConfig> {
private final MoxyJsonConfig config;
public MOXyJsonContextResolver() {
config = new MoxyJsonConfig()
.setAttributePrefix("")
.setValueWrapper("value")
.property(JAXBContextProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
}
#Override
public MoxyJsonConfig getContext(Class<?> objectType) {
return config;
}
}
You forgot to add the attribute: #XmlAccessorType(XmlAccessType.FIELD)
Example:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Todo {
...
You have mentioned #XmlRootElement at class level in todo class. #XmlRootElement is only required if you want to produce your response in xml format, and also provide #Path at method level in TodoResource class, its a good practice.
mention #Produces(MediaType.APPLICATION_JSON) at method level. Hope this will work for you!

How to save theme in Primefaces

I want to use Primefaces ThemeSwitcher. I'm interested how I can save the selected theme when I reload the web application. For example how I can set the theme name as variable from database?
You won't be needing the ThemeSwitcher to effect the kind of persistence you're looking for.
Simply perform the database lookup for the theme in a ServletContextListener and then store the value in the servlet context, possibly overriding whatever you've set in the web.xml
public Class MyContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce){
String selectedTheme = myThemeDAO.getConfiguredTheme();
sce.getServletContext().setInitParameter("primefaces.THEME",selectedTheme);
}
}
link your ThemeSwitcher component to a managedBean and add a listener linked to a ajax event:
<h:form id="form-theme">
<p:themeSwitcher id="defaultSwitcher" value="#{themeSwitcherBean.theme}">
<f:selectItems value="#{themeSwitcherBean.themes}" />
<p:ajax listener="#{themeSwitcherBean.saveTheme}" />
</p:themeSwitcher>
</h:form>
in your managedbean create the method who call saveTheme, that going to call a class to persist in database, and call the the class for the database when start to get the theme who had saved into the database:
#SessionScoped
#ManagedBean(name="themeSwitcherBean")
public class ThemeSwitcherBean implements Serializable{
private Map<String, String> themes;
private String theme;
private GuestPreferences gp;
private void setGp(GuestPreferences gp) {
this.gp = gp;
}
public Map<String, String> getThemes() {
return themes;
}
public String getTheme() {
return theme;
}
public void setTheme(String theme) {
this.theme = theme;
}
#PostConstruct
public void init() {
setGp(new GuestPreferences()); // persistent class
setTheme(gp.getTheme()); // theme from the database;
themes = new TreeMap<String, String>();
themes.put("Aristo", "aristo");
themes.put("Black-Tie", "black-tie");
themes.put("Blitzer", "blitzer");
themes.put("Bluesky", "bluesky");
themes.put("Bootstrap", "bootstrap");
themes.put("Casablanca", "casablanca");
themes.put("Cupertino", "cupertino");
themes.put("Dark-Hive", "dark-hive");
themes.put("Dot-Luv", "dot-luv");
themes.put("Eggplant", "eggplant");
themes.put("Excite-Bike", "excite-bike");
themes.put("Flick", "flick");
themes.put("Glass-X", "glass-x");
themes.put("Hot-Sneaks", "hot-sneaks");
themes.put("Humanity", "humanity");
themes.put("Le-Frog", "le-frog");
themes.put("Midnight", "midnight");
themes.put("Mint-Choc", "mint-choc");
themes.put("Overcast", "overcast");
themes.put("Pepper-Grinder", "pepper-grinder");
themes.put("Redmond", "redmond");
themes.put("Rocket", "rocket");
themes.put("Sam", "sam");
themes.put("Smoothness", "smoothness");
themes.put("South-Street", "south-street");
themes.put("Start", "start");
themes.put("Sunny", "sunny");
themes.put("Swanky-Purse", "swanky-purse");
themes.put("Trontastic", "trontastic");
themes.put("UI-Darkness", "ui-darkness");
themes.put("UI-Lightness", "ui-lightness");
themes.put("Vader", "vader");
}
public void saveTheme() {
gp.setTheme(theme); // theme to database
}
}
method theme from class GuestPreferences is going to persist to the database
#SessionScoped
public class GuestPreferences {
public String getTheme(){
//return the theme from the database
}
public void setTheme(String theme){
//send the theme to the database
}
}
the form to send and receive data from the database depends of you prefer:
* jdbc
* jta
* jpa
for example, jta, make a persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="NAME-WHAT-YOU-WANT" transaction-type="JTA">
<provider>CLASS-OF-YOUR-PROVIDER</provider>
<jta-data-source>YOUR-DATASOURCE</jta-data-source>
<class>PATH-OF.GuestPreferences</class>
<properties>
<property name="NAME-OF-PROPERTY-TO-FORM-A-JDBC-URL" value="VALUE-OF-PROPERTY"/>
<property name="NAME-OF-PROPERTY-TO-FORM-A-JDBC-URL" value="VALUE-OF-PROPERTY"/>
<property name="NAME-OF-PROPERTY-TO-FORM-A-JDBC-URL" value="VALUE-OF-PROPERTY"/>
</properties>
</persistence-unit>
</persistence>
in a resources class you can declare:
#SuppressWarnings("unused")
#Produces
#PersistenceContext
private EntityManager em;
then, you can use it in your GuestPreferences class:
#Inject
private EntityManager em;
em.getTransaction().begin();
Query query = em.createQuery("SELECT u FROM user_table u where u.iduser=:iduser");
query.setParameter("iduser", "THEME-USER-ID");
User resultUser = (User) query.getResultList();
em.getTransaction().commit();
if(User!=null){
return resultUser.getTheme();
}
code above assumes you have a table called user_table where a user has a iduser, name ..., and a theme column, and it assumes you have an object called User to manage users
One more way to do this: include stylesheet to your pages template:
<h:body>
<h:outputStylesheet library="primefaces-#{themesBean.theme}" name="theme.css" /> </h:body>
Where #{themesBean.theme} variable reffers to name of your theme.
P.S. tested in PF5
I think setting selected theme in session would help:
session.setAttribute
Edit web.xml through code:
http://illegalargumentexception.blogspot.co.at/2008/08/java-using-xmlbeans-to-edit-webxml.html
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>EDITME</param-value>
</context-param>
Or create method before loading your page to choose the theme from db. (cleaner solution)

JSF 1.2 facelets custom component

I am trying to develop custom control in JSF 1.2 (using facelets).
I followed steps from different tutorials (defining .tld, taglib.xml, registered component in faces-config.xml and implementing UIComponent (component renders itself) and UIComponentELTag classes) and my component is rendered, I have value bound to it, but attributes I defined for that tag are ignored. I logged various methods in Tag class and noticed that none of the methods is ever called.
What am I missing? Is there a reason Tag handler class is never invoked?
Thanks in advance.
My taglib.xml file is:
<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>dynamissoft.com/entities/ui</namespace>
<tag>
<tag-name>legalEntityView</tag-name>
<component>
<component-type>rs.bozic.wastemanager.LegalEntityView</component-type>
</component>
</tag>
</facelet-taglib>
Have you tried creating a custom component using facelets (xml only). That's the most easy way, using facelets, usually, the different java classes aren't needed anymore.
Very rough overview:
Create facelet xml file (like myComponent.xhtml)
Register in the facelet inside a taglib (which in turn should be defined in the web.xml)
Optionally, create some support beans in Java
You can pass values/beans to your component using normal tag paramets:
Using the component
Inside the component
Param1 is just printed: #{myParam2}
Param2 used as value for table
...
There are excellent tutorials on Google, like the one from IBM.
If possible, consider using JSF 2.0. Facelets are integrated, and you have more flexibility to create your custom components. I created a blog posting a while ago on that: http://blog.whitehorses.nl/2010/02/08/jsf-2-0/ (or Google yourself)
Just to expand Gerbrand's answer a bit, here's a procedure for a simple Facelets-compatible component. It renders a span tag that wraps a text specified via component's text attribute.
First create the component class (in our case it's just a flavour of
UIOutput):
package sample.mytag;
import java.io.IOException;
import javax.faces.component.UIOutput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
public class SpanComponent extends UIOutput{
private String text;
#Override
public Object saveState(FacesContext context) {
Object values[] = new Object[2];
values[0] = super.saveState(context);
values[1] = target;
return ((Object) (values));
}
#Override
public void restoreState(FacesContext context, Object state) {
Object values[] = (Object[])state;
super.restoreState(context, values[0]);
target = (String)values[1];
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
#Override
public void encodeBegin(FacesContext context) throws IOException {
ResponseWriter writer=context.getResponseWriter();
writer.startElement("span", component);
writer.writeAttribute("id", id, null);
writer.writeText(text, null);
writer.endElement("span");
writer.flush();
}
#Override
public String getFamily(){
return "myTag.component";
}
#Override
public void encodeEnd(FacesContext context) throws IOException {
return;
}
#Override
public void decode(FacesContext context) {
return;
}
}
Next, we need a taglib XML file, let's call it mytag.taglib.xml and put it inside WEB-INF dir.
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"WEB-INF/facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>http://sample.tag/mytags</namespace>
<tag>
<tag-name>myspan</tag-name>
<component>
<component-type>myTag.component</component-type>
</component>
</tag>
</facelet-taglib>
Note that:
.taglib.xml suffix is mandatory
<component-type> should have the same
value that is returned by component's getFamily() method
you can
replace WEB-INF/facelet-taglib_1_0.dtd with
http://java.sun.com/dtd/facelet-taglib_1_0.dtd
It's time to modify web.xml and faces-config.xml.
Former should be modified with
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/mytag.taglib.xml</param-value>
</context-param>
faces-config.xml should get
<component>
<component-type>myTag.component</component-type>
<component-class>sample.mytag.LabelComponent</component-class>
</component>
We're good to go!
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:sample="http://sample.tag/mytag">
<sample:myspan text="I'm inside a span!"/>
</ui:composition>

Resources