Using LocalDate in Serialized JSF Managed Bean - jsf

I'm currently working on an Java EE application with Java 8. And, I have a SessionScoped managed bean as below. Since LocalDate is value based, SONAR check throws me an error saying, "Value based should not be serialized"
#SessionScoped
#ManagedBean
public class MyBean implements Serializable {
private LocalDate startDate;
/*getters and setters */
}
How to handle this situation. Is it fine to make the variable transient? Is there any impact, if I make it transient? Or I can ignore this SONAR error?
Any help would be appreciated. Thank you in advance!

Related

#Inject gives null Object [duplicate]

This question already has answers here:
NullPointerException while trying to access #Inject bean in constructor
(2 answers)
Closed 5 years ago.
I have these two classes and want to use the method of MyData to insert data in MyBean.
#Named
#RequestScoped
public class MyBean implements Serializable {
#Inject
private MyData myData;
public MyBean() {
// NullPointerException, because myData is null
this.dataList = myData.method();
}
...
}
#Singleton
class MyData {
method(){
...
}
}
MyData on the other Hand injects a controller class myHandler:
#Singleton
public class myHandler {...}
I keep getting error messages, that myData.method() is null and have no idea about it. Maybe I haven't fully understood what CDI injection means?
Edit:
These are the fully qualified annotations.
import javax.ejb.Singleton;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
Edit2: The container used is a wildfly 11. Since I use Maven too, there is not much I could do wrong with my project structure because I have to follow the Maven rules.
As I mentioned before, the server works fine for crud operations on my database, where I used CDI and JSF before. I just added MyBean and MyData to my project.
I tried #Startup, results have not changed.
Edit3: I don't think it's a duplicate because I tried to use #DependsOn() annotation and still get null back. The NullException doesn't come from the bean but from JavaScript, where I want to insert a String with JSF later being processed to a chart. The stacktrace says, that this function passes null value to the member variable in the contructor of the bean.
Have you used EJB Singleton by mistake? javax.ejb.Singleton is not recognised by CDI and so it will not be picked up.
For CDI, use either javax.inject.Singleton or #ApplicationScoped.

injectionPoint.getBean() returns null if bean is an EJB bean in Java EE 7 (CDI 1.1)

I want to get bean from producer method in order to read its properties. In some scenarios the bean is a EJB Singleton bean.
I've simplified my code to focus on the problem.
My simple qualifier:
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface InjectMe {}
Simple producer:
#Dependent
public class SimpleProducer {
#Produces
#InjectMe
public String getInjectMe(InjectionPoint ip) {
// ip.getBean() returns null for some reason
return "ip=" + ip + ", bean=" + ip.getBean();
}
}
EJB (Singleton):
#Singleton
#Startup
public class SimpleSingleton {
#Inject
#InjectMe
private String injectMe;
#PostConstruct
public void init() {
System.out.println(injectMe);
}
}
Console output:
Info: ip=[BackedAnnotatedField] #Inject #InjectMe private com.test.ejb.SimpleSingleton.injectMe, bean=null
When I change Singleton bean to CDI bean everything works fine (ip.getBean() returns not null). It also worked in Java EE 6 even with Singleton bean but it does not in Java EE 7. I am using Glassfish 4 application server.
Is this behavior specified somewhere?
Using
injectionPoint.getMember().getDeclaringClass()
works for me in WildFly 10.1.0 and I also quickly tested it in Payara Server 4.1.1.162 #badassfish (build 116). I also did a test on brand new Payara Server 4.1.1.164 #badassfish (build 28). However,I had to change the scope of the producer bean to #ApplicationScoped. Default scope did not work. In my case, it even makes sense :)
The
injectionPoint.getBean().getBeanClass()
method worked for me in the old Payara, but not in the new WildFly 10.1.0.Final and new Payara Server 4.1.1.164 #badassfish (build 28).
If you have a look at Payara, the current new version 164 contains Weld 2.4.0.Final and WildFly 10.1.0Final uses version 2.3.5.Final. In both versions, the classical code does not work !
The conclusion is, on older CDI implementations (Weld), it works. In some newer Weld (introduced in Payara 161), the behavior changed. I do not know if this is intentional or not.
However, the solution is to use
injectionPoint.getMember().getDeclaringClass()
and annotate the producer bean with
#javax.enterprise.context.ApplicationScoped
annotation.

Accessing ResourceBundle as ManagedProperty Serialization Issue

first of all, sorry for my bad english!
in the following managed Bean (ApplicationScoped), i access a ResourceBundle(.properties) as a #ManagedProperty. a ResourceBundle Object is not serializable, so i get in the Eclipse/Tomcat Console an Error saying that this object cannot be serialized/de-serialized.. etc.
Exception loading sessions from persistent storage
java.io.WriteAbortedException: writing aborted;
java.io.NotSerializableException: java.util.PropertyResourceBundle
i have 2 Questions to this issue:
i think, JSF handles pre-defined(in faces-config.xml) ResourceBundles as ApplicationScoped beans. this means(if i understanding this correctly), this Object/Bean (ResourceBundle) is been stored somewhere somehow in a file (persistent storage). Now and since ResourceBundle is not serializable, then in which format is it been stored? and how JSF serves such "Beans"? serialized Objects are stored in files as Bytes, so how not serializable Objects are stored?
in the following example, i would declare my #ManagedProperty ResourceBundle as transient (due to serialization problem), but transient objects won't be stored in persistent storage (stateless), does this mean that with every call of the method getConfigurationAttribute(where i use this resourceBundle) will recreate/reload the ManagedPropery ResourceBundle since it is marked as transient?
Your help is greatly appreciated.
#ManagedBean(name="facesResource",eager=true)
#ApplicationScoped
public class FacesResource implements Serializable{
private static final long serialVersionUID = 2454454363100273885L;
#ManagedProperty("#{FACES_CONFIG}")
private ResourceBundle facesConfig;
//private transient ResourceBundle facesConfig;
....
private Map<String,Language> languagesMap;
private Map<String,Theme> themesMap;
....
public FacesResource(){
}
#PostConstruct
public void init(){
System.out.println("*** FacesResource init ....");
try{
....
this.initLanguages();
this.initThemes();
....
}catch(Exception ex){
ex.printStackTrace();
}
}
public String getConfigurationAttribute(String attributeKey){
return this.facesConfig.getString(attributeKey);
}
// ... other methods & getter/setter ...etc
}
UPDATE:
the ResourceBundle in the FacesResource Bean is independent of the Request Locale, so its not a problem to load it in an ApplicationScoped Bean, BUT
since i access/inject(as #ManagedProperty) this ApplicationScoped Bean in other SessionScoped Beans, which should be serialized, which means, that all attributes (resourceBundle included) should be serialized too, and here i got the Problem with Serialization/Deserializazion
#BalusC: if i do like you suggest in your answer: ResourceBundle.getBundle("com.example.text"), i have to provide the baseName of the Bundle. BUT this is exactly what i want to avoid. i don't want to hardcode static Paths in java Source Codes), so that when the path changes(most unlikely, but for the Case), i don't like to change paths in Java Source Codes but only in faces-config.xml.
and i cannot use FacesContext.getCurrentInstance().getApplication().getResourceBundle(facesContext, "bundleVarName"); because my Bean is marked with eager=true, which means, the facesContext is NULL at this moment!
i think, JSF handles pre-defined(in faces-config.xml) ResourceBundles as ApplicationScoped beans.
Nope. They are managed by ResourceBundle API itself. JSF just resolves them on a per-request basis based on the requested locale (otherwise it would affect the language of any user visiting the web application!). So, they are essentially request scoped. But this all has further nothing to do with serialization. The ResourceBundle class is simply never intented to be serializable. It just lazily loads the bundles in Java's memory.
You'd best just do the same. Lazy loading it if it becomes null after deserialization. You only shouldn't evaluate #{FACES_CONFIG}, because it would be dependent on request locale. Provided that you can only use JSF <resource-bundle><var>, then you'd best load them via Application#getResourceBundle(). Provided a resource bundle var name of FACES_CONFIG, here's an example:
private transient ResourceBundle facesConfig;
public ResourceBundle getFacesConfig() {
if (facesConfig == null) {
FacesContext context = FacesContext.getCurrentInstance();
facesConfig = context.getApplication().getResourceBundle(context, "FACES_CONFIG");
}
return facesConfig;
}
By the way, the variable name facesConfig is very confusing. It namely suggests that it represents the contents of faces-config.xml.
See also:
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException
You can't use #ManagedProperty on a not Serializable Type.
Is it a resource bundle for localized Strings?
Read this: http://www.mkyong.com/jsf2/jsf-2-0-and-resource-bundles-example/
FacesContext facesContext = FacesContext.getCurrentInstance();
ResourceBundle resourceBundle = facesContext.getApplication()
.getResourceBundle(facesContext, "bundleName");

RESTEasy, CDI, embedded Jetty, bean validation is ignored

I've a Groovy project where I use RESTEasy with Weld and deploy to embedded Jetty. What I can't seem to get working is bean validation. RESTEasy documentation says that adding resteasy-validator-provider-11 along with hibernate validator dependencies (hibernate-validator, hibernate-validator-cdi, javax.el-api, javax.el) is enough. But the bean validation is simply ignored by RESTEasy. I curiously also get the following message in the logs:
plugins.validation.ValidatorContextResolver - Unable to find CDI supporting ValidatorFactory. Using default ValidatorFactory
Based on the suggestions on [this][1] post, I tried registering Hibernate InjectingConstraintValidatorFactory in META-INF/validation.xml but it depends on a BeanManager being injected and blows up at runtime.
The code can be found here https://github.com/abhijitsarkar/groovy/tree/master/movie-manager/movie-manager-web
A log gist is here: https://gist.github.com/anonymous/8947319
I've tried everything under the sun without any success. Pls help.
To do this without EE, I believe you'll need to fork the existing InjectingConstraintValidatorFactory but instead of using injection of the bean manager, use the CDI 1.1 class CDI to get a reference to the bean manager, e.g. CDI.current().getBeanManager(). http://docs.jboss.org/cdi/api/1.1/javax/enterprise/inject/spi/CDI.html
You do need to be on CDI 1.1 to do this (so Weld 2+, 2.1.1 is current I believe). Here's an example impl, based on: https://github.com/hibernate/hibernate-validator/blob/master/cdi/src/main/java/org/hibernate/validator/internal/cdi/InjectingConstraintValidatorFactory.java
public class InjectingConstraintValidatorFactory implements ConstraintValidatorFactory {
// TODO look for something with better performance (HF)
private final Map<Object, DestructibleBeanInstance<?>> constraintValidatorMap =
Collections.synchronizedMap( new IdentityHashMap<Object, DestructibleBeanInstance<?>>() );
private final BeanManager beanManager;
public InjectingConstraintValidatorFactory() {
this.beanManager = CDI.current().getBeanManager();
Contracts.assertNotNull( this.beanManager, "The BeanManager cannot be null" );
}
#Override
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
DestructibleBeanInstance<T> destructibleBeanInstance = new DestructibleBeanInstance<T>( beanManager, key );
constraintValidatorMap.put( destructibleBeanInstance.getInstance(), destructibleBeanInstance );
return destructibleBeanInstance.getInstance();
}
#Override
public void releaseInstance(ConstraintValidator<?, ?> instance) {
DestructibleBeanInstance<?> destructibleBeanInstance = constraintValidatorMap.remove( instance );
destructibleBeanInstance.destroy();
}
}
I finally fixed this. Turns out, a validation.xml is not really required, resteasy-cdi module does a fine job of registering the BeanManager. What I was missing and not clearly documented anywhere, is that if an annotation is placed on a method, the validation engine just "decides" what should be validated. I placed a #NotNull on a method and it was validating the return type, not the parameters. One can use validationAppliesTo element in some cases but #NotNull doesn't have it. When I moved it from the method to the parameter, it started working.
Now I ran across what I believe is a Weld bug but I'll post that question separately.

Non-lazy instantiation of CDI SessionScoped beans

CDI newbie question. Simple test scenario: JSF + CDI SessionScoped beans.
I need an elegant way to instantiate a known set of session scoped CDI beans without mentioning them on a JSF page or calling their methods from other beans. As a test case - a simple logging bean, which simply logs start and end time of an http session.
Sure, I could create an empty JSF component, place it inside of a site-wide template and make it trigger dummy methods of the required session beans, but it's kinda ugly from my pov.
Another option I see, is to choose a single session bean (which gets initialized 100% either by EL in JSF or by references from other beans), and use its #PostConstruct method to trigger other session beans - the solution a little less uglier than the previous one.
Looks like I'm missing something here, I'd appreciate any other ideas.
While accepting the Karl's answer and being thankful to Luiggi for his hint, I also post my solution which is based on HttpSessionListener but does not require messing with BeanProvider or BeanManager whatsoever.
#WebListener
public class SessionListener implements HttpSessionListener {
#Inject
Event<SessionStartEvent> startEvent;
#Inject
Event<SessionEndEvent> endEvent;
#Override
public void sessionCreated(HttpSessionEvent se) {
SessionStartEvent e = new SessionStartEvent();
startEvent.fire(e);
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
SessionEndEvent e = new SessionEndEvent();
endEvent.fire(e);
}
}
To my surprise, the code above instantiates all the beans which methods are observing these events:
#Named
#SessionScoped
public class SessionLogger implements Serializable {
#PostConstruct
public void init() {
// is called first
}
public void start(#Observes SessionStartEvent event) {
// is called second
}
}
Yes, HttpSessionListener would do it. Simply inject the beans and invoke them.
If you container does not support injection in a HttpSessionListener you could have a look at deltaspike core and BeanProvider
http://deltaspike.apache.org/core.html

Resources