How to add dependency independent of another bundle | Adobe Higher Education
Skip to main content
vishnu_jangid
Level 2
September 28, 2022
Respondido

How to add dependency independent of another bundle

  • September 28, 2022
  • 2 respostas
  • 2461 Visualizações

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

 

@joerghoh @smacdonald2008 @arunpatidar @sham_hc @niall_o_donovan @lokesh_shivalingaiah 

Este tópico foi fechado para respostas.
Melhor resposta por vishnu_jangid

Hello @santoshsai @joerghoh 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

 

2 Respostas

SantoshSai
Community Advisor
Community Advisor
September 28, 2022

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-8d04401f1cc51365fe3e32f019cd720135ba920a1a7da7f19e9c9208478701fc

hope that helps you!

Regards,

Santosh

Santosh Sai
vishnu_jangid
Level 2
September 29, 2022

Hello @santoshsai ,

 

I did not get what exactly you are talking about. Can you please elaborate.

Thanks

joerghoh
Adobe Employee
Adobe Employee
October 3, 2022

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. 

 

 

 

vishnu_jangid
vishnu_jangidAutorResposta
Level 2
October 6, 2022

Hello @santoshsai @joerghoh 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

 

joerghoh
Adobe Employee
Adobe Employee
October 6, 2022

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!