How to create an instance of ImageIcon - java

I'm trying to create an instance of ImageIcon according to the instructions here (http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html)
/** Returns an ImageIcon, or null if the path was invalid. */
protected ImageIcon createImageIcon(String path,
String description) {
java.net.URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL, description);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
I have the image in the same folder as the java class, but it returns "Couldn't find file: .....". What should I do?

Class.getResource() is for accessing stuff via classloader, e.g. things in the same jar as your application.
To access a file from filesystem create URL from file, e.g. new File(path).toURI().toURL();

Related

Android CRUD MediaStore API 26+

I have an application for API26+
With Android 10 and above (API29+) should be used MediaStore to access files, instead of Environment.getExternalStoragePublicDirectory
normally making of new approach would be maked in creation of if-block
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
// deprecated code
} else {
// new approach
}
But:
MediaStorage use Uri to request a file. API28 and below works with File or String as path to file
With MediaStore manually creation of a folder is not needed. API 28 and below should create a folder if not exists.
Deleting of Files requires User interaction with MediaStore.
CRUD:
Create: To write data in File for any API is OutputStream required. That could be reached with if else
Read: How to create general approach to read a File, where API 29+ needs Uri, and API28- needs File|String to access a file?
Update: first Read to check if exists, then Create to get OutputStream
Delete: How to create a batch confirmation with MediaStore?
Is it possible to work with MediaStorage with API26+?
If yes, how? Many properties are added first in API29
After some own research and testing i have found the way to work with MediaStore and on old devices in same time.
First of all some helper classes needed:
With FileType we can support different file types in application at same time.
public enum FileType {
File(Environment.DIRECTORY_DOCUMENTS, Constants.VERSION_29_ABOVE ? MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) : null, "text/plain"),
Download(Environment.DIRECTORY_DOWNLOADS, Constants.VERSION_29_ABOVE ? MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL) : null, "text/plain"),
Image(Environment.DIRECTORY_PICTURES, Constants.VERSION_29_ABOVE ? MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) : null, "image/jpeg"),
Audio(Environment.DIRECTORY_MUSIC, Constants.VERSION_29_ABOVE ? MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) : null, "audio/mpeg"),
Video(Environment.DIRECTORY_MOVIES, Constants.VERSION_29_ABOVE ? MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) : null, "video/mpeg");
private final String directory;
private final Uri contentUri;
private String mimeType;
FileType(String directory, Uri contentUri, String mimeType) {
this.directory = directory;
this.contentUri = contentUri;
this.mimeType = mimeType;
}
public String getDirectory() {
return directory;
}
public Uri getContentUri() {
return contentUri;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
}
with setMimeType we can change current file extension and still use other settings
And we need simple callback class to get different results
public interface ObjectCallback<T> {
void result(T object);
}
When we want write some data in a file, we need an OutputStream
With internal storage, the way to get a file has not changed
/**
* opens OutputStream to write data to file
*
* #param context activity context
* #param fileName relative file name
* #param fileType file type to get folder specific values for access
* #param fileStream callback with file output stream to requested file
* #return true if output stream successful opened, false otherwise
*/
public boolean openOutputStream(Context context, String fileName, FileType fileType, ObjectCallback<OutputStream> fileStream) {
File internalFolder = context.getExternalFilesDir(fileType.getDirectory());
File absFileName = new File(internalFolder, fileName);
try {
FileOutputStream fOut = new FileOutputStream(absFileName);
fileStream.result(fOut);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
By external storage, the way to access a file on API 28- and API 29+ is completely different.
On API 28- we could just use a file for it.
On API 29+ we shoould first check, if file already exists. If it (say text.txt) exists and we would make ContentResolver.insert, it would create text-1.txt and in worst case (endless loop) in could quick fill whole smartphone storage.
/**
* #param context application context
* #param fileName relative file name
* #return uri to file or null if file not exist
*/
public Uri getFileUri(Context context, String fileName) {
// remove folders from file name
fileName = fileName.contains("/") ? fileName.substring(fileName.lastIndexOf("/") + 1) : fileName;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
// Deprecated in API 29
File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), Constants.PUBLIC_STORAGE_FOLDER);
File file = new File(storageDir, fileName);
return file.exists() ? Uri.fromFile(file) : null;
} else {
String folderName = Environment.DIRECTORY_PICTURES + File.separator + Constants.PUBLIC_STORAGE_FOLDER + File.separator;
// get content resolver that can interact with public storage
ContentResolver resolver = context.getContentResolver();
String selection = MediaStore.MediaColumns.RELATIVE_PATH + "=?";
String[] selectionArgs = new String[]{folderName};
Cursor cursor = resolver.query(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL), null, selection, selectionArgs, null);
Uri uri = null;
if (cursor.getCount() > 0) {
while (cursor.moveToNext()) {
String itemFileName = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME));
if (itemFileName.equals(fileName)) {
long id = cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
uri = ContentUris.withAppendedId(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL), id);
break;
}
}
}
cursor.close();
return uri;
}
}
/**
* opens OutputStream to write data to file
*
* #param context activity context
* #param fileName relative file name
* #param fileType file type to get folder specific values for access
* #param fileStream callback with file output stream to requested file
* #return true if output stream successful opened, false otherwise
*/
public boolean openOutputStream(Context context, String fileName, FileType fileType, ObjectCallback<OutputStream> fileStream) {
// remove folders from file name
fileName = fileName.contains("/") ? fileName.substring(fileName.lastIndexOf("/") + 1) : fileName;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), Constants.PUBLIC_STORAGE_FOLDER);
if (!storageDir.exists() && !storageDir.mkdir()) {
// directory for file not exists and not created. return false
return false;
}
File file = new File(storageDir, fileName);
try {
FileOutputStream fOut = new FileOutputStream(file);
fileStream.result(fOut);
} catch (Exception e) {
e.printStackTrace();
return false;
}
} else {
// get content resolver that can interact with public storage
ContentResolver resolver = context.getContentResolver();
// always check first if file already exist
Uri existFile = getFileUri(context, fileName);
if (existFile == null) {
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.MIME_TYPE, fileType.getMimeType());
// absolute folder name
values.put(MediaStore.MediaColumns.RELATIVE_PATH, fileType.getDirectory() + File.separator + Constants.PUBLIC_STORAGE_FOLDER);
// file name
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
// create uri to the file. If folder not exists, it would be created automatically
Uri uri = resolver.insert(fileType.getContentUri(), values);
// open stream from uri and write data to file
try (OutputStream outputStream = resolver.openOutputStream(uri)) {
fileStream.result(outputStream);
// end changing of file
// when this point reached, no exception was thrown and file write was successful
values.put(MediaStore.MediaColumns.IS_PENDING, false);
resolver.update(uri, values, null, null);
} catch (Exception e) {
e.printStackTrace();
if (uri != null) {
// Don't leave an orphan entry in the MediaStore
resolver.delete(uri, null, null);
}
return false;
}
} else {
// open stream from uri and write data to file
try (OutputStream outputStream = resolver.openOutputStream(existFile)) {
fileStream.result(outputStream);
} catch (Exception e) {
e.printStackTrace();
// Don't leave an orphan entry in the MediaStore
resolver.delete(existFile, null, null);
return false;
}
}
}
return true;
}
In same way could be opened InputStream on all devices and different storage.
To delete file:
internal could be still deleted with file.delete on every API
external storage with API29+ requires user interaction to delete some file
FileProvider
To use Intent for showing some picture, crop picture or whatever, where we use setDataAndType
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(photoUri, "image/*");
// allow to read the file
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
we need in some cases the FileProvider. Specially:
To show external file created with the app, the photoUri would look this way
Uri photoUri = Constants.VERSION_29_ABOVE ? uriToFile :
FileProvider.getUriForFile(context,
context.getApplicationContext().getPackageName() + ".provider",
new File(uriToFile.getPath()));

Problems creating a icon

I have problems trying to create an ImageIcon for my project. My createImageIcon method goes as follows ::
protected ImageIcon createImageIcon(String path, String description)
{
java.net.URL imgURL = getClass().getResource(path);
if (imgURL != null)
{
return new ImageIcon(imgURL, description);
}
else
{
System.err.println("Couldn't find file: " + path);
return null;
}
}
And the line that creates the Icon ::
ImageIcon icon = createImageIcon("**ICON URL***","Java");
Unfortunately, I cannot create any Icon because all the URLs I enter are not found (the file is not found). Could someone please tell me how to get the URL of an image found online that will work and will fit for this method? Thanks.

Variable path for file storage based on a user's group

I am working on an application that allows users to upload files. I want to keep the uploaded files organized into pre-created folders named for the group that the user belongs to. I can't seem to find a way to make the path editable so that I can pass the group's name into the method as a parameter and have the file stored in that directory.
Here's my latest attempt that results in a "Failed to store file file] with root cause" exception.
#Service
public class StorageServiceImpl implements StorageService {
#Value("${upload.path}")
private Path path;
public void uploadFile(MultipartFile file,String contentName, String groupName){
//make so that files are stored in path/groupname
this.path = Paths.get(this.path.toString() +"/"+groupName +"/");
String filename = contentName+"-"+StringUtils.cleanPath(file.getOriginalFilename());
System.out.println("\n\n\n\n\n"+filename + "\n\n\n");
try {
if (file.isEmpty()) {
throw new StorageException("Failed to store empty file");
}
if (filename.contains("..")) {
// This is a security check
throw new StorageException(
"Cannot store file with relative path outside current directory "
+ filename);
}
try (InputStream inputStream = file.getInputStream()) {
System.out.println("\n\n\n\n\n"+this.path.resolve(filename) + "\n\n\n");
Files.copy(inputStream, this.path.resolve(filename), StandardCopyOption.REPLACE_EXISTING);
}
}catch (IOException e) {
String msg = String.format("Failed to store file %s", file.getName());
throw new StorageException(msg, e);
}
}
}
Note: If the directory of the groupName is created before this method runs (as I intend to have it created when the group is created) then the method attempts to store the file in another directory of the same name inside that directory such as:
backend/src/main/webapp/WEB-INF/TestGroup/TestGroup/test.jpg
See how TestGroup shows up twice
Instead of doing this, here you are trying to inject value to a varible of type Path.
#Value("${upload.path}")
private Path path;
how about reading the value to a String variable and storing it as a File and then using it to upload like below,
#Value("${upload.path}")
private String path;
And then using it
public void uploadFile( MultipartFile file, String contentName, String groupName )
{
String filename = contentName + "-" + StringUtils.cleanPath( file.getOriginalFilename() );
// use a File object here
File uploadFilePath = Paths.get( new File( path ).getPath() + "/" + groupName + "/" + filename ).toFile();
try
{
try( InputStream in = file.getInputStream(); OutputStream out = new FileOutputStream( uploadFilePath ) )
{
// Leverage the support of Spring's FileCopyUtils Here
FileCopyUtils.copy( in, out );
}
catch( IOException ex )
{
throw new RuntimeException( ex );
}
}
catch( IOException e )
{
String msg = String.format( "Failed to store file %s", file.getName() );
throw new StorageException( msg, e );
}
}
I got it working by using the absolutePath method from the private Path path to generate the string.
public void uploadFile(MultipartFile file,String contentName, String groupName){
//make so that files are stored in path/groupname
String filename = contentName+"-"+StringUtils.cleanPath(file.getOriginalFilename());
File uploadFilePath = Paths.get(this.path.toAbsolutePath() + "/" + groupName+"/" + filename).toFile();
try {
if (file.isEmpty()) {
throw new StorageException("Failed to store empty file");
}
if (filename.contains("..")) {
// This is a security check
throw new StorageException(
"Cannot store file with relative path outside current directory "
+ filename);
}
try (InputStream inputStream = file.getInputStream();OutputStream out = new FileOutputStream(uploadFilePath);) {
FileCopyUtils.copy(inputStream,out);
}
}catch (IOException e) {
String msg = String.format("Failed to store file %s", file.getName());
throw new StorageException(msg, e);
}
}

How to get the path of the document inside .jar in spring boot? [duplicate]

This question already has answers here:
Can't Access Resources In Executable Jar
(4 answers)
Closed 3 years ago.
I'm running spring boot application with a jar file.
This application sends a mail alond with attachment. The attachment is the part of the jar file. I'm using the code below to fetch the attachment. I have referred this link Classpath resource not found when running as jar
public boolean sendEmail(String content, String subject, String from, String to, String cc, boolean isAttach, List<String> attachFiles, Session session) {
try {
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from, "XXX"));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
if(cc!=null && !cc.equals("")) {
message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc));
}
message.setSubject(subject);
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(content, "text/html; charset=utf8");
// creates multipart
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
if (isAttach) {
// adds attachments
if (!attachFiles.isEmpty()) {
for (String filePath : attachFiles) {
try {
ClassPathResource classPathResource = new ClassPathResource("Brochure.pdf");
InputStream inputStream = classPathResource.getInputStream();
MimeBodyPart attachPart = new MimeBodyPart();
attachPart.attachFile(IOUtils.toString(inputStream));
multipart.addBodyPart(attachPart);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
// sets the multipart as email's content
message.setContent(multipart);
Transport.send(message);
System.out.println("sent email for " + to);
return true;
} catch (MessagingException | UnsupportedEncodingException e) {
System.out.println("email sending failed for " + to);
e.printStackTrace();
// throw new RuntimeException(e);
return false;
}
}
I'm using the getInputStream() function itself in order to search for the file inside the jar file. But I'm getting the following error:
javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.FileNotFoundException: Invalid file path
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1365)
at javax.mail.Transport.send0(Transport.java:255)
at javax.mail.Transport.send(Transport.java:124)
at com.inversation.app.integration.service.mail.clients.GenericMailClient.sendEmail(GenericMailClient.java:95)
at com.inversation.app.jobs.CronJob.executeInternal(CronJob.java:62)
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: java.io.FileNotFoundException: Invalid file path
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:152)
at javax.activation.FileDataSource.getInputStream(FileDataSource.java:110)
at javax.activation.DataHandler.writeTo(DataHandler.java:318)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1694)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:996)
at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:561)
at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:84)
at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:901)
at javax.activation.DataHandler.writeTo(DataHandler.java:330)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1694)
at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1913)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1315)
... 7 more
Before podting this question here i have done research my myside, but still not able to solve the problem. Any help would be appreciated.
I'm able to solve the issue by using below code. Hope it helps others. Refer this issue - Similar issue
attachPart.setDataHandler(new DataHandler(new ByteArrayDataSource(this.getClass().getResourceAsStream("/"+filePath),"application/pdf")));
(Caution: You are hard-coding "Brochure.pdf", and ignoring filePath entirely in your loop. I shall assume you meant to attach each value of filePath.)
As you can see in the documentation for the attachFile method, the String argument must be a valid file name.
Converting the bytes in an InputStream to a String certainly will not result in a file name.
A resource in a .jar is not a file. It’s part of a .jar file, not a separate file.
You will need to set the MimeBodyPart’s content and file name manually, instead of using attachFile:
URL content = GenericMailClient.class.getResource("/" + filePath);
attachPart.setDataHandler(new DataHandler(content));
URI uri = content.toURI();
String path = uri.getPath();
String fileName = path.substring(path.lastIndexOf('/') + 1);
attachPart.setDisposition(Part.ATTACHMENT);
attachPath.setFileName(fileName);
(Do not attempt to use the getFile() method of URL. The getFile() method will not return a valid file name, both because the URL won’t be a file: URL, and because characters which are not allowed to appear directly in URLs (like spaces) will be percent-escaped. On the other hand, the URI class properly parses URI components and returns their unescaped forms.)
I Guess, You need to change the way of reading file using springs ResourceUtils from class path in spring boot application as:
File file = ResourceUtils.getFile("classpath:Brochure.pdf");
InputStream in = new FileInputStream(file);
I am sure, it will work for you
I have used this below code in my projects. Basically, what I do is scan the whole classpath for the file intended if I don't have the exact path. This is to help me in making sure that I don't need to have the file in a specific path.
This is because I encountered the same error as you when I use this line.
getClass().getClassLoader().getResource("Brochure.pdf")
So, I created two functions that takes a filename, and the classpaths included in the jar and recursively searched for the file.
private static File findConfigFile(String paths, String configFilename) {
for (String p : paths.split(File.pathSeparator)) {
File result = findConfigFile(new File(p), configFilename);
if (result != null) {
return result;
}
}
return null;
}
private static File findConfigFile(File path, String configFilename) {
if (path.isDirectory()) {
String[] subPaths = path.list();
if (subPaths == null) {
return null;
}
for (String sp : subPaths) {
File subPath = new File(path.getAbsoluteFile() + "/" + sp);
File result = findConfigFile(subPath, configFilename);
if (result != null && result.getName().equalsIgnoreCase(configFilename)) {
return result;
}
}
return null;
} else {
File file = path;
if (file.getName().equalsIgnoreCase(configFilename)) {
return file;
}
return null;
}
}
Here is an example of my code in action:
import java.io.File;
public class FindResourcesRecursive {
public File findConfigFile(String paths, String configFilename) {
for (String p : paths.split(File.pathSeparator)) {
File result = findConfigFile(new File(p), configFilename);
if (result != null) {
return result;
}
}
return null;
}
private File findConfigFile(File path, String configFilename) {
if (path.isDirectory()) {
String[] subPaths = path.list();
if (subPaths == null) {
return null;
}
for (String sp : subPaths) {
File subPath = new File(path.getAbsoluteFile() + "/" + sp);
File result = findConfigFile(subPath, configFilename);
if (result != null && result.getName().equalsIgnoreCase(configFilename)) {
return result;
}
}
return null;
} else {
File file = path;
if (file.getName().equalsIgnoreCase(configFilename)) {
return file;
}
return null;
}
}
}
Here I have a test case that is coupled with a file "test.txt" in my test/resources folder. The content of said file is:
A sample file
Now, here is my test case:
import org.junit.Test;
import java.io.*;
import static org.junit.Assert.fail;
public class FindResourcesRecursiveTest {
#Test
public void testFindFile() {
// Here in the test resources I have a file "test.txt"
// Inside it is a string "A sample file"
// My Unit Test will use the class FindResourcesRecursive to find the file and print out the results.
File testFile = new FindResourcesRecursive().findConfigFile(
System.getProperty("java.class.path"),
"test.txt"
);
try (FileInputStream is = new FileInputStream(testFile)) {
int i;
while ((i = is.read()) != -1) {
System.out.print((char) i);
}
System.out.println();
} catch (IOException e) {
fail();
}
}
}
Now, if you run this test, it will print out "A sample file" and the test will be green.
Now, is this okay with you?

Play! 2 with Java on heroku, save file temporary

At the very begining - sorry for my english.
I'm developing a play-application in java and deploy it to heroku.
I like to create a picture (a QRCode to be precisely), store it temporary and display it on the next page.
I do know about herokus ephemeral filesystem, but if I understand right, on the cedar stack, I am able to create files wherever I like, as long as it's ok, that they won't be stored for a long time. The app just needs to generate a QR, I scan it and the file may be deleted.
It seems as if the file is not created. Any ideas of how I can manage to temporary save and show my QRs?
Controller
public class Application extends Controller {
private static String workingDirectory = "public/images/";
public static Result qrCode() {
String msg = "I am a QR-String";
BufferedImage image = (BufferedImage) QR.stringToImage(msg);
String imgPath = workingDirectory+"posQR.png";
try{
File outputfile = new File(imgPath);
ImageIO.write(image,"png",outputfile);
}catch(IOException e){
e.printStackTrace();
}
return ok(views.html.qrCode.render());
}
}
View qrCode
<img src="#routes.Assets.at("images/posQR.png")">
Edit 1
Stored the image as tempFile an pass it to the view.
On heroku an local the view contains the exact absolute path, but the image won't load.
Any ideas left?
Controller
public class Application extends Controller {
private static String workingDirectory = "public/images/";
public static Result qrCode() {
String msg = "I am a QR-String";
BufferedImage image = (BufferedImage) QR.stringToImage(msg);
File outputfile = null;
String imgPath = workingDirectory+"posQR.png";
try{
outputfile = File.createTempFile("posQR",".png");
ImageIO.write(image,"png",outputfile);
}catch(IOException e){
e.printStackTrace();
}
return ok(views.html.qrCode.render(outputfile.getAbsolutePath()));
}
View qrCode
#(qrPath: String)
...
<img id="qr" src=#qrPath>
Does workingDirectory end with file separator?
String imgPath = workingDirectory+"posQR.png";
This helped me: Play! framework 2.0: How to display multiple image?
Finaly I did it. The trick was not to do src=path but src=getImage(path). Still strange, but now it works.
routes
GET /tmp/*filepath controllers.Application.getImage(filepath: String)
Application
public class Application extends Controller {
public static Result qrCode() {
String msg = "I am a QR-String";
BufferedImage image = (BufferedImage) QR.stringToImage(msg);
File outputfile = null;
try{
outputfile = File.createTempFile("posQR",".png");
ImageIO.write(image,"png",outputfile);
}catch(IOException e){
e.printStackTrace();
}
return ok(views.html.qrCode.render(outputfile.getAbsolutePath()));
}
...
public static Result getImage(String imgPath){
return ok(new File(imgPath));
}
}
view qrCode
#(qrPath: String)
...
<img src="#routes.Application.getImage(qrPath)"/>
Thanks for your help :D

Categories