Hello community,
I want to add a dependency specifically webp-imageio-sejda in my current project (project A), for this jar to be available to my bundle I have to embed it. In my AEM instance there already exist a bundle (project B) which already contains the same dependency and it is also embedded into that bundle.
Project A pom.xml :
.....
<Embed-dependency> webp-iamgeio </Embed-dependency>
......
<dependencies>
<!-- https://mvnrepository.com/artifact/org.sejda.imageio/webp-imageio -->
<dependency>
<groupId>org.sejda.imageio</groupId>
<artifactId>webp-imageio</artifactId>
<version>0.1.6</version>
<scope> provided </scope>
</dependency>
</dependencies>
Project B pom.xml
.....
<Embed-dependency> webp-iamgeio </Embed-dependency>
......
<dependencies>
<!-- https://mvnrepository.com/artifact/org.sejda.imageio/webp-imageio -->
<dependency>
<groupId>org.sejda.imageio</groupId>
<artifactId>webp-imageio</artifactId>
<version>0.1.6</version>
<scope> provided </scope>
</dependency>
</dependencies>
The problem is when I deploy my bundle (Project A) and run any service which is using a class (WebPWriteParam) from webp-imageio-sejda I am facing an error
java.lang.ClassCastException: class com.luciad.imageio.webp.WebPWriteParam cannot be cast to class com.luciad.imageio.webp.WebPWriteParam
This is because I have same JAR embedded in two different bundles. (Project A and Project B). I cannot Edit the POM of Project B.
Any idea How can I resolve this issue.
One solution I found that I can upload jar as an bundle and use that in both the bundles without embedding but I cannot edit the POM in the second bundle to remove embedding.
Thanks
@Jörg_Hoh @smacdonald2008 @arunpatidar @Sham_HC @Niall_O_Donovan @Lokesh_Shivalingaiah
Solved! Go to Solution.
Views
Replies
Total Likes
Hello @SantoshSai @Jörg_Hoh Thanks for your positive response. I have found a solution for my issue.
The problem was in obtaining writer. The ServiceRegistry keep records of all service providers ie the implementations of ImageWriter class. In my case the WebPWriter is registered twice as I have embedded the JAR in two bundles, so when I am getting the writer as below I am getting two writers [I thought I will get one writer as the others will be not reachable as per OSGI concept], one which is loaded from classloader of Project A and one which is loaded from classloader of Project B.
When I use the writer loaded with classloader of Project B I am getting the exception.
// Obtaining a WebP ImageWriter instance ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/webp").next();
For resolving this issue, I have just changed the way of getting writer. I have iterated over list of writer and used writer which is loaded by my current bundle's classloader.
// Obtain a WebP ImageWriter instance ImageWriter webPWriter = null; Iterator<ImageWriter> writers = ImageIO.getImageWritersByMIMEType("image/webp"); while(writers.hasNext()){ ImageWriter tempWriter = writers.next(); // MyClass is class in which I am writing this method if(tempWriter.getClass().getClassLoader() == MyClass.class.getClassLoader()){ webPWriter = tempWriter; break; } }
Please suggest if you have any better approach.
Thanks
Hi @vishnu_jangid ,
I believe you have to export content once you embed to your jar, please check here recently where I did it same:https://github.com/sansai2011/server-target/pull/1/files#diff-8d04401f1cc51365fe3e32f019cd720135ba92...
hope that helps you!
Regards,
Santosh
Hello @SantoshSai ,
I did not get what exactly you are talking about. Can you please elaborate.
Thanks
Hello @SantoshSai ,
I have exported the content only once. I have not added the class into Export-Package. I have only embedded the JAR. But the JAR is embedded into two different bundles which are on same AEM instance.
Thanks
This ClassCastException comes from the fact, that Bundle A and Bundle B ship with distinct copies of these classes (embedded into their respective JARs), but then references to these classes are passed between code of Bundle A and Bundle B. The classes are identical, but their unique IDs (which is a combination of fully qualified class name + ID of the classloader) is not.
The problem you are facing is that these classes are somehow leaking outside of the scope of the bundles. Meaning if your bundle embeds a JAR, it should not reveal any reference to these embedded classes through its API, either implicit or explicit.
If you cannot avoid that these APIs expose instances of these classes or references to them, you have to make this JAR public and accessible to all consumers; and the best case is to wrap them into a dedicated OSGI bundle and make them public. That would require changes at least to the bundle which currently ships with this embedded JAR.
If you cannot make these changes I don't see a clean way how you could fix it.
Hello @SantoshSai @Jörg_Hoh Thanks for your positive response. I have found a solution for my issue.
The problem was in obtaining writer. The ServiceRegistry keep records of all service providers ie the implementations of ImageWriter class. In my case the WebPWriter is registered twice as I have embedded the JAR in two bundles, so when I am getting the writer as below I am getting two writers [I thought I will get one writer as the others will be not reachable as per OSGI concept], one which is loaded from classloader of Project A and one which is loaded from classloader of Project B.
When I use the writer loaded with classloader of Project B I am getting the exception.
// Obtaining a WebP ImageWriter instance ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/webp").next();
For resolving this issue, I have just changed the way of getting writer. I have iterated over list of writer and used writer which is loaded by my current bundle's classloader.
// Obtain a WebP ImageWriter instance ImageWriter webPWriter = null; Iterator<ImageWriter> writers = ImageIO.getImageWritersByMIMEType("image/webp"); while(writers.hasNext()){ ImageWriter tempWriter = writers.next(); // MyClass is class in which I am writing this method if(tempWriter.getClass().getClassLoader() == MyClass.class.getClassLoader()){ webPWriter = tempWriter; break; } }
Please suggest if you have any better approach.
Thanks
That is quite hacky, and it does not scale (meaning that this will be tough work if you do that for more than one class).
But it's fine if it works for you. I hope that you don't run into other issues with that approach!
Views
Likes
Replies
Views
Likes
Replies