Custom maven plugin - file not found - java

I created a simple plugin in maven which aims to generate files automatically. The files are created by reading templates that are located, inside the plugin, in the resources folder (src / main / resources). When I use the plugin outside of an application it works correctly. If I try to run the plugin within an exisisting project, it cannot find the template files. How can I get around?
I copy resource in the jar in this way
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.txt</include>
</includes>
</resource>
</resources>
I use this code to read file
ClassLoader classLoader = getClass().getClassLoader();
String x = classLoader.getResource("template/" + fileName).getFile();
File file = new File(x);
The value of x is correct:
file:\C:\Users\myname\.m2\repository\com\ciro\myapp\0.0.1-SNAPSHOT\myapp-0.0.1-SNAPSHOT.jar!\template\assembler.txt
but when I execute
new File(x)
I get
file:\C:\Users\myname.m2\repository\com\ciro\myapp\0.0.1-SNAPSHOT\myapp-0.0.1-SNAPSHOT.jar!\template\
The syntax of the file, directory, or volume name is incorrect

I solved in this way
InputStream in = getClass().getResourceAsStream("/template/" + fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = reader.readLine();
while (line!=null){
data.add(line);
line= reader.readLine();
}
following this link
Read all lines with BufferedReader

Related

How to read PDF from the .jar file

In my maven project I have PDF file which is located inside resources folder. My function reads the PDF file from the resources folder and adds some values in the document based on the user's data.
This project is packed as .jar file using mvn clean install and is used as dependency in my other spring boot application.
In my spring boot project I create instace of the class that will perform some work on the PDF. Once all job on the PDF file is done, and when PDF file is saved on file system it is always empty (all pages are blank). I have impression that mvn clean install does something with the PDF file. Here is what I've tried so far:
First way
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
File file= new ClassPathResource("/pdfs/testpdf.pdf").getFile();//Try to get PDF file
PDDocument pdf = PDDocument.load(file);//Load PDF document from the file
List<PDField> fields = forms.getFields();//Get input fields that I want to update in the PDF
fieldsMap.forEach(throwingConsumerWrapper((field,value) -> changeField(fields,field,value)));//Set input field values
pdf.save(byteArrayOutputStream);//Save value to the byte array
This works great, but as soon as project is packed in a .jar file then I get exception that new ClassPathResource("/pdfs/testpdf.pdf").getFile(); can't find the specified file.
This is normal because the File class can't access anything inside .jar file (it can access the .jar file itself only) and that is clear.
So, the solution to that problem is to use the InputStream instead of the File. Here is what I did:
Second way
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
InputStream inputStream = new ClassPathResource("/pdfs/testpdf.pdf").getInputStream();//Try to get input stream
PDDocument pdf = PDDocument.load(inputStream );//Load PDF document from the input stream
List<PDField> fields = forms.getFields();//Get input fields that I want to update in the PDF
fieldsMap.forEach(throwingConsumerWrapper((field,value) -> changeField(fields,field,value)));//Set input field values
pdf.save(byteArrayOutputStream);//Save value to the byte array
This time getInputStream() doesn't throw error and inputStream object is not null. But the PDF file once saved on my file system is empty, meaning all pages are empty.
I even tried to copy complete inputStream and saving it to the file byte by byte but what I've noticed that every byte is equal 0. Here is what I did:
Third way
InputStream inputStream = new ClassPathResource("/pdfs/test.pdf").getInputStream();
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
File targetFile = new File(OUTPUT_FOLDER);
OutputStream outStream = new FileOutputStream(targetFile);
outStream.write(buffer);
Copied test.pdf is saved but when opened with Adobe Reader is reported as corrupted.
Anyone have idea how to fix this?
You have to load it like this:
InputStream inputStream = this.getClass().getClassloader().getResourceAsStream("/pdfs/testpdf.pdf");
If you load it via the ClassLoader the path starts in the root of the classpath.
After few hours of investigation and good input from #Simon Martinelli and #Tilman Hausherr I had 2 issues to solve:
First issue - Read the file correctly
In order to read a file from the resources folder you have to use appropriate classes. As stated above you can't use File class to read the file from the .jar and I used the following construction in my case:
InputStream inputStream = CreatePDF.class.getResourceAsStream("/pdfs/test.pdf");
PDDocument pdf = PDDocument.load(inputStream);
In my case CreatePDF class is static one. If your class is not static then use the following:
InputStream inputStream = this.getClass().getResourceAsStream("/pdfs/test.pdf");
PDDocument pdf = PDDocument.load(inputStream);
Second issue - My original problem
One thing I noticed in my third example of my question is, when I'm copying file byte by byte from the resources to my local folder then all bytes were equal to 0. I knew this can't be correct so I tried to do the same thing with simple .txt file and in that case everything worked correctly. This means mvn clean install was causing some problems on PDF files.
After some investigation I realized that mvn filters are causing the problem. If resource filters are enabled:
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
then your binary data is going to be corrupted and that was my original problem. When I set it to false it worked like expected.
Here is Warning from the maven page:
Warning: Do not filter files with binary content like images! This
will most likely result in corrupt output.
If you have both text files and binary files as resources it is
recommended to have two separated folders. One folder
src/main/resources (default) for the resources which are not filtered
and another folder src/main/resources-filtered for the resources which
are filtered.
Here is an example how you could do it:
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.txt</include>
<include>**/*.html</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.pdf</include>
</includes>
</resource>

getResourceAsStream returns null when reading properties file

I want to load application.properties file form maven resource folder but getResourceAsStream returns null. here is my code:
static {
Properties props = new Properties();
InputStream in = Configuration.class.getResourceAsStream("application.properties");
props.load(in);
}
but InputStream is null. Configuration class is located at org.elasticsearch.utils package and application.properties is located at src/main/resources. What is wrong?
You're trying to read a classpath resource relative to the Configuration class.
If you want to do this, the resource must be on the same relative path, i.e. your property file must be in src/main/resources/org/elasticsearch/utils.
Or you can instead use absolute path: /application.properties.
From what I am seeing, your setup is just right. Having the maven resource folder and the java folder both under "main" is totally fine.
I had a problem with the filename of the properties file. I still do not understand why, but as soon I changed the name from application.properties to whateverYouWant.properties it suddenly works.
And have you enabled filtering for maven resources in the pom.xml?
<build>
<!--Allows access to maven resources-->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
Here is a guide from Alex Miller Retrieve version from maven pom.xml in code
And here is the full code example for accessing the properties in java code (I know you posted already nearly all of it, but just in case if somebody stumbles upon this post)
public String getVersionNumber() {
String version = "";
ClassLoader classLoader = getClass().getClassLoader();
final Properties properties = new Properties();
try {
properties.load(classLoader.getResourceAsStream("main.properties"));
version = properties.getProperty("application.version");
} catch (IOException ioException) {
log.log(Level.WARNING, "Version number could not be retrieved from maven resources.");
} catch (NullPointerException nullPointerException) {
log.log(Level.WARNING, "Cannot find .properties file to read version number");
}
return version;
}
This is what I have tried and working:
#Jiri's answer is also correct.
PS: "/config.properties" also works in my example. But if the this was inside ElasticTest class, then you should have to use just "config.properties".
you need to either add a / at the beginning of the rsource location string or move it to match the package structure or use the classloader rather than the class.
When looking for a resource via a class the assumption is that the resource directory structure mirrors your class structure.
so your code is looking for the resource under
src/main/resources/org/elastic...
If the file "application.properties" is under "src/main/resources", use full path (in the sense of class loader):
getResourceAsStream("/application.properties")
If you move your file to the same package as your class, you can use relative path:
getResourceAsStream("application.properties")
If you move your file to the same other packages, use full path:
getResourceAsStream("/my/package/name/application.properties")

Trying to compare generated inputStream with resource file - jUnit

I'm trying to compare the inputStream from a resource file with a created inputStream.
I'm doing that the following way:
InputStream isAsJpg = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("koala.jpg");
InputStream returnedIs = ImageUtil.convertImageStreamToPdfStream(isAsJpg);
//get is from src/test/resources
InputStream expectedIs = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("koala.pdf");
and for my tests I'm calling:
assertTrue(IOUtils.contentEquals(expectedIs, returnedIs));
but it returns false. Therefor I started with creating files so that I could manually check if the file is empty or something. So I added:
File tempFile = File.createTempFile("koala", ".pdf");
tempFile.deleteOnExit();
try (FileOutputStream out = new FileOutputStream(tempFile)) {
IOUtils.copy(returnedIs, out);
}
and I have checked the content of the file manually and it seems ok. Now I wanted to created a file from the resource that I've got to check that content (on the same way) and the pdf was empty.. Although it is placed in the src/test/resource directory and when I try to open it there, it is not empty.
What am I doing wrong? It seems as if I'm not getting the resource on the correct way (koala.pdf) but I can't find an error actually..
EDIT:
When I go and look to
C:..\target\test-classes
the file is there, but.. it is empty (blank page). Although when I open it from
C:..\src\test\resources
it is not empty. How can that be??
I've found a solution.
It's possible to say to maven that he should replace Maven placeholders of type ${..} and my binary PDF content is ofc full with it and therefor the file got corrupted.
I've changed the filtering in my pom:
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>false</filtering>
</testResource>
</testResources>
and the file in the target/test-classes also contains the image now.
Does this line
InputStream returnedIs = ImageUtil.convertImageStreamToPdfStream(isAsJpg);
actually write to a file? It doesn't seem like it. It seems like you should use the InputStream returned to write to a corresponding OutputStream. Then continue as you were.

Reading a resource with BufferedReader

I am trying to read a resource that will be included into a .JAR, but I get a nullPointer
for the following:
bReader = new BufferedReader(new InputStreamReader(
this.getClass().getResourceAsStream("resources/" + fileName)));
Using a File however, works fine..
bReader = new BufferedReader(new FileReader(new File("resources/" + fileName)));
Assuming your IDE/Maven/ANT/Gradle/build process will include contents of "resources" in jar at root, try finding it at "/".
bReader = new BufferedReader(new InputStreamReader(
this.getClass().getResourceAsStream("/" + fileName)));
UPDATE:
Make sure the "resources" folder is configured as a resource folder.
Is this a Spring framework project? Try:
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(new ClassPathResource("XML_Request.xml").getInputStream()));
Resource to load is sitting in the src/main/resources directory:
Set "resources" folder as a resource folder.
Try this code:
bReader = new BufferedReader(new
InputStreamReader(getClass().getClassLoader().getResourceAsStream(fileName)))
Unlike getClassLoader().getResourceAsStream(filename), the version you are using getClass().getResourceAsStream(filename) uses a path relative to the class's location, rather than the classpath root. You need to either use an absolute path getClass().getResourceAsStream("/" + filename) or use the ClassLoader version.
Also, make sure "resources" is on your classpath (if you are using Maven, it should be "src/main/resources" relative to your pom.xml). If so, you don't need to actually include "resources" in your filename, because that is the classpath root.
This is because of the reader class and the file to be read are in different packages. When this.getClass().getRasourceAsStream("resource/file_name") is called, it will search for the resource directory in the package directory where the current reader class presents if found then it will search for "file_name" file. So, if your file is not present it returns null.
In this case, you need to come back from current file reader class directory accordingly and then you have to give the path to your file. To back from a directory we should use ../
For example, if
Reader class package : package com.abc.util;
File present in : com.abc.template;
Then you should call the getResourceAsStream() method as follows.
bReader = new BufferedReader(new InputStreamReader(
this.getClass().getResourceAsStream("../template/" + fileName)));
this.getClass().getResourceAsStream("resources/" + fileName) loads file from classpath as new File("resources/" + fileName) loads file from your work dir(the project root dir in eclipse). To make the former work, you need to add the jar which containing resources dir to your classpath.

placing a input file relative to program

In my program (simple plain cosole app) I am reading a file a.txt.
Now I will be giving the program to someone else and he should be able to run it. I don't want the file path to be fixed like D:\a.txt , instead it should be relative to my program. Where should I place the file so that my program always finds it?
File file = new File("D:\aks.txt");
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
while( (str= bufferedReader.readLine())!=null){
}
My code is working fine when I hard code the path like D:\a.txt
Put the file in the classpath (e.g. the package root or in a certain package) and just get it straight from the classpath as follows
InputStream input = getClass().getResourceAsStream("/a.txt");
// ... (continue with InputStreamReader and so on)
(the exact path depends on the location of the current class and whether you prefix with / to start from package root and which classloader you're using)
Package and distribute it as a single executabele JAR file.
See also:
Java: Pathnames not working once I export to JAR

Categories