Java casting / classloader issues

2019-02-18 14:28发布

问题:

Here is the simplified version of the problem:

 SomeClass c = (SomeClass) obj.getSomeClassParent()

not always but it happens sometimes to trigger exception

 org.somepackage.SomeClass can't be cast to org.somepackage.SomeClass 

How is this possible ? I suppose it has something to do with the fact that JAI imageio is native lib, but relay how can this happen ? I'm probably missing something but what ?

I'm using JAI imageio version 1.1 
dcm4che 2.0.21  DICOM lib

Here is the original code

  ImageInputStream iis = ImageIO.createImageInputStream(src);
  Iterator<ImageReader> iter = ImageIO.getImageReadersByFormatName("DICOM");
  ImageReader reader = iter.next();
  DicomImageReadParam param = (DicomImageReadParam) reader.getDefaultReadParam();

And the original exception

org.dcm4che2.imageio.plugins.dcm.DicomImageReadParam can't be cast to    
org.dcm4che2.imageio.plugins.dcm.DicomImageReadParam

Exception Image http://img215.imageshack.us/img215/3894/exception.jpg

回答1:

I think it can happen if

  1. a SomeClass instance was loaded from ClassLoader X (so its class is SomeClass of CL X or let's call it: CL(X).SomeClass)
  2. but it is being cast in a different class loader. E.g. the current Threads class loader is Y so SomeClass is actually CL(Y).SomeClass

So you have:

  • instance class = CL(X).SomeClass
  • class cast target = CL(Y).SomeClass

Or in other words - not the same class - thus the class cast exception.


Possible duplicate of: ClassCastException when casting to the same class - it has some good suggestions as well.



回答2:

i would guess that you have a problem due to the mismatch between classloaders and native libraries. native libraries are loaded and associated with a classloader, however, the programs can only really load one instance of a native library. so, if you load the native lib in classloader A, and classes which it outputs will be associated with classloader A. if you later load the same native library in classloader B, you aren't really loading it again, and it will still be passing out classes for classloader A. so, either you redeployed your webapp, or you have 2 webapps in the same webserver which use the same native library.

if possible, you should try to put the native library in the base classpath of the webserver, so that it will be loaded by the base classloader, and thus be usable by any webapp. if you can't do this, and the problem is only a redeployment issue, then you might want to undeploy and wait a bit before redeploying (in theory, the native lib will be unloaded when the classloader with which it is associated is GCed, but of course, this can take an unknown amount of time).



回答3:

Strange have you tried casting it to a Object it extends, not sure if it has the functionality you require but might be worth trying to see if it still throws the exception.



回答4:

From the image I see that it looks like a web application. I read 'catalina'. So there is a big chance, that it is a pure classloading problem.

It could happen, for example, if the ImageReader you get from the ImageIO class was loaded by a different classloader (maybe because it's deployed in a different webapp), so the DicomImageReadParam object returned by the getDefaultReadParam() method is an instance of a - technically spoken - different class.