-1

I don't get it - I'm trying to get the path of a file so that the file (an image) can be included as an attachment in an email.

My system consists of two parts - a web app and a jar. (actually three parts - a common shared jar containing DAOs etc.)

They're both built using maven. They both contain this image in this path:

src/main/resources/logo_48.png

WebApp:

String logo1 = getClass().getClassLoader().getResource("logo_48.png").getPath();

This works perfectly - both on local (Windows) and Linux

Jar Application:

String logo1 = getClass().getClassLoader().getResource("logo_48.png").getPath();    //doesn't work

I've taken advice from here: How to access resources in JAR file? here: Reading a resource file from within jar here: http://www.coderanch.com/t/552720/java/java/access-text-file-JAR

and others

Most answers offer to load the file as a stream etc. but I'm only wishing to get the path assigned to the String. Other resources have led me to hacking the code for hours only to find the end result doesn't work.

After so many instances of /home/kalton/daily.jar!logo_48.png does not exist errors I was frustrated and settled on the following workaround:

Copy the logo_48.png directly to the folder where the jar resides (/home/kalton/)

Alter my jar application code to:

String logo1 = "/home/kalton/logo_48.png";

And it works.

Could anyone show me the right way to get the PATH (as a String) of a file in the resources folder from a JAR that is not unpacked? This issue was driving me crazy for weeks! Thanks in advance. KA.

Adding actual use code of 'path' for clarity of use:

public static MimeMultipart assemble4SO(String logoTop, String emailHTMLText) throws MessagingException, IOException {
    MimeMultipart content = new MimeMultipart("related");
    String cid = Long.toString(System.currentTimeMillis());
    String cidB = cid + "b";
    String cssStyle = "";

    String body = "<html><head>" + cssStyle + "</head><body><div>" + "<img src='cid:" + cid + "'/>" + emailHTMLText + "<img src='cid:" + cidB + "'/></div></body></html>";
    MimeBodyPart textPart = new MimeBodyPart();

    textPart.setContent(body, "text/html; charset=utf-8");
    content.addBodyPart(textPart);

    //add an inline image
    MimeBodyPart imagePart = new MimeBodyPart();
    imagePart.attachFile(logoTop);
    imagePart.setContentID("<" + cid + ">");
    imagePart.setDisposition(MimeBodyPart.INLINE);
    content.addBodyPart(imagePart);

.............

Community
  • 1
  • 1
Ken Alton
  • 686
  • 1
  • 9
  • 21
  • I recommend you stop taking advice from coderanch.com. 98% of the answers there are utterly wrong. – VGR Mar 05 '16 at 17:33
  • 1
    You can't get the file path of a resource in a jar file, because a resource in a jar file is not a file on the file system. It's a zip entry. Why do you need this path? Which API do you use to send an email and create an attachment? What is your code? – JB Nizet Mar 05 '16 at 17:36

1 Answers1

1

From the top…

A .jar file is actually a zip file. A zip file is a single file that acts as an archive. The entries in this archive are not separate files, they're just sequences of compressed bytes within the zip file. They cannot be accessed as individual file names or File objects, ever.

Also important: The getPath method of the URL class does not convert a URL to a file name. It returns the path portion of the URL, which is just the part after the host (and before any query and/or fragment). Many characters are illegal in URLs, and need to be “escaped” using percent encoding, so if you just extract the path directly from a URL, you'll often end up with something containing percent-escapes, which therefore is not a valid file name at all.

Some examples:

String path = "C:\\Program Files";

URL url = new File(path).toURI().toURL();
System.out.println(url);            // prints file:/C:/Program%20Files
System.out.println(url.getPath());  // prints /C:/Program%20Files

File file = new File(url.getPath());
System.out.println(file.exists());  // prints false, because
                                    // "Program%20Files" ≠ "Program Files"

 

String path = "C:\\Users\\VGR\\Documents\\résumé.txt";

URL url = new File(path).toURI().toURL();

// Prints file:/C:/Users/VGR/Documents/r%C3%A9sum%C3%A9.txt
System.out.println(url);

// Prints /C:/Users/VGR/Documents/r%C3%A9sum%C3%A9.txt
System.out.println(url.getPath());

File file = new File(url.getPath());
System.out.println(file.exists());  // prints false, because
                                    // "r%C3%A9sum%C3%A9.txt" ≠ "résumé.txt"

Based on your edit, I see that the real reason you want a String is so you can call MimeBodyPart.attachFile. You have two options:

  1. Do the work of attachFile yourself:

    URL logo = getClass().getLoader().getResource("logo_48.png");
    imagePart.setDataHandler(new DataHandler(logo));
    imagePart.setDisposition(Part.ATTACHMENT);
    
  2. Copy the resource to a temporary file, then pass that file:

    Path logoFile = Files.createTempFile("logo", ".png");
    try (InputStream stream =
        getClass().getLoader().getResourceAsStream("logo_48.png")) {
    
        Files.copy(stream, logoFile, StandardCopyOption.REPLACE_EXISTING);
    }
    imagePart.attachFile(logoFile.toFile());
    

As you can see, the first option is easier. The second option also would require cleaning up your temporary file, but you don't want to do that until you've sent off your message, which probably requires making use of a TransportListener.

VGR
  • 40,506
  • 4
  • 48
  • 63