EJB not serialized in Managed Bean - jsf-2

My application server is WebSphere Application Server V8. I have a session scoped managed bean in which I have injected EJB (EJB 3.0) using #EJB annotation. EJB is stateless.
#ManagedBean
#SessionScoped
public class MyBean extends BaseBackingBean implements
Serializable {
#EJB
private IDetails custInfo;
I was analyzing the session data and noticed NotSerializableException
java.io.NotSerializableException: com.ejb.EJSLocal0SLDetailsImpl_081f812d at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) at
java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1537) at
java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1502) at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1420) at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at
Now I tried to mark the EJB as transient and it works fine without throwing NotSerializableException exception.
#EJB
private transient IDetails custInfo;
Is this correct implementation or what can be alternate solution?
I have referred Should EJBs be instance variables and marked as transient in JSF Managed Beans? where it is mentioned that marking EJB as transient is not required; then what can be wrong?

Implemented a POC code on WAS V8 with both Local and Remote interfaces, noted the following:
a. With Local interface (EJB does not implement Serializable)
// Initializing the EJB in the servlet
SerializableTestEJBLocal localSrvlt=new SerializableTestEJB();
//Try to serialize
FileOutputStream objFOS = new FileOutputStream("D:\\MYTEST\\testsrv.txt");
ObjectOutputStream objOpStr = new ObjectOutputStream(objFOS);
objOpStr.writeObject(localSrvlt);
This resulted in java.io.NotSerializableException: com.ibm.test.SerializableTestEJB
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:..
To prevent this, the EJB had to explicitly implement Serializable.
b. With Remote Interface (EJB does not implement serializable)
//Obtain Remote Stub.
SerializableTestEJBRemote seremoteSrvlt=(SerializableTestEJBRemote)PortableRemoteObject.narrow(homeObject, SerializableTestEJBRemote.class);
//Try serialization
FileOutputStream objFOS = new FileOutputStream("D:\\MYTEST\\testsrv.txt");
ObjectOutputStream objOpStr = new ObjectOutputStream(objFOS);
objOpStr.writeObject(seremoteSrvlt);
The serialization was successfully.
Conclusion:
The inherent mechanism of remote interface is to obtain a stub or proxy to allow for client-server communication occurs using this proxy pattern. This involves marshalling and unmarshalling of data and hence the proxy-stub is Serializable by default and hence the EJB does not need to implement the Serializable interface.
But the local interfaces does not involve remote look ups and stub handlers. EJB initializes is similar to initializing a locally available class, hence serialization is not available by default. In this scenario, either the EJB will need to implement serializable interface or the object will need to be declared transient to skip serialization.
I am declaring the variable as transient. This might be WebSphere specific solution

Related

How to get and cast JNDI object correctly in Liberty

I have a big problem on getting the correct instance or at least casting the instance I got with JNDI-lookup to correct interface at Web Sphere Liberty (16.0.0.4, running on Java 7, though using Oracle Java 1.8.0_45 in the back, developing on Eclipse Neon.2).
When I start the server and the ear containing the EJB, I get the following notification into the log:
The server is binding the xxx.interfaces.MyLocal interface of the MyEJB enterprise bean in the xxx-ejb.jar module of the xxx-ear application. The binding location is: java:global/xxx/MyEJB!xxx.interfaces.MyLocal
Then I have a web application (ear) which has a service provider (with #Produces) for the previously started ejb-service, which will provide the JNDI resource as injectable (#Inject) for the rest of the application (a bit tricky thing, the main idea is to allow to change the lookup location from configuration file + do some other stuff also). It seems to work correctly for all it is supposed to, but when getting the JNDI-resource, it kind of works but not correctly.
If I put the ejb part as a dependency into my web-module, I can inject it directly (#Inject MyLocal myEjb;).
As the injected resource I get an object with the signature:
EJSMyLocal0SLMyEJB_a4549339#cc5d2cdd
with lookup I get an object with signature (at the same time as the inject):
EJSMyLocal0SLMyEJB_a4549339#cdda36a7
(Not the same instance afaik, but the "type" is correct?)
The injected resource is correctly (automatically of course) cast on 'MyLocal' interface and is ok.
When I try to check the resource got with JNDI, it does not qualify as an instance of 'MyLocal' nor as 'MyRemote'? Also the actual cast fails of course with ClassCastException. (MyRemote is basically the same as the MyLocal interface ... MyLocal extends MyRemote, both interfaces are accordingly annotated with #Local and #Remote)
The EJB looks like this at the time of testing...
#Stateless
#Named
#Default
#Local(MyLocal.class)
#Remote(MyRemote.class)
public class MyEJB implements MyLocal, MyRemote { ... }
I also tried to cast the JNDI resource like this.
InitialContext ic = new InitialContext();
Object lookedUpEjb = ic.lookup(lookup); // the 'java:global...' from log
MyRemote jndiEjb = (MyRemote) PortableRemoteObject.narrow(lookedUpEjb, MyRemote.class)
// Tried also casting/checking 'instanceof' to MyLocal...
No difference with that, the same ClassCastException occurs?!
I have the following features in server.xml
<featureManager>
<feature>javaee-7.0</feature>
<feature>ldapRegistry-3.0</feature>
<feature>localConnector-1.0</feature>
<feature>adminCenter-1.0</feature>
<feature>wsSecurity-1.1</feature>
<feature>ejbLite-3.2</feature>
<feature>ejbRemote-3.2</feature>
<feature>cdi-1.2</feature>
<feature>jpa-2.1</feature>
<feature>jsf-2.2</feature>
<feature>jaxrs-2.0</feature>
<feature>jaxws-2.2</feature>
</featureManager>
I found this documentation on the Liberty JNDI functionality:
https://www.ibm.com/support/knowledgecenter/SSAW57_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_ejb_remote.html
I can't see where I go wrong. How do I cast that object from JNDI lookup to MyLocal or MyRemote interfaces?
---- Note ----
Using the #EJB annotation is not an option (it works though), since it will be hard coded reference to the resource. I want it to be optional though, thus JNDI lookup. #EJB will cause the app to crash when the resource is not available.
The problem is that each application has a different ClassLoader and the object that has been bound into JNDI was loaded with the ClassLoader of the application that defined the EJB.
This should not be an issue for Remote EJB interfaces as the ORB should have taken care of this for you. On a remote call that returns such an object, the ORB will serialize the object (from the target ClassLoader) and then deserialize using the client ClassLoader. For a lookup like this, the PortableRemoteObject.narrow should also take care of this. The failure here appears to just be a bug in the ORB.
In order to support cross application access to Local EJB interfaces, either the Local EJB interface needs to be moved to a shared library, that is used by both applications, or both applications configured to use a single global ClassLoader. See this link for more information about using Local EJB interfaces across applications: Correct way to lookup local EJB in websphere - Getting ClassCastException (Note: this link is discussing traditional WebSphere, but the issue is the same with Liberty, as is the resolution to use a shared library for the interface).

Spring Session without additional context initialization?

I'm trying to use the recently released Spring Session library to do external session management in Redis. I'm using this guide. When I try to start my server, I get this error:
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
I assume this is because my webapp already has code for context initialization. I would prefer to leave that code as is. Is there some way to achieve the result of that tutorial without having to do an additional context initialization? It doesn't really seem like it should be necessary if I can add the springSessionRepositoryFilter bean and corresponding filter object myself, but I don't know how the Spring Session code does that internally.
With Spring Boot application it does not need using initializer classes as spring offical reference:
http://docs.spring.io/spring-session/docs/current-SNAPSHOT/reference/html5/guides/boot.html .
Also using spring security you can check below spring tutorial:
https://github.com/spring-projects/spring-session/tree/master/samples/javaconfig/security/src/main/java/sample
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
public class Initializer extends AbstractHttpSessionApplicationInitializer {
}
If you want to configure with maven instead of gradle you can check my answer in comment.
Hope it helps!
The changes you need to make to your existing initializer should be minimal. First, it probably implements WebApplicationInitializer currently and this should be changed to extend AbstractHttpSessionApplicationInitializer. Second, in your onStartup method, add super.onStartup(servletContext) after your existing initialization code.
public class Initializer extends AbstractHttpSessionApplicationInitializer
{
#Override
public void onStartup(ServletContext servletContext) throws ServletException
{
// existing code
super.onStartup(servletContext);
}
}
I know you were not wanting to change your initializer, but this is a very minimal approach to make it work.

CDI Keeps all Injected tree references of SessionScoped beans?

I am starting a new project with JavaEE 7 and declared a Sessionscoped bean to maintain the web logged user information in session.
The UserSessionBean, as I named it, is intended to be lightweight - trying to avoid lots of data to be kept in the session by Weld. But in some cases I need to get all user information, so added a getUser() method which must query and retrieve a UserEntity from JPA. In order for the method to do its job, I need to #Inject other resources onto the UserSessionBean.
My question is: These dependant resources will be kept and serialised within the UserSessionBean by Weld until the context is destroyed?
The weld documentation says this:
An instance of a dependent bean is never shared between different
clients or different injection points. It is strictly a dependent
object of some other object. It is instantiated when the object it
belongs to is created, and destroyed when the object it belongs to is
destroyed.
That makes me think the all SessionBean tree is kept by weld during session life, but how can I keep a lightweight SessionBean and use injected CDI resources on it?
Since what you're injecting are also CDI beans, it is not the beans themselves that get serialised, but their lightweight proxies. Upon deserialisation, the proxies dynamically resolve the correct beans for whatever scope they are. See section 5.4 Client Proxies of the CDI1.0 spec. Hence, your bean is as lightweight as possible.

Meaning of bean discovery mode annotated in CDI 1.1

I am migrating an application to Java EE 7 and would like to CDI 1.1. But I don't get the meaning of bean-discovery-mode="annotated". The
CDI 1.1 specification is not very helpful. At least I have not found any useful paragraph. Did I miss it?
This example runs perfectly with bean-discovery-mode="all" and injects an instance of LoggingClass:
public class LoggingClass {
public Logger logger = Logger.getLogger("ALOGGER");
}
#Test
public class MMLoggerProducerIT extends Arquillian {
#Inject private LoggingClass lc;
}
But if I change from bean-discovery-mode="all" to bean-discovery-mode="annotated" the container is not able to inject an instance into the field lc.
How do I have to annotate LoggingClass to use bean-discovery-mode="annotated" correctly?
When using bean-discovery-mode="annotated" only classes with a bean defining annotation are discovered. All other classes are ignored. Any scope type is a bean defining annotation. If a scope type is declared on a bean class, then the bean class is said to have a bean defining annotation [spec]. The 1.1 spec is not completely clear here. Only classes with a #NormalScope scope or #Dependent pseudo scope are discovered, #javax.inject.Singleton and all other #Scope (pseudo) scopes are ignored.
Note that the definition of a "bean defining annotation" changed in CDI 1.2 and is now very well defined:
The set of bean defining annotations contains:
#ApplicationScoped, #SessionScoped, #ConversationScoped and #RequestScoped annotations,
all other normal scope types,
#Interceptor and #Decorator annotations,
all stereotype annotations (i.e. annotations annotated with #Stereotype),
and the #Dependent scope annotation.
As a practical matter, bean-discovery-mode="ALL" turns on scanning of all classes in an archive. This is called an "explicit archive".
Omitting beans.xml, or setting bean-discovery-mode="ANNOTATED", makes the archive an implicit archive. In this case, the container will scan for beans with annotated scope types.
This explains why LoggingClass isn't injected when you set bean-discovery-mode="ANNOTATED". As documented in the Java EE 7 Tutorial:
CDI can only manage and inject beans annotated with a scope type in an implicit archive.
Edit: so just to be absolutely clear, you need to add a scope type to LoggingClass. So something like this:
#SessionScoped
public class LoggingClass {
public Logger logger = Logger.getLogger("ALOGGER");
}
In Java EE 7 and CDI 1.1, we removed the requirement to include the beans.xml deployment descriptor to turn on CDI for an archive, bringing CDI 1.1 in line with most other Java EE APIs where deployment descriptors are optional. It also removed the binary on/off nature of including beans.xml or not. You can control which files are scanned by the container with the settings in bean-discovery-mode.
See the JavaEE tutorial on packaging CDI applications here:
http://docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm#CACDCFDE
I also agree with the answer form #rmuller. But I want to point out that there is still different behavior on application servers Payara and Wildfly.
See the following example with a normal not scoped class but having a #EJB injection:
public class SomeClass {
#EJB
MyService myService;
...
}
If you provide a beans.xml file with:
.... version="1.2" bean-discovery-mode="annotated"....
Payara 4.1 will treat the class SomeClass NOT as a CDI bean and will NOT inject the service EJB.
This is clear to me that it behaves as stated in the specification.
But Wildfly 10 treats the class as an CDI bean and injects the service EJB which is not expected. To get this working the beans.xml file should look like this:
.... version="1.2" bean-discovery-mode="all"....
It's amazing that the two most common application servers are different here in behavior.

How can I use Ninject WCF extension with a singleton service?

I'm using Ninject 2.2.1.4 and Ninject.Extensions.Wcf 2.2.0.4.
My service is decorated with the following attribute:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
Using the above attribute, I receive the error:
"The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host."
If I remove the attribute Ninject works as expected.
After doing some research it's my understanding that since the service is marked as a singleton it will automatically be created with a parameter-less constructor by the ServiceHost, hence the error message. In order to resolve the issue, I have to create the service object myself, resolved using ninject, and then pass that singleton object off to the ServiceHost to use. I'm not sure how to do that.
I looked at the WCF extension source and I see that NinjectServiceHost inherits from ServiceHost, so my thought was to bind NinjectServiceHost to my instance of the service object using the overloaded constructor:
public NinjectServiceHost( object singletonInstance )
: base( singletonInstance )
{
}
I'm not sure if that's correct and if it is, how and where to properly bind it so the ServiceHost can be fed my instance.
Any suggestions? Thanks.
If you can live with a beta Version I suggest to update to 2.3.x It supports IIS hosted singleton Services. See also the examples on github

Resources