Your achievements

Level 1

0% to

Level 2

Tip /
Sign in

Sign in to Community

to gain points, level up, and earn exciting badges like the new
Bedrock Mission!

Learn more

View all

Sign in to view all badges

SOLVED

How to add dependency independent of another bundle

Avatar

Level 2

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 

1 Accepted Solution

Avatar

Correct answer by
Level 2

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

 

View solution in original post

7 Replies

Avatar

Community Advisor

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

Avatar

Level 2

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

 

Avatar

Employee Advisor

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. 

 

 

 

Avatar

Level 2

Hello @Jörg_Hoh thanks for the reply but could you please explain in detail why the classes are leaking outside or give a scenerio for leaking.

Thanks 

Avatar

Correct answer by
Level 2

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

 

Avatar

Employee Advisor

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!