I'm using :
PathMatchingResourcePatternResolver rr = new ...;
rr.getResources("classpath*:**/*.class")
to get all the classes from the classpath that is made of directories and jars. The call returns only classes from the directories; JAR files are ignored. The following call returns classes from JARs :
rr.getResources("classpath*:org/**/*.class")
Is that possible to get all the classes without knowing the base package name ?
It is mentioned in the documentation that when using "classpath*:" prefix along with ant-style patterns atleast one root directory needs to be mentioned before the patterns starts and that it is a limitation in the JDK's ClassLoader.getResources() method. If the root directory is not mentioned then it retrieves files from the root of the expanded directories only.
So unfortunately you are out of luck here.
Related
I am trying to enumerate classes in the package with
Enumeration<URL> resourceUrls = myObject.getClassLoader().getResources("path/to/my/package/");
while (resourceUrls.hasMoreElements()) {
...
Unfortunately it returns nothing. Why?
Assuming path is correct. Path starts with no slash and ends with slash. There are several public classes under path.to.my.package package.
I took this code from Spring.
You cannot walk a class path like you can walk a file path. Walking a file path is done on the file system, which does not apply to a class path.
While a java class path entries are formed like file paths and usually are folders and files (either on the file system or inside a JAR archive), it does not necessarily have to be that way. In fact, the classes of one single package may originate from various locations of differing nature: one might be loaded from a local JAR file while another one might be loaded from a remote URL.
The method ClassLoader.getResources() exists to provide access to all "occurrences" of a resource if it has the same name in different JAR files (or other locations). For example you can use
ClassLoader.getSystemClassLoader().getResources("META-INF/MANIFEST.MF");
to access the manifest file of each JAR file in your class path.
Try with
Enumeration<URL> urls = ClassLoader.getSystemClassLoader().getResources("path/to/my/package");
while (urls.hasMoreElements()) {
System.out.println(urls.nextElement());
}
I have a set of codes which are common for two different products, but a part of the code is behaving differently for each product
URL wsdlURL = IntegrationLandscapeService.class.getClassLoader().getResource("IntegrationLandscapeService.wsdl");
For One set up it is giving absolute path and for the other its giving relative path and this is leading to problems, my requirement is to get absolute path for the issue.
Packaging:
Code flow:
The call is made from the Main Class File and from there CommonCode in common code it is looking for the WSDL located in LandScapeService.jar
Update:
The next line of the code is
IntegrationLandscapeService landscapeService = new IntegrationLandscapeService(wsdlURL);
but I get the below error
failed [Failed to access the WSDL at: jar:file:/
tracker.jar!/lib/t24-IF_IntegrationLandscapeService-IntegrationLandscapeService-jwc.jar!/IntegrationLandscapeService.wsdl
.It failed with:
\tracker.jar (The system cannot find the file specified).]
Screen Shot of Jar
The error shows two '!' in the path which indicates the resource is in an embedded/nested/inner jar-file. A product that uses the fat/bundled-jar approach (where one jar-file contains other jar-files) will need some trickery to load classes and resources from the embedded jar-files. You can read about it at http://www.jdotsoft.com/JarClassLoader.php (*)
In any case, there is not much you can do about it since loading resources from embedded jars is not supported natively by Java. The implementation providing the "trickery" I mentioned above will need to fix that (and some do it better than others, see the link above).
The other product with a Par-file indicates the use of OSGi which only requires proper configuration to keep resource-loading working. There is an answer here that explains your situation and solution options.
(*) Spring-boot also has some good documentation and a solution, but I have not tried using the solution with a non-Spring application. See https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html for more information.
You can use getAbsolutePath
File file = new File(url.getPath());
String path = file.getAbsolutePath();
Isn't that what you are looking for?
This is because the files inside the JAR are not treated as regular files, as they are not expanded and not available directly to file explorer.
In Jar, if the files are referred, you will get the path from the root of the JAR file.
Please make sure you have the classpath entry for the Jar location. This will help to find the resource. Otherwise, try the following code(not sure whether it will work in your case, give it a try).
String resource = "/com/example/IntegrationLandscapeService.wsdl"; //package structure of the file
URL res = IntegrationLandscapeService.class.getResource(resource);
Refer this answer to understand more Stack Overflow comment
So for our test structure we currently have a base module in which we have some of our common configuration files etc (example: ds.properties). Now I'm currently running tests in a different module and I'm trying to load all .properties files (to get all the configurations) and I was using
(new PathMatchingResourcePatternResolver(getClass().getClassLoader())).getResources("classpath:*.properties")
Now this is only finding alpha.properties (the property file in my module). Is there a way to get the property files in all modules?
Some stuff I have already tried:
(new PathMatchingResourcePatternResolver(getClass().getClassLoader())).getResources("classpath:ds.properties")
Returns the ds.properties that I want but obviously not auth.properties.
(new PathMatchingResourcePatternResolver(getClass().getClassLoader())).getResources("classpath*:*.properties")
Again only alpha.properties
(new PathMatchingResourcePatternResolver(getClass().getClassLoader())).getResources("classpath*:**/*.properties")
Returns alpha.properties and a bunch of .properties files from the jre that I do not want.
I'm too lazy atm to find the reference in the documentation, but it's essentially this:
Top-level classpath-scan is not finding all resources matching a pattern. The reason is written in the docs.
Put your property files in a package (src/main/resources/somefolder for maven) and adapt your scan path to it and it should work as expected. (classpath*:somefolder/*.properties)
For completeness: From the docs
Please note that classpath*: when combined with Ant-style patterns will only work reliably with at least one root directory before the pattern starts, unless the actual target files reside in the file system. This means that a pattern like " classpath*:*.xml" will not retrieve files from the root of jar files but rather only from the root of expanded directories. This originates from a limitation in the JDK’sClassLoader.getResources() method which only returns file system locations for a passed-in empty string (indicating potential roots to search).
Ant-style patterns with " classpath:" resources are not guaranteed to find matching resources if the root package to search is available in multiple class path locations. This is because a resource such as
com/mycompany/package1/service-context.xml
may be in only one location, but when a path such as
classpath:com/mycompany/**/service-context.xml
is used to try to resolve it, the resolver will work off the (first) URL returned by getResource("com/mycompany");. If this base package node exists in multiple classloader locations, the actual end resource may not be underneath. Therefore, preferably, use " classpath*:" with the same Ant-style pattern in such a case, which will search all class path locations that contain the root package.
I am looking to create a hierarchy based on the Spring configurations. The simplest form is several "core" libraries and several "custom" projects that are able to override the beans in the "core" libraries.
When running very simply unit tests via Maven the "core" configuration isn't able to found causing the test to fail.
final Resource[] resources = applicatonContext.getResources("classpath*:core-*spring.xml");
Returns nothing. It isn't able to find the expected core-one-spring.xml or core-two-spring.xml that are located in my custom projects core dependencies.
Isn't it default behavior of Spring to look into the JARs on the classpath as well? Or is there something special I have to do?
When I run in my IDE (IntelliJ) the tests pass perfectly because the entire project is loaded and they are just files that Spring can find.
UPDATE
Spring is able to find the files if I add them explicitly without wildcards.
#ContextConfiguration({"classpath:core-one-spring.xml", "classpath:core-two-spring.xml", "classpath:custom-spring.xml", "classpath:test-spring.xml"})
or
final Resource[] resources = custom.getResources("classpath:core-one-spring.xml");
From the manual
Please note that " classpath*:" when combined with Ant-style patterns will only work reliably with at least one root directory before the pattern starts, unless the actual target files reside in the file system. This means that a pattern like " classpath*:*.xml" will not retrieve files from the root of jar files but rather only from the root of expanded directories. This originates from a limitation in the JDK’s ClassLoader.getResources() method which only returns file system locations for a passed-in empty string (indicating potential roots to search).
In my OSGi bundle (an eclipse plugin) I can query class entries at certain paths using something like:
bundle.findEntries("<class_directory>/<package_name_as_url>/", "*.class", true)
For example, if my classes are in the bin directory in my bundle, and I want to find all classes in the package mypackage, then I could write the path as the string "/bin/mypackage/", producing this:
bundle.findEntries("/bin/mypackage/", "*.class", true)
However, I have not managed to do the same when the classes are packaged in a jar inside my bundle. For example, if the jar is myJar.jar inside the folder 'lib', how I could query all the classes in it? I tried with these alternatives without any success:
bundle.findEntries("/lib/myJar.jar!/", "*.class", true)
bundle.findEntries("/lib/myJar.jar/", "*.class", true)
If using strings for writing the paths will not work for resources inside JARs, then how I could query the entries in my bundle that are children of a given resource URL, instead of using a plain string like "/bin/mypackage/" or "/lib/myJar.jar!/" as shown in the examples above? (such URL points to the JAR I need to query).
I know I can use:
JarFile jarFile = (JarFile) resolvedURL.getContent();
and then
jarFile.entries()
to get the entries in a Jar, but I am not happy with this solution since: 1) I would like to find a generic way to ask for bundle resources independently if they are in a JAR or not (not funny polluting the code with if conditions). 2) With that solution I cannot automatically filter the resources using a pattern, like "*.class".
Thanks in advance for any help or feedback!
UPDATE:
Apparently there is not a simple/efficient way to do this (!) - though I would love to be wrong about that -. I found here a discussion about how to convert a URL in an IPath:
http://www.eclipse.org/forums/index.php/mv/tree/88506/#page_top
(in the discussion they suggest to use Platform.asLocalURL().getPath(), that happens to be deprecated by now, I tried with the equivalent FileLocator.toFileURL().getPath instead)
Once you have the IPath you could use FileLocator.findEntries(bundle, path) to get the children entries from the URL. The problem of this approach is that apparently if the resource you need to query is inside a jar (as in my case), Eclipse will copy it somewhere in your operative system.
In addition of this being a potential bottleneck for your application, FileLocator.findEntries(bundle, path) will fail given that the path is not anymore a real path of the bundle, but the path of a cached directory somewhere in the OS.
I am surprised there is not a direct way to accomplish this.
A better solution is to use the new BundleWiring.listResources method. This method will search the bundle classpath including jar files for resources such as .class files.