What I have done so far is :
/** Default location of help files folder */
private static final String DEFAULT_PATH = "../../../../resources/files/help/";
/** A 404 error file */
private static final String ERROR_404 = "../../../../resources/files/help/404.html";
/**
* #param fileName
* #return The URL of file, if found at default location, otherwise a 404 error page URL.
*/
public static URL getURL(String fileName) throws MalformedURLException{
URL url = (new File(ERROR_404)).toURI().toURL();
System.out.println(url);
url = (new File(DEFAULT_PATH + fileName)).toURI().toURL();
System.out.println(url);
return url;
}
Output:
file:/H:/My%20Project/Project%20Name%20Module/../../../../resources/files/help/404.html
file:/H:/My%20Project/Project%20Name%20Module/../../../../resources/files/help/plazaCode.html
Folder Hierarchy in the JAR created through NetBeans:
I am on Windows 7, JDK 7.
UPDATE:
Actually I want this URL for a JTextPane to show a HTML page by method:
textPane.setPage(URL url);
Can I have any better solution than this? and with the same Folder Heirarchy.. ?
404.html since this is an application resource, it will probably end up embedded in a Jar.
Resources in archives cannot be accessed using a File object.
URL getURL(String fileName) To help avoid confusion, change that to URL getURL(String resourceName).
Use Class.getResource(String) much as discussed on your previous questions.
'Relative' URLs become dangerous by that stage, since they depend on the package of the class that calls them, I generally make them 'absolute' by prefixing the entire path with a single / which effectively means 'look for this resource, from the root of the run-time class-path'.
So that String might read (adjusting the rest of the code as already advised):
private static final String ERROR_404 = "/resources/files/help/404.html";
You can use URL url = getClass().getResource("..."). Probably "/files/help/404.html".
When you create a File in this way you will get a relative file (and therefore a relative URL). To get a absolute URL from that path you need to get an absolute File first.
Try this:
new File(ERROR_404).getCanonicalFile().toURI().toURL()
(EDIT: After you JTextPane information above)
I haven't ever tried this, so I have no clue on why that's not working. But its a different question, you should ask a new Question.
Related
For some reason I keep getting an NPE in a gradle javafx project.
My folder structure is very basic. I have a package with my java files in the main/java folder. I also have my resources in the main/resources folder. When I try to load image.png it gives me an NPE.
public static Image createImage(Object context, String url) {
Image m = null;
InputStream str = null;
URL _url = context.getClass().getResource(url);
try {
m = new Image(_url.getPath());
} catch (NullPointerException e) {
e.printStackTrace();
}
return m;
}
This is a helper class.
From the Scene I call: Image image = Helper.createImage(this, "image.png");
The absolute path to the image would be main/resources/images/image.png.
I checked every tutorial on the internet but I couldn't find any solution for this. I also tried it with the path to the image as parameter and also with an InputStream but it never worked.
Resources
The Class#getResource(String) and related API are used for locating resources relative to the class path and/or module path. When using Class to get a resource you can pass an absolute name or a relative name. An absolute name will locate the resource relative to the root of the class path/module path; an absolute name starts with a /. A relative name will locate the resource relative to the location of the Class; a relative name does not start with a leading /.
In a typical Maven/Gradle project structure, the src/main/java and src/main/resources are roots of the class path/module path. This means all resource names are relative to those directories. It's slightly more complicated than that because the files under those directories are moved to the target/build directory and it's that location that's put on the class path/module path, but for all intents and purposes consider the source directories as the root. There's a reason a get-resource API exists in the first place, to provide an application-location-independent way of obtaining resources.
Issues in Your Code
From your question I gather your project structure looks something like:
<project-dir>
|--src/
|--main/
|--java/
|--resources/
|--images/
|--image.png
And you're calling your method with an Object and a resource name of image.png. The problem here is that, since you're passing a relative name, the resource is located relative to the Class of the passed Object (i.e. context). I doubt your class is located in a package named images which means the resource will not be found relative to said class. You need to pass an absolute name: /images/image.png.
The other problem is your use of URL#getPath(). The URL you obtain from Class#getResource(String) will, if the resource were to be found, look something like this:
file:/path/to/gradle/project/build/resources/main/images/image.png
But the result of URL#getPath() will give you:
/path/to/gradle/project/build/resources/main/images/image.png
This causes a problem due to the way Image works. From the documentation:
All URLs supported by URL can be passed to the constructor. If the passed string is not a valid URL, but a path instead, the Image is searched on the classpath in that case.
Notice the second sentence. If the passed URL does not have a scheme then it's interpreted as a resource name and the Image will locate the image file relative to the classpath. In other words, since you're passing the value of URL#getPath() to the Image constructor it searches for the resource image.png in the package path.to.gradle.project.build.resources.main.images. That package does not exist. You should be passing the URL as-is to the Image constructor via URL#toString() or URL#toExternalForm().
Solution
If you're going to use the URL returned by Class#getResource(String) to load the Image then no matter what you need to use URL#toString() or URL#toExternalForm() instead of URL#getPath().
public static Image createImage(Object context, String resourceName) {
URL _url = context.getClass().getResource(resourceName);
return new Image(_url.toExternalForm());
}
Then you have at least two options:
Pass the absolute resource name (i.e. "/images/image.png") to your #createImage(Object,String) method since the image.png resource is not in the same package as the passed Object (i.e. context).
Move the resource to the same package as the class of the passed in Object (i.e. context). For instance, if the context object's class is com.foo.MyObject then place the resource under src/main/resources/com/foo and it will be in the same package as MyObject. This will allow you to continue passing the relative resource name.
Of course, as noted by the documentation of Image you can pass a scheme-less URL and it's interpreted as a resource name. In other words, you could do:
Image image = new Image("images/image.png");
And that should work. A note of caution, however: When using modules the above will only work if the resource-containing package is opens unconditionally or if the module itself is open.
Try using the path /images/image.png.
The resources always get referenced from the class root, in your case src/main/resources, so from there going to /images/image.png should be the correct path.
this is how I am passing the images in my application. ivSerialAssignmentLogo is a FXML element (ImageView).
ivSerialAssignmentLogo.setImage(new Image(getClass().getResourceAsStream("/img/serialAssignment.svg")));
In your case, you could use something like that
public static Image createImage(Object context, String url) {
Image m = null;
InputStream str = null;
URL _url = context.getClass().getResource("/images/" + url);
try {
m = new Image(_url.getPath());
} catch (NullPointerException e) {
e.printStackTrace();
}
return m;
}
I've implemented a class to read from RSS 2.0 and Atom 1.0 feeds. I want to write some unit tests in order to verify functionality. Here is the feed reader section of my code:
private String readFeed(final String url) throws IOException
{
final StringBuilder builder = new StringBuilder();
final URL feedUrl = new URL(url);
final BufferedReader in = new BufferedReader(
new InputStreamReader(feedUrl.openStream()));
String input;
while ((input = in.readLine()) != null)
{
builder.append(input);
}
in.close();
return builder.toString();
}
After some research, I figured the best way to test would be to have a sample feed as an XML file in my project resources directory.
I've created a example file "resources/rss2-0.xml"
I'm sending in the following value to the readFeed function, "resource:///rss2-0.xml",
and I keep receiving java.net.MalformedURLException: unknown protocol: resource
This is my first time using a URL pathway to load from a resource. From what I can tell, resource seems like it should be a valid protocol. Anyone have any ideas what I may be doing wrong or other ways to go about this?
If you want to deal with path using your local file system, the Path class is best suited for this task.
An object that may be used to locate a file in a file system. It will
typically represent a system dependent file path.
You can use it like so :
Path path = FileSystems.getDefault().getPath("/resources/rss2-0.xml");
BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);
If your really want to deal with URL, the protocol you're looking for is simply "file". So it would be file:///rss2-0.xml instead of resource:///rss2-0.xml and even file:/resources/rss2-0.xml to be exact.
Note that in your case, you will indeed have to deal with URLs sooner or later, but when working on local tests, using the Path class will save you troubles. If you want another alternative, try the URI class. Since an URI is an identifier (see difference between URI and URL) it can identify either an URL or a Path an may serve as a bridge between your production code which will ultimately deal with URLs and your test code where the Path class could be best put in use.
For example :
public interface FeedReader {
String readFeed(final URI uri);
}
And 2 implementations, one for testing locally :
public class LocalFeedReader implements FeedReader {
#Override
public String readFeed(final URI uri) {
// URI -> Path
// then dealing with Path to target local rss2-0.xml file
}
}
And one for production code :
public class WebFeedReader implements FeedReader {
#Override
public String readFeed(final URI uri) {
// URI -> URL
// then dealing with URL to target real resources
}
}
The java docs say that only http, https, file, and jar are "guaranteed" to exist on the search path for protocol handlers. Others only "may" be supported.
http://docs.oracle.com/javase/8/docs/api/java/net/URL.html#URL-java.lang.String-java.lang.String-int-java.lang.String-
It looks like if you want a custom handler that isn't supported in your java distribution, you'll have to create one.
http://mjremijan.blogspot.com/2012/02/create-your-own-java-url-handlers.html
OK. So I have a pretty simple question: I want to be able to load a resource (a whole folder) from inside a running .jar file, but I have not been able to get it to work. This is what I have tried (if the class name were "myClass" and the folder being called "myFolder"), but it always throws a NullPointerException:
URL folderURL = myClass.class.getClassLoader().getResource("myFolder/");
String folderPath = folderURL.getPath();
File myFolder = new File(folderPath);
The NullPointerException is always thrown before I create "myFolder".
Some more info: I have to access the folder from static context. The class that is accessing the folder is NOT in the same directory as the folder itself is in. (The folder is in the root directory inside the jar, the class is a couple subpackages down.)
Does anyone have a solution to my problem? Sorry if I used wrong terminology :P, but anything you can do to help is appreciated.
There's no way this will work. You're trying to create a File object from a resource inside a JAR. That isn't going to happen. The best method to load resources is to make one your package folders a resource folder, then make a Resources.jar in it or something, dump your resources in the same dir, and then use Resources.class.getResourceAsStream(resFileName) in your other Java class files.
If you need to 'brute force' the subfiles in the JAR directory pointed to by the URL given by getResource(..), use the following (although it's a bit of a hack!). It will work for a normal filesystem too:
/**
* List directory contents for a resource folder. Not recursive.
* This is basically a brute-force implementation.
* Works for regular files and also JARs.
*
* #author Greg Briggs
* #param clazz Any java class that lives in the same place as the resources you want.
* #param path Should end with "/", but not start with one.
* #return Just the name of each member item, not the full paths.
* #throws URISyntaxException
* #throws IOException
*/
String[] getResourceListing(Class clazz, String path) throws URISyntaxException, IOException {
URL dirURL = clazz.getClassLoader().getResource(path);
if (dirURL != null && dirURL.getProtocol().equals("file")) {
/* A file path: easy enough */
return new File(dirURL.toURI()).list();
}
if (dirURL == null) {
/*
* In case of a jar file, we can't actually find a directory.
* Have to assume the same jar as clazz.
*/
String me = clazz.getName().replace(".", "/")+".class";
dirURL = clazz.getClassLoader().getResource(me);
}
if (dirURL.getProtocol().equals("jar")) {
/* A JAR path */
String jarPath = dirURL.getPath().substring(5, dirURL.getPath().indexOf("!")); //strip out only the JAR file
JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
Set<String> result = new HashSet<String>(); //avoid duplicates in case it is a subdirectory
while(entries.hasMoreElements()) {
String name = entries.nextElement().getName();
if (name.startsWith(path)) { //filter according to the path
String entry = name.substring(path.length());
int checkSubdir = entry.indexOf("/");
if (checkSubdir >= 0) {
// if it is a subdirectory, we just return the directory name
entry = entry.substring(0, checkSubdir);
}
result.add(entry);
}
}
return result.toArray(new String[result.size()]);
}
throw new UnsupportedOperationException("Cannot list files for URL "+dirURL);
}
You can then modify the URL given by getResource(..) and append the file on the end, and pass these URLs into getResourceAsStream(..), ready for loading. If you didn't understand this, you need to read up on classloading.
It's pretty simple:
getClass().getResourceAsStream("/resources/images/myImage.png")
Would return an input stream which can be used like so:
Image myImage = ImageIO.read(getClass().getResourceAsStream("/resources/images/myImage.png"));
And from there, use your Image how you like. This also works just as well if you're using the input stream to read a text file, or for pretty much whatever else you're doing.
Edit:
The path above is relative to the .jar's root.
I think I am on to something. In Eclipse, make a new source folder named "resources" and in that folder, create a package named "myFolder". To have a Path to "myFolder", you just have to say:
Path path = Paths.get(Main.class.getResource("/myFolder").toURI()); // or the class name instead of Main
Up until now (December 2017), this is the only solution I found which works both inside and outside the IDE (Using PathMatchingResourcePatternResolver): https://stackoverflow.com/a/47904173/6792588
I am creating a Swing application with a JEditorPane that should display an HTML file named url1.html stored locally in the page folder in the root folder of the project.
I have instantiated the following String object
final String pagePath = "./page/";
and in order to be displayed by the JEditorPane pane I have created the following URL object:
URL url1 = new URL("file:///"+pagePath+"url1.html");
However when the setPage() method is called with the created URL object as a parameter:
pagePane.setPage(url1);
it throws me a java.io.FileNotFoundException error.
It seems that there is something wrong with the way url1 has been constructed. Anyone knows a solution to this problem?
The solution is to find an absolute path to url1.html make an object of java.io.File on it, and then use toURI().toURL() combination:
URL url1 = (new java.io.File(absolutePathToHTMLFile)).toURI().toURL();
Assuming if the current directory is the root of page, you can pass a relative path to File:
URL url1 = (new java.io.File("page/url1.html")).toURI().toURL();
or
URL url1 = (new java.io.File(new java.io.File("page"), "url1.html")).toURI().toURL();
But this will depend on where you run the application from. I would make it taking the root directory as a command-line argument if it is the only configurable option for the app, or from a configuration file, if it has one.
The another solution is to put the html file as a resource into the jar file of your application.
To load a resource from the classpath (as khachik mentioned) you can do the following:
URL url = getClass().getResource("page/url1.html");
or from a static context:
URL url = Thread.currentThread().getContextClassLoader().getResource("page/url1.html");
So in the case above, using a Maven structure, the HTML page would be at a location such as this:
C:/myProject/src/main/resources/page/url1.html
I would try the following
URL url = new URL("file", "", pagePath+"url1.html");
I believe by concatenating the whole string, you are running into problems. Let me know, if that helped
I wrote a little Java servlet that would dynamically generate an image button given parameters including label, height, width and so on, and it would add each new one to a cache. It worked fine, BUT it required a servlet call for every call to display the button or its highlighted version. I dumped the cache and made PNG files of all the buttons used at the moment in the app, added those files to the app so they could be referenced by "/images/button/xyz.png", where the filename is a hash of the input parameters.
That works fine, but I want my original servlet to be called on the occasion when someone has added a new button. I use a custom tag to define these buttons, so the tag handler gets called when the JSP compiles... so I have a point where I can choose to use one of the pre-generated buttons, OR generate a reference to the servlet so it can render the button when it is displayed.
My question is: How can I detect the image is available in pre-rendered for? I'm not sure that a call to create a URL object based off the full path and then doing a call to getResource() is the answer -- I don't want it to load the image at this time, I just need to know if it exists.
Is there some way to create a File object that would take a relative URI and allow me to test for existence?
I suppose you are talking about the getResource() method on java.lang.Class . This is actually well-suited to the problem since by contract, it will return null if no resource exists with the given path. The resource isn't actually loaded until you use getResourceAsStream() (or similar) so this is not a performance concern.
You can try the following approach in a utility class.
public static boolean imageExists(final String imageFileName) throws Exception{
boolean status = false;
HttpURLConnection conn = null;
URL url = new URL(imageFileName);
conn = (HttpURLConnection )url.openConnection();
conn.setRequestMethod("HEAD");
String contentType = conn.getContentType();
if(contentType.contains("image")){
status = true;
}else{
status = false;
}
return status;
}
This assumes your image file names are unique.