1

I am trying to load beans outside a war file. The goal is that is should be possible to change the jar file without a new war file.

My war file includes the external jar as a provided dependency:

        <dependency>
            <groupId>com.lube</groupId>
            <artifactId>foo</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>

I added the jar file into the applibs folder in the domain directory (domain/lib/applibs) and filled out the library field during the deployment.

payara deployment

It seems that no beans are loaded from this jar file (injection is not possible), but it is possible to use the class. (the class is available in the current classloader).

If i am injecting something in a class from the war file i am getting following exception UnsatisfiedResolutionException: WELD-001334: Unsatisfied dependencies for type XXX with qualifiers

I am using payara 4.1.2.174, but it doesn't work with payara 5 too.

The main question is: Should it be possible to load beans (ejb/cdi) outside the war? I don't find any good solution in the web.

P.S.: I can not use microservices ;)

Edit: The war file does not contain the jar file. The jar file is currently located in the domain under /lib/applibs ( I tested all other folders too )

The command how i did that was the following asadmin add-library --type app C:\library.jar

The library.jar contains only one CDI bean

@Model
public class CdiBean {
    public void test() {
        System.out.println("It works!");
    }
}

and the beans.xml file. (resources/META-INF - I tested it without the META-INF folder too)

The WAR file has a startup class which tries to load the Bean.

@Singleton
@Startup
@TransactionManagement(value = javax.ejb.TransactionManagementType.BEAN)
public class AppStartup {
    @PostConstruct
    public void postConstruct() {
        try {
            System.out.println(CdiBean.class);
            CDI.current().select(CdiBean.class).get().test();
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }
}

The output after the deployment of the war is:

[2020-01-21T13:47:36.413+0100] [Payara 4.1] [INFO] [] [] [tid: _ThreadID=103 _ThreadName=admin-thread-pool::admin-listener(3)] [timeMillis: 1579610856413] [levelValue: 800] [[   class com.lube.CdiBean]]

[2020-01-21T13:47:36.474+0100] [Payara 4.1] [SEVERE] [] [javax.enterprise.system.tools.deployment.common] [tid: _ThreadID=103 _ThreadName=admin-thread-pool::admin-listener(3)] [timeMillis: 1579610856474] [levelValue: 1000] [[
  Exception while invoking class org.glassfish.ejb.startup.EjbApplication start method
javax.ejb.EJBException: javax.ejb.CreateException: Initialization failed for Singleton AppStartup
    ...
Caused by: javax.ejb.CreateException: Initialization failed for Singleton AppStartup
    at com.sun.ejb.containers.AbstractSingletonContainer.createSingletonEJB(AbstractSingletonContainer.java:553)
    at com.sun.ejb.containers.AbstractSingletonContainer.access$000(AbstractSingletonContainer.java:82)
    at com.sun.ejb.containers.AbstractSingletonContainer$SingletonContextFactory.create(AbstractSingletonContainer.java:723)
    ... 72 more
Caused by: java.lang.IllegalStateException: WELD-001334: Unsatisfied dependencies for type CdiBean with qualifiers  
    ... 74 more
Caused by: org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001334: Unsatisfied dependencies for type CdiBean with qualifiers  
    ... 102 more
]]
lube
  • 133
  • 1
  • 1
  • 8
  • Yes it should: https://stackoverflow.com/questions/39112542/cdi-beans-inside-jar-are-not-found-by-the-container-unsatisfied-dependencies... From https://www.google.com/search?q=cdi+resolve+beans+in+different+jar+in+ear+site:stackoverflow.com – Kukeltje Jan 21 '20 at 12:18

2 Answers2

1

After 3 days of testing i found a solution - FINALLY :D I didn't find any solution so i searched in the payara github repo for "applibs" and i found following interessing class. appserver/web/weld-integration/src/main/java/org/glassfish/weld/DeploymentImpl.java

There is a method called private void processBdasForAppLibs( ReadableArchive archive, DeploymentContext context ) with a nice java doc.

 // These are application libraries that reside outside of the ear.  They are usually specified by entries
    // in the manifest.
    // to test this put a jar in domains/domain1/lib/applibs and in its manifest make sure it has something like:
    //                           Extension-Name: com.acme.extlib
    // In a war's manifest put in something like:
    //                           Extension-List: MyExtLib
    //                           MyExtLib-Extension-Name: com.acme.extlib

After i found that i added following plugin to the jar file:

            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Extension-Name>com.lube</Extension-Name>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>

and the following to the war file

            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.3</version>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Extension-List>ExternalLib</Extension-List>
                            <ExternalLib-Extension-Name>com.lube</ExternalLib-Extension-Name>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>

After that i build the jar and added it to the domain/lib/applibs. Than i deployed the war and everything works as expected!

lube
  • 133
  • 1
  • 1
  • 8
0
  • You can combine multiple wars into single ear and run it.
  • Or it might be possible to use add-library command. It was available for GlassFish Server, it is available for Payara Micro. I believe there should be such functionality (I could find it for Payara Server though).
y_ug
  • 904
  • 6
  • 8
  • If you combine multiple wars in an ear, the wars can still not 'see' eachother by default. Adding as a library is a very specific thing that should not be needed. https://stackoverflow.com/questions/39112542/cdi-beans-inside-jar-are-not-found-by-the-container-unsatisfied-dependencies – Kukeltje Jan 21 '20 at 12:18
  • @Kukeltje when you specify `provided` you indicate that it should be provided somehow at runtime. Answer from the link privided by you suggest using `beans.xml` to configure class loading. `add-library` allows to specify shared library 'provided' by your container. If all this does not fit you, you can try to load you classes [dynamically with URLClassLoader](https://stackoverflow.com/questions/24685807/classnotfoundexception-while-loading-a-class-from-file-with-urlclassloader/24685919#24685919) – y_ug Jan 21 '20 at 12:30
  • @Kukeltje I know that provided means, that the container should provide the "right" jar file. But that is my problem. The jar file is loaded, but the defined beans are no beans. ( can not be injected / i have a beans.xml ) – lube Jan 21 '20 at 12:48
  • But on-topic: I now see that OP is trying to get a shared jar out side a war AND outside an ear... Sorry. I was mislead by your first bullit here – Kukeltje Jan 21 '20 at 12:52
  • Oh and the `provided` was not mentioned by me anywhere... No idea where you got that from. – Kukeltje Jan 21 '20 at 12:53
  • @Kukeltje I marked the wrong person, sorry ;) I updated the question and added the current behaviour of the deployment. Maybe there is a bug in the payara. My next try is to use an ear file instead of the war file. Maybe it will work with that. – lube Jan 21 '20 at 12:56