I'm getting an ClassCastException while calling an EJB in an Pojo over JNDI. I use Oracle Weblogic Server 10.3.6 (EJB 3.0).
My structure:
app.ear
lib
Interfaces.jar
MyBeanInterface.java
ejb.jar
MyBeanImpl.java
webapp.war
Client.java
WEB-INF
web.xml
My local Interface:
package mypackage;
#Local
public Interface MyBeanInterface {}
My EJB-Class:
package mypackage;
#Stateless(name = "MyBean")
public class MyBeanImpl implements MyBeanInterface {}
My Client (not an EJB):
MyBeanInterface bean = (MyBeanInterface) new InitialContext().lookup("java:comp/env/ejb/MyBean");
My web.xml
<ejb-local-ref>
<ejb-ref-name>ejb/MyBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>mypackage.MyBeanInterface</local>
</ejb-local-ref>
My Exception:
The Lookup itself works. I get a reference. But when I want to cast with (MyBeanInterface) I get the following error:
Cannot cast an instance of "class mypackage.MyBeanInterface_whjkp6_MyBeanImpl (loaded by instance of weblogic.utils.classloaders.GenericClassLoader(id=28136))" to an instance of "interface mypackage.MyBeanInterface(loaded by instance of weblogic.utils.classloaders.GenericClassLoader(id=28144))
What can I do?
It seems the classes are loaded by different class loaders. Possible options are:
1) Ensure the classes are loaded by same class loader
2) Use reflection
3) Serialize and then deserialize
Refer:
1) cast across classloader?
2) https://community.oracle.com/thread/757133
3) ClassCastException because of classloaders?
Related
Quarkus application (0.19.1), created from QuarkEE artifact fails to start with:
[io.qua.dev.DevModeMain] Failed to start quarkus: java.lang.ExceptionInInitializerError ..
Caused by: java.lang.ArrayIndexOutOfBoundsException: 1
at io.quarkus.hibernate.validator.runtime.HibernateValidatorRecorder
EDIT
I've opened a ticket for it:
https://github.com/quarkusio/quarkus/issues/3284
Root cause was a bean validation constraint javax.validation.constraints.NotNull on the static factory method of the enum class. Simplified example:
public enum Gender {
MALE,
FEMALE;
public static Gender fromCode(#NotNull String code) {
return Gender.valueOf(code);
}
}
and having this dependency in your pom:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
</dependency>
Confusing thing is that static factory methods on simple POJO class works.
Note
I'm aware that validation of static methods is not supported by the Bean Validation specification. It is just a hint for IDE.
Java EE 8 Validating Constructors and Methods: Bean Validation constraints may be placed on the parameters of nonstatic methods and constructors and on the return values of nonstatic methods. Static methods and constructors will not be validated.
I have got a problem with ejb remote method invocation. For testing I created a ejb project with a statless bean and a simple method, declared in a remote interface. I deployed this project in a JBoss 7.1.
Now I want to call the business method hello in my bean from another class, which is not part of the project and not deployed in that jboss server. So if I understand it correct, this is a normal remote method call from a client.
I wrote my HelloWorldClient, declared the properties for the InitialContext(). But when I run this client, I got a NameNotFoundException. For me it seems like the exception is because of a false jndi-name, but I tried a lot to get the correct one.
On the console I got jndi names from my server for the project, but it doesn't work. Could someone help me solve this problem?
Client with context:
Properties jndiProps = new Properties();
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
jndiProps.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
jndiProps.put(Context.PROVIDER_URL,"remote://localhost:4447");
jndiProps.put(Context.SECURITY_PRINCIPAL, "testuser");
jndiProps.put(Context.SECURITY_CREDENTIALS, "testpasswort");
Context ctx = new InitialContext(jndiProps);
HelloWorldRemote hello = (HelloWorldRemote) ctx.lookup("java:global[/ejbproject1]/ejbproject1/HelloWorldBean[/HelloWorldRemote]");
My Bean:
#Stateless(name="hello")
public class HelloWorldBean implements HelloWorldRemote{
#Override
public String hello(String value) {
System.out.println("Say hello to "+value);
return "Hello " + value;
}
the jndi names from the jboss
18:19:07,464 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-6) JNDI bindings for session bean named hello in deployment unit deployment "ejbproject1.jar" are as follows:
java:global/ejbproject1/hello!interfaces.HelloWorldRemote
java:app/ejbproject1/hello!interfaces.HelloWorldRemote
java:module/hello!interfaces.HelloWorldRemote
java:jboss/exported/ejbproject1/hello!interfaces.HelloWorldRemote
java:global/ejbproject1/hello
java:app/ejbproject1/hello
java:module/hello
and the exception:
javax.naming.NameNotFoundException: global[/ejbproject1]/ejbproject1/HelloWorldBean[/HelloWorldRemote] -- service jboss.naming.context.java.jboss.exported.global[.ejbproject1].ejbproject1.HelloWorldBean[.HelloWorldRemote]
Change from
java:global/ejbproject1/hello!interfaces.HelloWorldRemote
to
java:/ejbproject1/hello!interfaces.HelloWorldRemote
That will work.
Despite what is claimed here:
for applications not working because of missing #Path at class level
-> it should work now
I still have to annotate my endpoint implementations, as annotations on interfaces are not being picked up.
Is it related to the way I configure JAX-RS, or is it a bug still present in TomEE?
interface:
#Path("myPath") public interface MyEndpoint {
#Path("{id}") String getById(#PathParam("id") long id);
}
implementation:
#Stateless class EJBBackedMyEndpoint implements MyEndpoint {
String getById(long id) { return "foo"; }
}
openejb-jar.xml
<openejb-jar xmlns="http://www.openejb.org/openejb-jar/1.1">
<ejb-deployment ejb-name="EJBBackedMyEndpoint">
<properties>cxf.jaxrs.providers = exceptionMapper</properties>
</ejb-deployment>
</openejb-jar>
resources.xml
<resources>
<Service id="exceptionMapper" class-name="package.MyExceptionMapper"/>
</resources>
beans.xml present with just empty root element
Update:
JAX-RS Spec apparently doesn't mention class-level annotations at all
#Consumes and #Produces work when applied on the interface,
#Path (class level) doesn't work when applied on the interface,
#Path on method level is honoured when routing requests, however the UriBuilder is failing:
UriBuilder.path(EJBBackedMyEndpoint.class, "getById") throws IllegalArgumentException: No Path annotation for 'retrieve' method.
That blog post is perhaps misleading. Putting #Path, #GET, #PathParam or other JAX-RS annotations on an interface is not supported by JAX-RS. Per spec all these need to be on the "Resource Class", which is the #Stateless bean class in this situation.
If you move #Path from the interface to bean class it should work. At least it should get further.
read this article on SO, and had some clarifying questions.
I put my config.properties under src/main/resources
In spring-servlet.xml config file
I added the following:
<context:property-placeholder location="classpath:config.properties"/>
In my business layer, I am trying to access it via
#Value("${upload.file.path}")
private String uploadFilePath;
Eclipse shows error:
The attribute value is undefined for the annotation type Value
Can i not access the property in the business layer or are property files only read in the controller?
UPDATE::
src/main/java/com.companyname.controllers/homecontroller.java
public String home(Locale locale, Model model) {
MyServiceObject myObj = new MyServiceObject();
System.out.println("Property from my service object: = " + myObj.PropertyValue());
if(myObj.PerformService())
{
///
}
}
src/main/java/com.companyname.services/MyService.java
public class MyServiceObject {
#Value("${db.server.ip}")
private String _dbServerIP;
public String PropertyValue() {
return _dbServerIPaseURL;
}
}
Another site where I found the explanation
Please check that you import Value from org.springframework.beans.factory.annotation package:
import org.springframework.beans.factory.annotation.Value;
also the property placeholder must be declared in the respective context configuration file, in case of controller it's likely Spring dispatcher servlet configuration file.
update You are confusing property-placeholder that post processes bean values, that contain dollar symbol ${<property name>} with Spring expression language container extension that process values containing a hash symbol #{<Spring expression language expression>}, in the link you have shown the latter approach is used.
regarding the instantiation of MyServiceObject myObj
If you want the object to be managed by Spring you should delegate its creation to the container:
if MyServiceObject is a stateless service then it's a singleton with the singleton bean scope, you should register it in your application context, for example with the following xml configuration:
<bean class="my.package.MyServiceObject"/>
and inject it to your controller:
private MyServiceObject myServiceObject;
#Autowired
public void setMyServiceObject(MyServiceObject myServiceObject){
this.myServiceObject = myServiceObject;
}
if many instances of MyServiceObject are required, you can declare it as a bean with some other (non-singleton) bean scope (prototype, or request, for example).
However, as there's only one instance of the controller, you can't merely let the Spring container to autowire MyServiceObject instance to the controller field, because there will be only one field and many instances of MyServiceObject class. You can read about the different approaches(for the different bean scopes) for resolving this issue in the respective section of the documentation.
Here is a method that allows us to fetch whatever values are needed from a property file. This can be in Java code (Controller class) or in a JSP.
Create a property file WEB-INF/classes/messageSource.properties It will be in the classpath and accessible in both controllers and JSTL.
Like any property file, this one consists of a key and a value
For example:
hello=Hello JSTL, Hello Contoller
For the Controllers
Locate the xml file that you use to define your Spring beans. In my case it is named servlet-context.xml. You may need to determine that by looking in your web.xml in cases where you are using the servlet contextConfigLocation property.
Add a new Spring bean definition with the id="messageSource". This bean will be loaded at runtime by Spring with the property file key value pairs. Create the bean with the following properties:
bean id="messageSource"
class = org.springframework.context.support.ReloadableResourceBundleMessageSource
property name="basename" value="WEB-INF/classes/messageSource
In the bean definition file for the controller class (testController) add the messageSource as a property. This will inject the messageSource bean into the controller.
bean id="testController" class="com.app.springhr.TestController"
beans:property name="messageSource" ref="messageSource"
In the controller JAVA class, add the messageSource Spring Bean field and its getters and setters. Note the field type is ReloadableResourceBundleMessageSource.
private org.springframework.context.support.ReloadableResourceBundleMessageSource messageSource;
public org.springframework.context.support.ReloadableResourceBundleMessageSource getMessageSource() {
return messageSource;
}
public void setMessageSource(
org.springframework.context.support.ReloadableResourceBundleMessageSource messageSource) {
this.messageSource = messageSource;
}
In your controller code, you can now fetch any known property value from the bundle.
String propValue = getMessageSource().getMessage("hello", objArray, null);
Using JSTL
Since the property file messageSource.properties is in the classpath, JSTL will be able to find it and fetch the value for the given key.
Add the import of the fmt taglib
taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"
Use the fmt:tag in the JSP to fetch a value from the property file.
Sorry about the pseudo syntax, this editor doesn't seem to render any XML.
fmt:bundle basename="messageSource"
fmt:message key="hello"
Hope this helps others
I'm facing weird behavior with JBoss AS 7 and my application which uses EJB3.1.
I successfully lookup bean but when Im trying to cast it to its interface, exception is thrown.
Code in short:
#Local
public interface BusinessObjectsFactory { ... }
#Stateless
#Local(BusinessObjectsFactory.class)
public class JPABusinessObjectsFactory implements BusinessObjectsFactory { ... }
...
Object obj = ctx.lookup("java:app/moduleName/" +
"JPABusinessObjectsFactory!pckg.BusinessObjectsFactory");
Class c = obj.getClass();
System.out.println(c.getName()); // pckg.BusinessObjectsFactory$$$view36
System.out.println(c.getInterfaces()[0].getName()); // BusinessObjectsFactory
BusinessObjectsFactory bof = (BusinessObjectsFactory) obj; //cast exception
Any ideas? Note that interface is needed (which implementation is looked up is read from configuration file and might change)
I switched to another lookup strategy while this is no longer issue for me. I'm not sure if this is still present in newest versions of JBoss/Wildfly AS. That's why I'm closing this question.