Thanks to this post, https://stackoverflow.com/a/28047512/1227941 I am now using CDI to make msg available in my #Named beans like this:
#RequestScoped
public class BundleProducer {
#Produces
public PropertyResourceBundle getBundle() {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().evaluateExpressionGet(context, "#{msg}", PropertyResourceBundle.class);
}
}
With Injection like:
#Inject
private PropertyResourceBundle bundle;
The question: What should I do if I have more property files: ui.properties, admin.properties ...?
I'd simply use a classifier annotation to choose which bundle to inject. Ripped from a little project of mine:
The annotation:
#Qualifier
#Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
#Retention(RetentionPolicy.RUNTIME)
public #interface Bundle {
#Nonbinding
public String value() default "";
}
The producer method (adapt as necessary for your context):
#Produces #Bundle ResourceBundle loadBundle(InjectionPoint ip) {
String bundleName = ip.getAnnotated().getAnnotation(Bundle.class).value();
ResourceBundle res = ResourceBundle.getBundle(bundleName);
return res;
}
And the injection:
#Inject #Bundle("ui")
private ResourceBundle uiResources;
Related
I've coded this aspect:
#Aspect
public class LoggingCacheAspect {
#Pointcut("call * javax.cache.integration.CacheLoader.load(*)")
void cacheLoadCalls() {};
#Before("cacheLoadCalls")
public void beforeCacheCalls() {}
}
Also, I'm using CDI, and I'm looking forward to figure out how to inject a bean into this aspect.
I guess that adding #Inject annotation will not be enought.
Is it possible?
How could I get it?
You need to use an interceptor instead of the aspect
Here is an example:
#InterceptorBinding
#Target({TYPE, METHOD })
#Retention(RUNTIME)
public #interface CacheLog{
}
#Interceptor
#CacheLog
public class CacheLogInterceptor implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private YourBean yourBean;
#AroundInvoke
public Object cacheLogMethodCall(InvocationContext ctx) throws Exception {
//#Before
yourBean.method();
...
return ctx.proceed();
}
}
#CacheLog
public void cacheLoadCalls() {
...
...
}
I wanted to know, is there any option to call a managed bean inside of EJB bean. Imagine, we have the code:
#ManagedBean
#SessionScoped
public class MyManagedBean implements Serializable {
public String getUrl() {
return "http://www.google.com";
}
}
#Stateless
public class MyEJB {
#ManagedProperty(value = "#{myManagedBean}")
MyManagedBean myManagedBean;
public void setMyManagedBean(MyManagedBean myManagedBean) {
this.myManagedBean = myManagedBean;
}
public void call() {
// NullPointerException here
System.out.println(myManagedBean.getUrl());
}
}
I also tried this:
#Stateless
public class MyEJB {
#EJB
MyManagedBean myManagedBean;
...
}
... but it returns different MyManagedBean instance.
This is not right. With CDI managed beans instead of JSF managed beans it's possible, but it is just not right as in, bad design. The business service should not be aware about the front-end at all. It makes the business service unreusable on other front-ends than JSF.
You should do it the other way round. You should inject the EJB in the managed bean, not the other way round. The EJB should be kept entirely stateless. You should just directly pass the EJB the information it needs as method argument (and never assign it as instance variable of EJB afterwards).
E.g.
#ManagedBean
#SessionScoped // <-- Did you read https://stackoverflow.com/q/7031885?
public class MyManagedBean implements Serializable {
private String url = "http://www.google.com";
#EJB
private MyEJB myEJB;
public void submit() {
myEJB.call(url);
}
public String getUrl() {
return url;
}
}
and
#Stateless
public class MyEJB {
public void call(String url) {
// No NullPointerException here.
System.out.println(url);
}
}
See also:
JSF Service Layer
I'm having problems with CDI on tomcat. That's some relevant part of my code:
public class JPAUtil {
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("unit");
#Produces #RequestScoped
public static EntityManager getEntityManager() {
return emf.createEntityManager();
}
public void close(#Disposes EntityManager em) {
em.close();
}
}
My DAO Class:
public class DAO<T> implements Serializable{
private final Class<T> classe;
#Inject
protected EntityManager em;
public DAO(Class<T> classe) {
this.classe = classe;
}
}
and a child class:
public class UserDao extends DAO<User> implements Serializable{
public UserDao() {
super(User.class);
}
}
Because of the Generics, I used a producer for the DAO class:
public class DAOFactory {
#Produces
#SuppressWarnings({ "rawtypes", "unchecked" })
public DAO createDAO(InjectionPoint injectionPoint) {
ParameterizedType type = (ParameterizedType) injectionPoint.getType();
Class classe = (Class) type.getActualTypeArguments()[0];
return new DAO(classe);
}
}
In this example:
public class Test {
#Inject UserDAO userDAO;
#Inject DAO<User> dao;
}
When I try to use the UserDAO class, everything works fine, but when I use the DAO, the EntityManager remains null. Anyone have any idea?
In DAOFactory you instantiate the DAO with new operator, if you do so, CDI has no chance to inject dependencies in the DAO instance.
While in UserDAO CDI manages the entity manager injection.
So in DAOFactory you should set manually the entity manager in the newly created DAO instance.
(Java EE 6 with Glassfish 3.1)
I have a property file that I want to process only once at start up time, so I did this
public class Config implements ServletContextListener{
private static final String CONFIG_FILE_PATH = "C:\\dev\\harry\\core.cfg";
private static final String CONFIG_ATTRIBUTE_NAME = "config";
private long startupTime;
private ConfigRecord config;
#Override
public void contextInitialized(ServletContextEvent sce) {
this.startupTime = System.currentTimeMillis() / 1000;
this.config = new ConfigRecord(CONFIG_FILE_PATH); //Parse the property file
sce.getServletContext().setAttribute(CONFIG_ATTRIBUTE_NAME, this);
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
//Nothing to do here
}
public ConfigRecord getConfig() {
return config;
}
public long getStartupTime() {
return startupTime;
}
}
and in web.xml, i register it as follow
<listener>
<listener-class>com.wf.docsys.core.servlet.Config</listener-class>
</listener>
Now how do I access the ConfigRecord config from the managed bean. I try this
#ManagedBean
#RequestScoped
public class DisplayInbound {
#EJB
private CoreMainEJBLocal coreMainEJBLocal;
#javax.ws.rs.core.Context
private ServletContext servletContext;
public void test(){
Config config = (Config) servletContext.getAttribute("config")
ConfigRecord configRecord = config.getConfig();
}
}
I dont think it work. Got NullPointerException.
That #Context annotation is only applicable in a JAX-RS controller, not in a JSF managed bean. You have to use #ManagedProperty instead. The ServletContext is available by ExternalContext#getContext(). The FacesContext itself is available by #{facesContext}.
#ManagedProperty(value="#{facesContext.externalContext.context}")
private ServletContext context;
Or because you stored the listener as a servletcontext attribute, which is basically the same as the JSF application scope, you could also just set it as managed property by its attribute name:
#ManagedProperty(value="#{config}")
private Config config;
But since you're on JSF 2.0, I'd suggest to use an #ApplicationScoped #ManagedBean instead which is eagerly constructed. With #PostConstruct and #PreDestroy in such a bean you have similar hooks on webapp's startup and shutdown as in a ServletContextListener.
#ManagedBean(eager=true)
#ApplicationScoped
public void Config {
#PostConstruct
public void applicationInitialized() {
// ...
}
#PreDestroy
public void applicationDestroyed() {
// ...
}
}
You can inject it in another beans the usual #ManagedProperty way and access it in the views the usual EL way.
I'm trying to do simple thing. Inject qualified String (or File) in CDI.
So I have a qualifier:
#Retention(RetentionPolicy.RUNTIME)
#Target({FIELD,METHOD,PARAMETER,TYPE})
#Qualifier
public #interface FilesRepositoryPath {}
I have a producer:
public class FilesRepositoryPathProducer {
#Produces
#FilesRepositoryPath
public String getRepositoryDirectory() {
return "path.taken.from.configuration";
}
}
And I'm trying to use it:
#ApplicationScoped
public class FilesRepository {
#Inject
public FilesRepository(#FilesRepositoryPath String filesDirectory) {
//Do some stuff
}
}
However, WELD cannot instantiate this bean. I am getting an exception:
org.jboss.arquillian.impl.event.FiredEventException: org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001410 The injection point [field] #Inject private za.co.fnb.commercial.dms.file.FilesRepositoryBeanTest.repo has non-proxyable dependencies
I know String is unproxable, but why WELD wants to create a proxy? It has #Dependent scope, so AFAIK it shouldn't create proxy anyway. How can I make it work?
you need the default constructor
#ApplicationScoped
public class FilesRepository {
public FilesRepository() {
}
#Inject
public FilesRepository(#FilesRepositoryPath String filesDirectory) {
//Do some stuff
}
}