Java Class cast exception, Classloader error on using javax xml providers? - java

I get the following error when I switched from OSGI Equinox to OSGI Karaf runtime.
Earlier the com.sun implementation was working fine, but now I need an apache implementation to run in one environment and com.sun in the older.
I know that OSGI has different class loading mechanism when compared to Java Class loading.
We are providing the javax packages as a part of the rt.jar which contains the Provider interface.
The implementation is coming from com.sun.xml
com.sun.xml.internal.ws.spi.ProviderImpl cannot be cast to javax.xml.ws.spi.Provider (loaded by org.apache.felix.framework.BundleWiringImpl$BundleClassLoader#0x0000000100162fd8) (found matching super class javax.xml.ws.spi.Provider loaded by , but needed loader org.apache.felix.framework.BundleWiringImpl$BundleClassLoader#0x0000000100162fd8)
at javax.xml.ws.spi.Provider.provider(Provider.java:43)
at javax.xml.ws.Service.<init>(Service.java:35)
at javax.xml.ws.Service.create(Service.java:126)
When I look at the logs, both class loaders seem to have the same ID, then why get a class cast exception?
javax.xml.ws.spi.Provider (loaded by org.apache.felix.framework.BundleWiringImpl$BundleClassLoader#0x0000000100162fd8) (found matching super class javax.xml.ws.spi.Provider loaded by , but needed loader org.apache.felix.framework.BundleWiringImpl$BundleClassLoader#0x0000000100162fd8)
As of now, I am using a hack to get around this in two different environments
private static final String PROVIDER_CXF = "org.apache.cxf.jaxws.spi.ProviderImpl";
private static final String PROVIDER_DEFAULT = "com.sun.xml.internal.ws.spi.ProviderImpl";
private String setProvider() {
log.debug("set default provider");
System.setProperty(PROVIDER, PROVIDER_DEFAULT);
try {
Service.create(new QName(null, ""));
return PROVIDER_DEFAULT;
} catch (Exception e) {
log.debug("setting cxf provider");
System.setProperty(PROVIDER, PROVIDER_CXF);
return PROVIDER_CXF;
}
}

You may need to set -Dorg.osgi.framework.bootdelegation=com.sun.*. See https://osgi.org/specification/osgi.core/7.0.0/framework.module.html#framework.module.parentdelegation. It is possible Equinox provides a common, useful default for boot delegation while Karaf does not.

Related

ClassNotFoundException using QuarkusClassLoader with local class and Debezium Engine

ClassLoader classLoader = QuarkusClassLoader.getSystemClassLoader();
String str = "com.mycompany.service.SomeClass";
try {
Class<? extends SomeClass> someClass =
(Class<? extends SomeClass>) classLoader.loadClass(str);
} catch (Throwable e) {
e.printStackTrace();
}
I'm trying to figure out why I get java.lang.ClassNotFoundException when I try to load com.mycompany.service.SomeClass. This class is defined locally in the project, I'm getting this error when I start my Quarkus app (mvn compile quarkus:dev). If I use another class loader (i.e. this.getClass().getClassLoader()), this error does not happen. It seems like it only happens with QuarkusClassLoader
EDIT:
I think in the end the problem was related to Debezium Engine initialisation. That exception was thrown when calling the following line:
// Create the engine with this configuration ...
engine =
DebeziumEngine.create(Json.class)
.using(props)
.notifying(this::handleDbChangeEvent)
.build();
See my answer for how I fixed it
Using Classloader.getSystemClassLoader is certainly not the correct thing to do because in dev-mode (and more generally, you would rarely want to do that in Java code), Quarkus dot not a flat classloader structure, but a layered one.
See https://quarkus.io/guides/class-loading-reference for more details on how Classloading in dev-mode works.
You can force all classes of a jar to be loaded by the system ClassLoader instead of the Quarkus ClassLoader by using something like:
quarkus.class-loading.parent-first-artifacts=stax:stax-api
Where you essentially configure the groupId and the artifactId of the jar that should be loaded by the system ClassLoader
I fixed this by passing Thread.currentThread().getContextClassLoader() in the engine initialisation.
engine =
DebeziumEngine.create(Json.class)
// Have to pass the current class loader to avoid ClassNotFoundException
.using(Thread.currentThread().getContextClassLoader())
.using(props)
.notifying(this::handleDbChangeEvent)
.build();

org.apache.felix.ipojo.ComponentFactory cannot be cast to org.apache.felix.ipojo.Factory

I have a bundle component,
package ipojo;
import ipojo.service.Hello;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Invalidate;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.Validate;
#Component(name="hello-factory")
#Provides
public class HelloImpl implements Hello{
#Override
public void shoutHello() {
System.out.println("HellooOOOOoooOooo!");
}
#Validate
public void start() throws Exception {
System.out.println("Hello started :)");
}
#Invalidate
public void stop() throws Exception {
System.out.println("Hello Stopped :(");
}
}
In my java application, I embedded Apache Felix, and deployed iPOJO APIs. Then, I tried to create an instance of my above component using Factory Service, as the following:
myBundle= context.installBundle("myBundlePath");
myBundle.start();
ServiceReference[] references = myBundle.getBundleContext().getServiceReferences(Factory.class.getName(), "(factory.name=hello-factory)");
if (references == null) {
System.out.println("No references!");
}
else {
System.out.println(references[0].toString());
Factory factory = myBundle.getBundleContext().getService(references[0]);
ComponentInstance instance= factory.createComponentInstance(null);
instance.start();
}
I successfully got the reference to the factory service, but at the following line:
Factory factory = myBundle.getBundleContext().getService(references[0]);
I get the following ClassCastException:
java.lang.ClassCastException: org.apache.felix.ipojo.ComponentFactory cannot be cast to org.apache.felix.ipojo.Factory`
I changed this line to:
Factory factory = (ComponentFactory) myBundle.getBundleContext().getService(references[0]);
then I got:
java.lang.ClassCastException: org.apache.felix.ipojo.ComponentFactory cannot be cast to org.apache.felix.ipojo.ComponentFactory
How can I solve my problem? Thank you.
When embedding Felix (or any other OSGi framework) you create a boundary between the classloaders. The host and the bundles are not using the same classloaders meaning that classes from inside and outside are not compatible. In other words, accessing OSGi services from the host is particularly complex and require using reflection.
For simplicity reasons, you should use the Factory service (and any other services) from a bundle and not from the host.
If you really need to use them from the host, you have to configure the OSGi framework to export all the required packages from bundle 0.
This exception means that there are classpath problems, as there are multiple versions of libraries in the classpath.
A ClassCastException when a class cannot be cast to a class of the same name is caused by an attempt to cast classes accross classloaders: it's not possible to do so, see here.
The classloader which loaded the class makes part of the class unique identifier.
So two classes with the exact same name org.apache.felix.ipojo.ComponentFactory will not be the same if they where loaded in different classloaders.
You need to debug your classpath, find the unwanted version of the library containing that class and remove it.

A good way to "centralize" instances provided by a library?

I have written this project and already use it in other libraries of mine.
However, I find something amiss. Namely, in each user of this library, I create a utility class whose only role is to provide one or more MessageBundles. And this sucks.
I'd like to have, built into the library, a mechanism in order to have library users be able to register/recall bundles.
My first idea would be to have a singleton factory with a .register() and .get() method (with appropriate checks for duplicate keys etc) and call these from within static initialization blocks...
... But there is a problem: there is no guarantee as to which static initialization block will be called first.
Knowing that I'd like to keep the dependencies of this library "intact" (which is to mean, no external dependency at all), what solution would you recommend?
(note: this is Java 6+)
You could use the standard support for service providers: ServiceLoader. You would simply require each user of your library to provide an implementation of some interface, for example
public interface MessageBundleProvider {
List<MessageBundle> getBundles();
}
The name of the class implementing this interface would have to be specified in a file of the jar file of the user library named META-INF/services/com.example.MessageBundleProvider.
At runtime, your library would automatically discover all the message bundle providers using the following code:
private static final ServiceLoader<MessageBundleProvider> LOADER
= ServiceLoader.load(MessageBundleProvider.class);
private static final List<MessageBundle> BUNDLES;
static {
BUNDLES = new ArrayList<MessageBundle>();
for (MessageBundleProvider provider : loader) {
for (MessageBundle bundle : provider.getBundles()) {
BUNDLES.add(bundle);
}
}
}
Disclaimer: I know that ServiceLoader exists, but I've never used it before. It's how all the standard Java service providers are discovered, though (like JDBC drivers, charset providers, etc.).

Implementing Spring-like package scanning in Android

I'm attempting to implement a package-scanning feature, similar to Spring's component-scan, for the Android framework I'm developing. Basically, I would like to be able to specify a base package, e.g. com.foo.bar and retrieve all Class instances that have a particular annotation. I don't want to have to register every component with my framework as that would defeat the purpose of the auto scanning.
Based on my research, it seems that it's not possible with Java to retrieve resources given a package name using reflection. However, I briefly looked into the Reflections framework, and I'm wondering if there is an Android-compatible equivalent. If not, perhaps there is a slightly less obvious way to accomplish what I want to do.
I looked into the Spring source a bit to see how they achieved this, but I don't think what they are doing would work within the Dalvik runtime.
Update
Currently, the below code has been the best I can do to retrieve all classes that contain a specific annotation, but frankly it's a pretty poor solution. It makes some really unsafe assumptions about the ClassLoader plus it scans (and loads) all application classes.
public Set<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotation) {
Set<Class<?>> classes = new HashSet<Class<?>>();
Field dexField = PathClassLoader.class.getDeclaredField("mDexs");
dexField.setAccessible(true);
PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();
DexFile[] dexs = (DexFile[]) dexField.get(classLoader);
for (DexFile dex : dexs) {
Enumeration<String> entries = dex.entries();
while (entries.hasMoreElements()) {
String entry = entries.nextElement();
Class<?> entryClass = dex.loadClass(entry, classLoader);
if (entryClass != null && entryClass.isAnnotationPresent(annotation)) {
classes.add(entryClass);
}
}
}
return classes;
}
I wanted to find all the subclass at runtime.
So I've been looking for android class scanning.
This is my final code from what I gathered in web.
You will get the idea.
public static void findSubClasses(Context context, Class parent) {
ApplicationInfo ai = context.getApplicationInfo();
String classPath = ai.sourceDir;
DexFile dex = null;
try {
dex = new DexFile(classPath);
Enumeration<String> apkClassNames = dex.entries();
while (apkClassNames.hasMoreElements()) {
String className = apkClassNames.nextElement();
try {
Class c = context.getClassLoader().loadClass(className);
if (parent.isAssignableFrom(c)) {
android.util.Log.i("nora", className);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// android.util.Log.i("nora", className);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
dex.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I share the opinion of Joop Eggen and find his approach a good one. In Android I try to avoid the usual web app features which lead to a long lasting application start. I do not use reflection or package scanning.
But if you want to .... if I understand it correctly you want to have an annotation for a class. Instead of using annotations you could also use marker interfaces (to just have more possibilites).
1) Look at
Annotation: Java custom annotation and dynamic loading
Has an implementation in the question which just answers your question.
Annotation: Scanning Java annotations at runtime
Interface: Find Java classes implementing an interface
Interface: Is something similar to ServiceLoader in Java 1.5?
Interface: How can I get a list of all the implementations of an interface programmatically in Java?
Interface: Since the approach is expensive, maybe the ServiceLoader is a compromise between execution time and comfort, since it loads only the classes given in the services file. On the other hand if only classes with a certain interface are in your package then the ServiceLoader isn't that faster.
2) AndroidAnnotations
I would prefer the way AndroidAnnotations work (maybe an integration in AndroidAnnotations is the preferable way): It automatically adds an extra compilation step that generates source code, using the standard Java Annotation Processing Tool. So instead of runtime scanning you execute code based on the annotations generated during compile time.
I think the Bean/EBean annotation could work for you (only single class): https://github.com/excilys/androidannotations/wiki/Enhance%20custom%20classes
A scan-feature is not available, see this thread
3) Writing your own annotation processor
See APT (Annotation Processing Tool). The idea would be to generate a static function which returns a list of classes which are annotated, so that no class scanning is needed.
A very good ressource is http://javadude.com/articles/annotations/index.html
Take a look at Vogar's ClassPathScanner. It uses it to find test cases on the class path.
EDIT:
I found this issue in the Android issue tracker. It appears that ClassLoader.getResource(String) is 'working as expected', in that it returns null. This is expected because the DalvikVM does not keep the resources around after compiling. There are workarounds listed in the issue, but there may be another way to access the classes you desire.
Use the PackageManager to get a hold of an instance of ApplicationInfo. ApplicationInfo has a public field called sourceDir which is the full path (a String) to the location of the source directory for that application. Create a File from this String, and you should be able to navigate to your package within the source directory. Once there, you can use the method from my original answer to find the classes you are looking for.
String applicationSourceDir =
getPackageManager().getApplicationInfo(androidPackageName, 0).sourceDir;
/EDIT
You should be able to use the ClassLoader.getResource(String) to get a URL to your specific package (the passed in String being the package name you are interested in delimited by path separators rather than periods). With this URL you can then call getFile(), from which you can create a Java File to the package folder. Call packageFile.listFiles() from there, and you have your classes/subpackages.
Be recursive with the subpackages, and with the classes find the Class object using the static Class.forName(String) method.
In your java build process incorporate the class path scanning, generating injection data/code. This could then be ported too to Dalvik. It is even more efficient that dynamic scanning.

ServiceLoader to find implementations of an interface

I tried to use the Java ServiceLoader to find all classes that implement a specific interface like so:
loader = ServiceLoader.load(Operation.class);
try {
for (Operation o : loader) {
operations.add(o);
}
} catch (ServiceConfigurationError e) {
LOGGER.log(Level.SEVERE, "Uncaught exception", e);
}
Unfortunately, when I run Eclipse in debug mode the ServiceLoader doesn't find any classes. I feel like I'm missing a trivial point...
ServiceLoader cannot do it.
In order to expose class as a service that can be discovered by ServiceLoader you need to put its name into provider configuration file, as described in Creating Extensible Applications With the Java Platform
.
There are no built-in ways find all classes that implement a particular interface. Frameworks that can do something similar use their own classpath scanning solutions (and even with custom classpath scanning it's not easy because .class files only store information about interfaces implemented directly, not transitively).
If the implementations are ones that you wrote yourself, you could use AutoService to make them available through the ServiceLoader interface, eg
#AutoService(Operation.class)
class Foo implements FooInterface {
}
#AutoService(Operation.class)
class Bar extends Foo {
}
In order to scan your classpath at runtime for implementations of specific interface you would need to use different solution eg. Reflections (notice s on the end, this is not java's Reflection API)

Categories