Description of the issue:
As Jib handles /classes and /resources separately Weld is unable to reconcile the beans.xml and classes resulting in it not finding any. This is contrary to how a Jar archive and Maven would do this as they would be both placed into the same root file system rather than split.
Expected behavior:
Use single /classes directory by default as per Jar.
Steps to reproduce:
jib-maven-pluginEnvironment: Helidon 1.0.0, Maven 3.6, Jib 1.0.0
jib-maven-plugin Configuration:
TODO
Workaround:
Place beans.xml file in src/main/jib/app/classes/META-INF.
Hi @dansiviter,
Does Weld hard-code the directory /classes in its path? /resources will be under the JVM classpath, so for example, getResource("META-INF/beans.xml") and things like that should be able to read in beans.xml. (Are you using Java 11 by any chance?) Why should the class files and resources files be physically in the same directory? I don't know Weld, but this is a bit surprising to me.
So it appears Gradle has the same issue due to separating the /classes and /resources classpath entries:
There are some potential options which I'll explore but I think there is merit in making the Jib classpath more like a real Jar archive and using one classpath entry /classes.
I see what the underlying issue is with Weld. (To me, this had a better explanation for the core issue.) Certainly, it is technically possible to merge /classes and /resources in Jib, but similar to Gradle not supporting this, it makes me hesitate to make the move, especially given that there's a simple workaround of placing beams.xml at src/main/jib/app/classes/META-INF.
We will leave this issue open, but even if we consider doing this, I think this will be a very low priority.
I suppose it depends on if Jib is supposed to be replicating a Jar class archive or a build tool such as Gradle. If it's the former, then merging is conceptually closer to a single Jar. Although this was found with Weld, it's likely there will be others that rely on this behaviour.
@dansiviter I imagine it could also be an issue with Weld perhaps accessing this file with a certain expectation that cannot always be guaranteed. Could be helpful asking the Weld team why that file is where it is, and why it is being accessed in a way that is incompatible with jib?
if Jib is supposed to be replicating a Jar class archive or a build tool such as Gradle. If it's the former, then merging is conceptually closer to a single Jar.
@dansiviter Jib is opinionated to basically replace (runnable fat) JAR packaging and make it obsolete when it comes to containerizing an app. Jib doesn't make use of JAR or require you to build JAR. We basically don't have the intention to follow or mimic the JAR spec. See this comment for the intention, for example.
However, we've got many requests to directly support or embed a JAR, so we are considering the option to use the JAR as-is in Jib. This would probably be the option that is closest to what you want here.
@chanseokoh Embedded Jar would be great.
@loosebazooka I believe it's more to do with the CDI spec where it states:
A directory in the JVM classpath is a bean archive if it has a file named beans.xml in the META-INF directory.
See CDI 1.0 Section 12.1 Bean Archives
@dansiviter I guess my question is, when using getResourceAsStream you should be able to access the file whether it is in classes or not because they all have the exact same path on the classpath given how jib is defining the classpath.
for instance using:
SomeClass.class.getClassLoader().getResourceAsStream("/META-INF/beans.xml");
will work when I put beans.xml in both
src/main/resources/META-INF/beans.xml src/main/jib/app/classes/META-INF/beans.xmlWhat confuses me, and I'm curious why, is how is Weld reading this file that makes it incompatible with classpath stuff?
Ignore Weld for a moment. The CDI specification states "A directory in the JVM classpath...". As there are two directories, /classes and /resources, they _could_ have their own beans.xml file which relates to the beans within that directory hierarchy. This is to isolate the bean archive from other, potentially 3rd party Jar, archives that have their own beans.xml. getResourceAsStream(...) _can_ ignore which directory or Jar it finds that file effectively breaking the encapsulation. So, using the default Jib classpath of /app/resources:/app/classes:/app/libs/* these are all valid places for beans.xml:
/app/resources/META-INF/beans.xml
/app/classes/META-INF/beans.xml # this is separate to /app/resources/ as CDI treats JVM classpath directories as different bean archives
/app/lib/my.jar#META-INF/beans.xml
/app/lib/3rdParty.jar#META-INF/beans.xml
They all may exist and must all be resolvable.
Coming back to Weld, they are only correctly implementing the specification to which Jib and Gradle, by default, breaks.
I see, appreciate the explanation. It still feels strange that it would use the physical layout to make decisions. I guess you have your workaround for now. We'll take another look at CDI too.
Weld (and other CDI implementations) use
ClassLoader.getResources("META-INF/beans.xml")
This method returns an enumeration of URL of all such resources on the classpath. And CDI implementations have to depend on the classloader to be based on directories and jar files - and it simply uses the URL to access the underlying file system.
In case the beans.xml is found in directory resources, the CDI implementation is not capable of determining which classes belong to the bean archive, unless they are in the same directory.
v1.4.0 has been released with embedded JAR support!