Same code behaving differently on two different packaging - java

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

Related

java.nio.file.InvalidPathException with getPath

I am using this code
String path = getClass().getResource("Template.xls").getPath();
When I run it on my machine (windows), everything is good. I even did system.out.println on the get resource part and on the get path part and the results were:
file:/C:/Eclipse/Netbeans/SoftwareCom/build/classes/assets/Template.xls
/C:/Eclipse/Netbeans/SoftwareCom/build/classes/assets/Template.xls
However I am getting the following error reports from some users
java.nio.file.InvalidPathException: Illegal char <:> at index 4:
file:\C:\Software%20Com\SoftwareCom.exe!\assets\Template.xls
Iam not sure whats happening or why would it work for some and not others
Any pointers?
To answer this question properly, it would be helpful to know what you want to do with the path information. To read the file, you don't need the path.
You could just call
getClass().getResourceAsStream("Template.xls")
If you really want to know the path, you should call
URL url = getClass().getResource("Template.xls");
Path dest = Paths.get(url.toURI());
This might cause problems as you seem to pack your java files in a windows executable. See Error in URL.getFile()
Edit for your comment:
As I wrote above, you don't need the path of the source to copy. You can use
getClass().getResourceAsStream("Template.xls")
to get the content of the file and write the content to whereever you want to write it. The reason for failing is that the file in your second example is contained within an executable file:
file:\C:\Software%20Com\SoftwareCom.exe
as can be seen from the path:
file:\C:\Software%20Com\SoftwareCom.exe!\assets\Template.xls
The exclamation mark indicates that the resource is within that file.
It works within Netbeans because there the resource is not packed in a jar, but rather is a separate file on the filesystem.
You should try to run the exe-version on your machine. It will most likely fail as well. If you want more information or help, please provide the complete code.
I faced this same issue and go around it by using the good ol' File API
URL url = MyClass.class.getClassLoader().getResource("myScript.sh");
Path scriptPath = new File(url.getPath()).toPath();
And it worked!

Load files dynamically in multiple environments

so I am in the process of making a small application.
Right now, the project works fine. I am running it through an IDE. The problem comes about when trying to run the project as a jar - which is the end result. Right now, it fails to properly load the required files (classes and simple ASCII files).
The method I am using is one based off of:
final Enumeration<URL> paths = CLASS_LOADER.getResources("");
Where CLASS_LOADER is an instance of class.getClassLoader().
This works great when not inside a jar. Inside a jar though, it seems to fail horribly. For example, in the code above, paths would be empty.
I am assuming that the fault is that the files are all within a jar - the same jar to be precise.
The class path for the manifest file is blank at the moment.
If it helps, I have two tasks that require loading files.
I need to create a list of all files that are a subclass of
another class.
I need to load a list of language files (all of
which are in the same directory).
If you need anything else to help debug this problem or provide a solution - let me know. Thanks for reading this!
For ClassLoader.getResources() to work you need to feed a path relative to the jar root. If you want to search the jar then ClassLoader public API won't help you. You have to use custom code based on java.util.jar.JarFile, like the one here.

Intellij can't find .png

My intellij can't find local .png images.
private String craft = "craft.png";
ImageIcon ii = new ImageIcon(this.getClass().getResource(craft));
The .png is located in the same directory as the java files. I don't understand why it isn't working. Using maven build, tried alternating from resources to java, but still no luck :(
craft.png must be placed into src/main/resources, otherwise it will be not copied to the classpath according to the Maven rules. See this answer for more details.
Your code should be also changed to:
private String craft = "/craft.png";
Here is the sample working project.
Go to your IntelliJ Preferences and search for "resource patterns" (or just go straight to the "Compiler" settings).
IntelliJ will only copy certain resources to the output directory. Make sure the resource pattern includes *.png.
I have my resource pattern set to !*.java (copy everything that's not a source file) which seems to work fine (and should really be the default, in my opinion).
tried alternating from resources to java
So at first you tried putting craft.png into src/main/resources. That is where it must be put according to Maven (not in src/main/java).
But it didn't work because
this.getClass().getResource("craft.png") tries to find "craft.png" relative to the this.class's package. If your this.class is in package foo.bar then you must put craft.png in src/main/resources/foo/bar/
You can also provide an absolute path in getResource() by using a leading slash /. For example put craft.png into a custom folder under resources src/main/resources/customFolder/ and read it with the leading slash / in front of customFolder:
this.getClass().getResource("/customFolder/craft.png")
If you don't use leading slash in getResource() method then internally class's package name is prepended to the resource name to make it absolute.
This behavior is explained in Class.getResource()

ClassLoader loading the wrong instance of a file

So I see there has already been a post very similar to this issue, however I am in a situation where I have no power to specify the location of this file within my jar and so am hoping someone is aware of a solution to get around this.
So I currently use the following snippet to obtain a file as an input stream, the file 'plugin.xml' is located at the root of the jar and I cannot change this location as another piece of software (dynatrace) creates this file and determines its location.
the standard snippet:
InputStream is = JmxPlugin.class.getResourceAsStream("/plugin.xml");
Now I am aware that the issue is that the ClassLoader is picking up the first file which matches the name 'Plugin.xml' along the classpath (one which isn't in my jar, yay).
Can anyone think of a way to ensure I pick up the correct file without having to move it? The relative path of my class in the jar is com/something/jmx/JmxPlugin.class.
(Id rather not have to unpack the jar in memory).
Many thanks for any contributions,
I'm not absolutely sure, but seems like Thread.currentThread().getContextClassLoader().getResourceAsStream("/plugin.xml") may solve your issue. If not, you'll have to create your own ClassLoader and resolve the issue there.
The simplies way is to move your jar in classpath to be the first containing Plugin.xml,
Another approach is to use getResource() to locate your jar file:
URL myJar=JmxPlugin.class.getResource("/"+JmxPlugin.class.getName().replace(".","/")+".class");
then use this URL to open jar file and extract Plugin.xml.

loading from JAR files during deployment vs development

when i am loading some data into my java program, i usually use FileInputStream. however i deploy the program as a jar file and webstart, so i have to use getRessource() or getRessourceAsStream() to load the data directly from the jar file.
now it is quite annoying to always switch this code between development and deployment?
is there a way autmate this? i.e. is there a way to know if the code is run from a jar or not?
when i try to load it withoug jar like this:
InputStream is = this.getClass().getResourceAsStream("file.txt");
the returned inputstream is simply null, although the file is definitely in the root directory of the application.
thanks!
Why do you use FileInputStream during development? Why not just use getResourceAsStream from the very start? So long as you place your files in an appropriate place in your classpath, you shouldn't have any problems. It can still be a file in the local filesystem rather than in a jar file.
It's helpful to develop with the final deployment environment in mind.
EDIT: If you want something in the root directory of your classpath, you should either use:
InputStream x = getClass().getResourceAsStream("/file.txt");
or
InputStream x = getClass().getClassLoader().getResourceAsStream("file.txt");
Basically Class.getResourceAsStream will resolve relative resources to the package containing the class; ClassLoader.getResourceAsStream resolves everything relative to the "root" package.
You could read your data always as a ressource. You only have to add the path where the data lies to your classpath.
If your data stays in WEB-INF/somewhere/mydata.txt inside your jar file, you will access it with:
getClass().getResourceAsStream( "/WEB-INF/somewhere/mydata.txt" )
Now, if you create a development directory /devel/WEB-INF/somewhere/mydata.txt and put /devel to your classpath, your code will work in development and production.
EDIT after explanation in question:
In your case this.getClass().getResourceAsStream( "mydata.txt" ) the resource is taken from the same position where the classfile of this is taken from. If you want to keep this, then you have to create a directory /devel/<path of package>/mydata.txt and again add /devel to your classpath.
How about setting a system property in your dev environment, via the -D switch? e.g. java -D:mypropertyname=mypropertyvalue
You could set the property in ant scripts in your dev environment, other environments don't get the property:
e.g.
public static boolean isDevEnvironment(){ return System.getProperty("mypropertyname")!=null;}
You might find a better way to hack it from one of the existing System Properties
If a file is considered part of your deployed application (as opposed to be part of the installation specific files) and can be located through the classpath then consider simply always using getResourceAsStream since it works regardless of the actual deployment scheme as long as it is in the classpath.
You might also find the information available from the JVM relevant (if allowed by the security manager):
// Get the location of this class
Class cls = this.getClass();
ProtectionDomain pDomain = cls.getProtectionDomain();
CodeSource cSource = pDomain.getCodeSource();
URL loc = cSource.getLocation(); // file:/c:/almanac14/examples/
http://www.exampledepot.com/egs/java.lang/ClassOrigin.html?l=rel
There shouldn't be any difference between development vs deployment, IHMO.
Classloader.getResource or getResourceAsStream works well, you can read resources and even write them.You can write your own Protocol handles and access everything as an URL/URI, which allows you to read and write resources and also allows proper identification of who actually provide the resource.
The only problem is if an URLStreamHandlerFactory is already registered(in a J2EE application the container could install a factory and you don't have any way to go over and install your own) and you cannot use your handlers "anywhere".
Knowing that, it is preferred to implement your own "resources". At that time when I need it I couldn't find something like that so I had to implement my own ResourceManager. For me it looks more intuitive to access a resource like
Resource layout = ResourceManager.resolve("view://layout/main.jsp")
instead of
URL layout = Classloader.getResource("some_package/view/layout/main.jsp")

Categories

Resources