Get directory path of maven plugin in its own Mojo - java

I am creating a custom maven plugin. In one of its Mojos, I am reading a Xpp3Dom object from XML file using following code piece:
File pluginsFile = new File(
"absolute-path-to-file/plugins.xml");
Xpp3Dom Xpp3DomObject = new Xpp3Dom("plugins");
try {
FileReader reader = new FileReader(pluginsFile);
Xpp3DomObject = Xpp3DomBuilder.build(reader);
reader.close();
} catch (Exception e) {
// TODO throw exception
}
The XML file from which I am reading (plugins.xml) is stored in src/main/resources of the maven plugin itself. My question is, how do I point to that XML file without explicitly stating the absolute path to that file?
To be clear: I want this file to be under the directory of my maven plugin. It cannot be outside the maven plugin as it is a necessary part of the maven plugin and should not be changed by other maven projects that consume this plugin.
I have searched for a variable/method in Maven Mojo that would give me the absolute location of the maven plugin itself. If I get that, then I can just give the location as value-of-that-variable/src/main/resources/plugins.xml. But I am unable to find such variable. I have also tried for a way to pass properties from Maven plugin POM to one of its Mojos so that I can pass project.build.directory, but cannot find a way.
To be clear: I want to access a file that is under the maven plugin directory, in one of its Mojos.
Any suggestions will help.

I think the easiest form to read some of the own plugin's resources files is through the getResourceAsStream() API, because sooner or later, your plugin will be delivered as a JAR, and then the src directory will dissapear and there will remain only classpath resources:
try (InputStream input=getClass().getClassLoader().getResourceAsStream("plugins.xml")){
try(Reader reader=new InputStreamReader(input));
{
Xpp3Dom Xpp3DomObject = Xpp3DomBuilder.build(input);
} catch (Exception e) {
...
}
}
Anyway, in this way there is a risk that some other JAR of the classpath should contain a plugins.xml file by chance. To avoid (or at least reduce) this risk, you should package it:
src\
main\
resources\
foo\
bar\
MyMojo.java
plugins.xml
... and in this case, you must read it through getClass().getResourceAsInputStream().

Related

Eclipse - Gradle sourceSets, how to manage my yaml property files

I'm using Gradle 7.0 and I made my project using the task Gradle Init. Then I imported it in Eclipse (2021-03 with buildship 3.1.5). Everything is fine but when I try to read or when I create a file in a java method with "/myfile.yaml" as path, it creates it (or try to read it) in the D:\ root folder (the partition where my eclipse is installed).
If I don't use the slash ("myfile.yaml" instead of "/myfile.yaml") the file is created in the root folder of the project. I thought it was supposed to be in src/main/resources until it's not built.
My goal is not really to create a file, it was just easier to test. My goal is to read some Yaml configuration files. What should I do to make sure the file will be in the build package and read in the correct place in both context (eclipse debbugging and the build package directory) ? And also, what is the best practice to set the path of the file (sonarlint alerts me about the way I do it : hardcoded in the method below, I know it's not supposed to be like this... I would use a constant but sonarlint doesn't like either).
The tree of the app :
- Project
- app
- src/main/java (containing java classes)
- src/main/resources (supposing to contain resources, yaml in my case)
- My build.gradle file
- yaml file when I try "myfile.yaml" without any /
- gradle/wrapper/gradle-wrapper.jar & gradle-wrapper.properies
- gradlew & gradlew.bat
- settings.gradle
My settings.gradle :
rootProject.name = 'myapp'
include('app')
My build.gradle:
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
}
apply plugin:'java'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
implementation 'com.google.guava:guava:30.0-jre'
// Yaml reader
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.3'
testImplementation 'junit:junit:4.13.1'
}
//I tried with and without this sourceSets and the result was the same
sourceSets {
main {
java {
srcDirs= ["src/main/java"]
}
resources {
srcDirs= ["src/main/resources"]
}
}
}
application {
// Define the main class for the application.
mainClass = 'myapp.launchers.App'
}
And here is the method which writes a file using the Jackson library (yaml) :
public static void writeConfiguration() throws JsonGenerationException, JsonMappingException, IOException {
WorkerConfig wc = new WorkerConfig();
WorkerPathConfig wpc = new WorkerPathConfig();
wpc.setTmpdir("\\some\\uri\\file");
wpc.setOutputdir("\\some\\other\\uri\\file");
wc.setPathConfig(wpc);
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
objectMapper.writeValue(new File("/application.yaml"), wc);
}
Java Reading Resource Files
You are managing files in your Java program.
If you are using java.io.File class to get a reference to a specific file it will take those references as actual paths:
Absolute path: "/myfile.yaml" -> will point to the root of the hard drive, in your case D:\myfile.yaml
Relative path: "myfile.yaml" -> will point to the root of your java project
Now your goal should be to get the project specific path to load configuration files. This can be achieved with ClassLoader instance. You can read the content of the file like in the example below. classLoader.getResourceAsStream() will search for a file inside your resources.
String fileName = "myfile.yaml";
ClassLoader classLoader = getClass().getClassLoader();
try (InputStream inputStream = classLoader.getResourceAsStream(fileName);
InputStreamReader streamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(streamReader)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
2 Gradle build script
If you have your classes in "src/main/java" and resource files in "src/main/resources" then this is compliant with the convention of gradle java plugin and you don't need to specify explicitly sourceSets block in your Gradle build script.
Sonar warning
You can extract file name as a constant and pass it as a parameter when loading the configuration file. I suppose this file "myfile.yaml" is convention of your application. In a best case it's documented somewhere.
At least this will greatly ease up development, instead if you would want to have it provided dynamically you would need to read file name from environmental variable or an argument provided in main method.
You can suppress SonarQube warning if it doesn't apply in your case and explain why you ignored it.

Spring Boot uber JAR: cannot be resolved to absolute file path because it does not reside in the file system

I got following error after export Spring Boot version 1.5.7.RELEASE to runnable JAR. I don't use maven because security reasons, and I added all JARs in build path.
I run below command
java -jar mailer.jar
then I received error as you see in screenshot
Because when your resource does not exist in packaged uber-jar, has problem with classpath. Use solution like this
String fuu = "";
ClassPathResource classPathResource = new ClassPathResource("static/foo.txt");
try {
byte[] binaryData = FileCopyUtils.copyToByteArray(classPathResource.getInputStream());
fuu = new String(binaryData, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
It seems like the application is trying to access a file through the AbstractFileResolvingResource.getFile() (a couple of rows down in the stack trace) which is not possible from a runnable spring boot jar (it may work when running from an IDE).
Try using getInputStream() instead, see for example this post.
Try this
IOUtils.toString(new InputStreamReader(this.getClassLoader().getResourceAsStream("fileName.json")))
OR
new InputStreamReader(new ClassPathResource("fileName.json", this.getClassLoader()).getInputStream())
Don't use FileReader or File
use InputStreamReader, InputStream etc

Third party JAR's in java

I included the 3rd party jar file in the java project but still this is showing compile time error.
I included the path of the jar file in add external jar's in java.
package com.aamir;
import java.io.FileReader;
import java.io.IOException;
import au.com.bytecode.opencsv.CSVReader;//compile time error occurs here.
public class ReadCSV3 {
public static void main(String[] args)
{
CSVReader reader = null;
try
{
//Get the CSVReader instance with specifying the delimiter to be used
reader = new CSVReader(new FileReader("SampleCSVFile.csv"),',');
String [] nextLine;
//Read one line at a time
while ((nextLine = reader.readNext()) != null)
{
for(String token : nextLine)
{
//Print all tokens
System.out.println(token);
}
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Your problem is that you are including the source only JAR file. That's the problem right there. You have the sources only (uncompiled source) JAR file and not the binary JAR (it must contain the .class files). You need opencsv-2.2.jar instead.
Here is a zip file of the binary JAR.
I included the path of the jar file in add external jar's in java.
You need to add it to the project.
You didn't mention exactly how to added the jar. Can you please post the screenshot of
Right click project --> Build Path --> Configure --> Libararis (3rd Tab ) --> Add External Jar
You should add the jar here. Please do so if not already done.
What development tools are you using? Are you compiling at the command line or in an IDE?
If at the command line, you need to include the third party JAR in the CLASSPATH - either as an environment variable or as an argument to javac.
If in an IDE such as Eclipse, you need to specify the add the JAR to the build path in the project.
Firstly, just for sanity's sake, double-check that the JAR is in the build path - that you have given it the right name and the right path - you should see it in the Referenced Libraries section of your Java project if you expand it in the Project View. Try removing it and adding it again.
Then, secondly, check that the class you are importing exists - that you have got the right package name and class name (it is case sensitive). You should be able to expand the JAR in Eclipse and see the packages and classes inside it.
Thirdly, if you are certain that everything is correct, try to use Eclipse's auto-import feature - delete your import line and press CTRL-SHIFT-O (for Organise Imports) and see if it imports the right class.
If it is not auto-importing, then it indicates that the class is not in the class path. Try steps 1 and 2 again.
Also, try cleaning Project --> Clean --> Clean all projects

Find resources in project tree

I have a plugin project and I need a method that will find and open a file in the project where the plugin will run.
I have in a variable the name of the file which should be inside the project. How can this be done ?
Thank you !
For a file resource inside a plug-in:
Bundle bundle = Activator.getDefault().getBundle("com.your.plugin.name");
if (bundle != null) {
URL fileURL;
try {
fileURL = FileLocator.toFileURL(bundle.getEntry("/path/to/your/file/from/the/plugin/root"));
String fileSystemPathToYourFile = fileURL.getPath());
} catch (IOException exception) {
// ...
}
}
Of course, you'll have to make sure the corresponding resource is properly included in your plug-in's binary build (bin.include property in build.properties file, or Binary Build section in the Build tab of the plug-in manifest editor).
If your file is a JAR, you may also have to export your plug-in as a directory (not 100% sure, may depend of what you actually do with your JAR resource - like add it to a project's build path or to a launch configuration classpath).

How to include plain files and folders into Eclipse product/plugin?

I have a plugin, which is using some plain text and binary files when running.
This is because plugin is using some third-party code, which works as in conventional application, i.e. taking data from within application directory.
When I was running plugin from within Eclipse, these data was just laying inside project directory in some folders.
To access this data I was using code like
public static final String CorePropertiesPath = "conf/core.xml";
public static URL CorePropertiesURL;
//...
Bundle bundle = Platform.getBundle(ID);
CorePropertiesURL = bundle.getEntry(CorePropertiesPath);
try {
CorePropertiesURL = FileLocator.resolve(CorePropertiesURL);
} catch (IOException e) {
e.printStackTrace();
}
I.e. to access data from file in "core/core.xml" in my project's directory, I was first converting it with getEntry() method and then with resolve() method.
This was working.
But when started to create products, I found that my files like "core/core.xml" just absent in target directory. Probably they should reside in my bundle jar, but they are not there.
How to force them to come in prescribed place?
Check build.properties file (you can edit it on the 'Build' tab of a manifest editor). Add
Eclipse-BundleShape: dir
in your MANIFEST.MF if you want to generate a directory and not a jar for your bundle.

Categories

Resources