Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible/how to embed and access HTML Files in a JAR?

i am somewhat blocked right now: i wrote a quite complex Java Desktop App (no Applet/Web App!) which has it's own "user Manual". This manual consists of some HTML and JPG files. This manual is displayed in the "Help Menu" within my application using a JEditorPane.

So far so good. This works very well as long as i launch the Programm with Eclipse. As soon as i create the deploy Version as a runable jar (which gets wrapped into an .exe with launch4j) the HTML "Viewer" is unable to display the user manual (the Images are missing).

I do understand why this is happening, but i have no idea on how to fix/circumvent this.

My application loads its ressources (properties Files, Icons, etc.) via getClass().getResource(). Examples:

this.setIconImage(new ImageIcon(getClass().getResource("/images/dialog-question.png")).getImage());

stream = new BufferedInputStream(MABIUpdater.class.getResourceAsStream("/settings.properties"));

Like i said before, this does work very well (launching the App from within Eclipse OR as a wrapped executable or runnable-jar.

So i tried to access my HTML "Manuals" like this, too:

File manual = new File(getClass().getResource("/manual/help.html").toURI());

jEditorPane.setPage(manual.toURI().toURL());

This does NOT really work. Launching the programm through Eclipse i see the Manual but with missing images. Launching it via jar/exe i get an empty frame.

So is there any "trick" on how to achieve this? I guess one problem is the HTML Page itself because it can't access the linked images within that jar. Here is an really small example a HTML file that does not work (missing image):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html lang="de">
    <head>
        <title>Manual</title>
    </head>
    <body>
        <h1>Example: </h1>
        <p>fubar</p>
        <img style="display: block; text-align: center;" src="../manual/img/Shot01.png" width="666" height="644" border="0" alt="Bildtext">
        <p><a href=\"http://www.google.com/\">blablubb</a></p>
    </body>
</html>

I hope my problem is clear and someone has an idea ;).

Edit: all the required HTML files and Images are in the JAR file/classpath. (just to make this clearer)

like image 425
Ulathar Avatar asked Aug 26 '13 11:08

Ulathar


People also ask

How do I access files inside a jar?

You could use something like this: InputStream is = this. getClass(). getClassLoader().

How can I access a folder inside of a resource folder from inside my JAR file?

What you could do is to use getResourceAsStream() method with the directory path, and the input Stream will have all the files name from that dir. After that you can concat the dir path with each file name and call getResourceAsStream for each file in a loop.

Can JAR files be read?

To view individual files in a non-executable jar file, you can obtain compression/decompression software that works with jar files. We recommend using either 7-Zip or WinRAR. Once you have installed this software, run the software, open the jar file, and extract the files contained in it.


1 Answers

File manual = new File(getClass().getResource("/manual/help.html").toURI());

That is where it goes wrong. Java cannot create a File object from an embedded-resource

Keep it as an URL and use that for setPage(..).


As to the more general problem.

HTML from a Jar file that links resources (e.g. CSS or images) by relative references will work just fine.

E.G.

This example loads HTML (that has a relative reference to an image) from a Jar.

import javax.swing.*;
import java.net.URL;

class ShowHtml {

    public static void main(String[] args) {
        final String address =
            "jar:http://pscode.org/jh/hs/object.jar!/popup_contents.html";
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    URL url = new URL(address);
                    JEditorPane jep = new JEditorPane(url);
                    JFrame f = new JFrame("Show HTML in Jar");
                    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    f.add(new JScrollPane(jep));
                    f.pack();
                    f.setSize(400,300);
                    f.setLocationByPlatform(true);
                    f.setVisible(true);
                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

Screenshot

JEditorPane displaying Jar'd HTML

HTML

The HTML that is being loaded.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<!--       
 *        Copyright (C) 1997  Sun Microsystems, Inc
 *                    All rights reserved.
 *          Notice of copyright on this source code 
 *          product does not indicate publication. 
 * 
 * RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by 
 * the U.S. Government is subject to restrictions as set forth 
 * in subparagraph (c)(1)(ii) of the Rights in Technical Data
 * and Computer Software Clause at DFARS 252.227-7013 (Oct. 1988) 
 * and FAR 52.227-19 (c) (June 1987).
 *
 *    Sun Microsystems, Inc., 2550 Garcia Avenue,
 *    Mountain View, California 94043.
 *
-->
<HTML>
<HEAD>
<TITLE>
Editing Project Attributes
</TITLE>
</HEAD>
<BODY BGCOLOR="#ffffff">
<IMG SRC="images/popup_icon.gif" width="24" height="24"> <b>Popup Window</b>
<p>
Popup windows appear near the location from which they are
activated.  They are not contained in frames and thus
cannot be resized or moved by the user.  Popups are
dismissed by clicking anywhere in the help viewer.
<p>
Popup windows can be activated by clicking on a text object, 
graphic object, or JComponent button.  All three examples are
included in this demo.
<p>
<A HREF="popup_contents2.html">More...</A>
</body>
</html>

E.G. 2

For dynamically created HTML, the JRE will probably use the class file's location as the presumed location of the HTML. But to remove all doubt, we can specify the base element in the head.

import javax.swing.*;

class HtmlUsingBase {

    public static void main(String[] args) {
        final String htmlContent =
            "<html>" +
            "<head>" +
            "<base href='http://www.gravatar.com/'>" +
            "</head>" +
            "<body>" +
            "<h1>Image path from BASE</h1>" +
            "<img src='avatar/a1ab0af4997654345d7a9" +
            "49877f8037e?s=128&d=identicon&r=PG'" +
            " width='128' height='128'>" +
            "</body>" +
            "</html>";
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JLabel label = new JLabel(htmlContent);
                JOptionPane.showMessageDialog(null, label);
            }
        });
    }
}

Screenshot

enter image description here

like image 120
Andrew Thompson Avatar answered Oct 19 '22 02:10

Andrew Thompson