I am trying to fetch a file from src/main/resources folder.
Earlier it was working fine but recently it has started picking that file from some target location (target/classes/filename.xml) (I did not create that file in target folder).
File xmlFile = new File(ReadXMLFile.class.getClassLoader().getResource(“filename.xml”).toURI());
Code that I am trying is:
File xmlFile = new File(ReadXMLFile.class.getClassLoader().getResource(“filename.xml”).toURI());
Expected: it should pick the file from src/main/resources/filename.xml
actual: it is picking the file from target/classes/filename.xml
Additional Info: My code is in ReadXMLFile.xml and its under the below folder structure
com.qa.smartcomm.util
ReadXMLFile.xml
Can someone help me with this issue?
Make sure you have structure(Module) like below:
├── src
│ └── main
│ ├── java
│ │ └── somepackage
│ │ └──Main.java
│ │
│ │
│ │
│ └── resources
│ └── filename.xml
└── pom.xml
File xmlFile = new File(String.valueOf(getClass().getClassLoader().getResourceAsStream("filename.xml")));
Target Folder is automatically by maven. It copies the resources from src/main/resources to target/classes/ together with the compiled java classes from src/main/java.
If you run your program target/classes is the root of you classloader.
Related
I have project2 that depends on project1. They are both next to each other on my file system.
When I try to build project2 (after successfully building project1) I get the error:
Could not determine the dependencies of task ':app:distTar'.
> Could not resolve all task dependencies for configuration ':app:runtimeClasspath'.
> Could not resolve project :project1.
Required by:
project :app
> No matching configuration of project :project1 was found. The consumer was configured to find a runtime of a library compatible with Java 11, packaged as a jar, preferably optimized for standard JVMs, and its dependencies declared externally but:
- None of the consumable configurations have attributes.
Project2 adds the dependency to project1 as follows...
build.gradle
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
* User Manual available at https://docs.gradle.org/7.2/userguide/building_java_projects.html
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// Use JUnit test framework.
testImplementation 'junit:junit:4.13.2'
// This dependency is used by the application.
implementation 'com.google.guava:guava:30.1.1-jre'
implementation project(':project1')
implementation files('../../project1/lib/build/libs/lib.jar')
}
application {
// Define the main class for the application.
mainClass = 'project2.App'
}
Settings.gradle
rootProject.name = 'project2'
include('app')
include ':project1'
project(':project1').projectDir = new File(settingsDir, '../project1')
The source for project1...
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package project1;
public class Library {
public boolean someLibraryMethod() {
return true;
}
}
The source for project2
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package project2;
import project1.*;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
System.out.println(new App().getGreeting());
bool someBool = Library.someLibraryMethod();
}
}
the complete folder structure of the two projects. Although it looks like project2 is under project1, that is just how the copy pasted output looks, they are indeed sibling folders.
── project1
│ ├── gradle
│ │ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── lib
│ │ ├── bin
│ │ │ ├── main
│ │ │ │ └── project1
│ │ │ │ └── Library.class
│ │ │ └── test
│ │ │ └── project1
│ │ │ └── LibraryTest.class
│ │ ├── build
│ │ │ ├── libs
│ │ │ │ └── lib.jar
│ │ ├── build.gradle
│ │ └── src
│ │ ├── main
│ │ │ ├── java
│ │ │ │ └── project1
│ │ │ │ └── Library.java
│ │ │ └── resources
│ │ └── test
│ │ ├── java
│ │ │ └── project1
│ │ │ └── LibraryTest.java
│ │ └── resources
│ └── settings.gradle
└── project2
├── app
│ ├── build.gradle
│ └── src
│ ├── main
│ │ ├── java
│ │ │ └── project2
│ │ │ └── App.java
│ │ └── resources
│ └── test
│ ├── java
│ │ └── project2
│ │ └── AppTest.java
│ └── resources
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
69 directories, 37 files
Types of Builds
First you have to decide if this should be a multi-project build or a composite build.
Multi-Project Build
This is when you have a single Gradle project that is made up of multiple sub-projects. You should use a multi-project build if the various modules are highly coupled.
You create a sub-project by using include in the settings.gradle[.kts] file. But you should only have the one settings file. Each individual sub-project may have its own build.gradle[.kts] file, and typically does, but does not necessarily have to. There are various ways to cross-configure sub-projects. See the documentation linked above for details.
I do not provide an example of a multi-project build in this answer.
Composite Build
This is when you have two (or more?) relatively independent projects, but one depends on the other like any other external dependency. Yet you want to use the artifacts of the Gradle project directly rather than grab the binaries from a repository. At least some of the time, anyway.
There are a few ways to create a composite build.
Use --include-build on the command line. This requires the least amount of modification to either project (none).
Use includeBuild in the settings.gradle[.kts] file (not include, as that's for multi-project builds). This requires modifying at least one of the project's configurations, which may not be desirable.
Create a "parent" Gradle project for the "real" projects with a settings.gradle[.kts] file. Then add includeBuild for the "real" projects that you want to composite.
In a composite build, the way dependencies are resolved is described in the documentation linked above. Here's an excerpt:
Included builds interact with other builds via dependency substitution. If any build in the composite has a dependency that can be satisfied by the included build, then that dependency will be replaced by a project dependency on the included build. Because of the reliance on dependency substitution, composite builds may force configurations to be resolved earlier, when composing the task execution graph. This can have a negative impact on overall build performance, because these configurations are not resolved in parallel.
Note you don't use project("...") to define a dependency on an included build. You simply use the regular Maven coordinates like normal, and if the included build has a project matching those coordinates, then it will be substituted in.
Example Composite Build
This example uses --include-build to create a composite build. Although this example can be reproduced by following the instructions below, it can be a little error-prone and tedious, so here is a GitLab repository of the final example. I make no promise to keep the repository alive.
Source Code
Here is how the two projects were generated and any changes I made to the build configurations and or the code. Note I used Gradle 7.6 when running the init task. Also, when prompted with:
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]
I answered, "no".
Project 1
This project is the "library". It was generated with the following command:
...\demo\project1> gradle init --type java-library --test-framework junit-jupiter --project-name project1 --package sample.project1 --dsl kotlin
I only made modifications to the following files:
lib\build.gradle.kts
I added:
group = "sample.project1"
version = "1.0"
lib\src\main\java\sample\project1\Library.java
Changed it to:
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package sample.project1;
public class Library {
public static void printMessage() {
System.out.println("Hello, this is a composite build!");
}
}
lib\src\test\java\sample\project1\LibraryTest.java
I deleted this file.
Project 2
This project is the "application". It depends on project 1. It was generated with the following command:
...\demo\project2> gradle init --type java-application --test-framework junit-jupiter --project-name project2 --package sample.project2 --dsl kotlin
I only made modifications to the following files:
app\build.gradle.kts
I added:
group = "sample.project2"
version = "1.0"
And added the following to the dependencies block:
// ADD DEPENDENCY ON PROJECT 1
implementation("sample.project1:lib:1.0")
app\src\main\java\sample\project2\App.java
I changed it to:
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package sample.project2;
import sample.project1.Library;
public class App {
public static void main(String[] args) {
Library.printMessage();
}
}
app\src\test\java\sample\project2\AppTest.java
I deleted this file.
Directory Structure
Here is the directory structure of the two projects after generating them and making the above modifications. The output excludes the .gradle directory.
...\DEMO
├───project1
│ │ .gitattributes
│ │ .gitignore
│ │ gradlew
│ │ gradlew.bat
│ │ settings.gradle.kts
│ │
│ ├───gradle
│ │ └───wrapper
│ │ gradle-wrapper.jar
│ │ gradle-wrapper.properties
│ │
│ └───lib
│ │ build.gradle.kts
│ │
│ └───src
│ ├───main
│ │ ├───java
│ │ │ └───sample
│ │ │ └───project1
│ │ │ Library.java
│ │ │
│ │ └───resources
│ └───test
│ ├───java
│ └───resources
└───project2
│ .gitattributes
│ .gitignore
│ gradlew
│ gradlew.bat
│ settings.gradle.kts
│
├───app
│ │ build.gradle.kts
│ │
│ └───src
│ ├───main
│ │ ├───java
│ │ │ └───sample
│ │ │ └───project2
│ │ │ App.java
│ │ │
│ │ └───resources
│ └───test
│ ├───java
│ └───resources
└───gradle
└───wrapper
gradle-wrapper.jar
gradle-wrapper.properties
Running Example
Running the example with the following command:
...\demo\project2> .\gradlew app:run --include-build ..\project1 --console plain
Note: I used --console plain in order to see all the task output. That way you can see tasks from the included build were executed. You do not need to include this option if you don't want to.
Gave the following output:
> Task :app:processResources NO-SOURCE
> Task :project1:lib:compileJava
> Task :project1:lib:processResources NO-SOURCE
> Task :project1:lib:classes
> Task :project1:lib:jar
> Task :app:compileJava
> Task :app:classes
> Task :app:run
Hello, this is a composite build!
BUILD SUCCESSFUL in 1s
4 actionable tasks: 4 executed
Make directories project1 and project2 both modules, one application and one library module.
Files gradle, gradlew, gradlew.bat, settings.gradle need to be moved one level up. The root project needs it's own build.gradle. Including
the modules in settings.gradle is straightforward:
include ':project1'
include ':project2'
Then one can depend on module :project2 in module :project1:
dependencies {
testImplementation project(':project2')
api project(':project2')
}
The library could also be published to the default local repository mavenLocal(). Unless publishing a sources package to Maven (eg. lib-sources.jar), it's usually easier to debug with two modules. The library module still can be made a Git sub-module.
My Project looks like:
project:
├── pom.xml
│
├── project-base
│ ├── pom.xml
│ └── src
│ └── main
│ └── java
│ └── com
│ └── company
│ └── project
│ └── util
│ └── io
│ └── YamlReader
│
├── project-algo
│ ├── pom.xml
│ └── src
│ └── test
│ └── java
│ └── com
│ └── company
│ └── project
│ └── AlgorithmTest
│
└── project-config
├── pom.xml
└── configs
└── application_config.yaml
on the AlgorithmTest I have to read some values from application_config.yaml which is located in another maven module.
To read yaml file I created a utility interface called YamlReader that uses
jackson-dataformat-yaml.
At the moment I didn't find a way to read file from another module, so I'm copying the application_config.yaml into the src/test/resources folder of the project-algo module, but it's not ok, every time I have to change somthing on the application_config.yaml, I need to update both file.
I'm using the following method:
public static <C extends ConfigParent> C readConfiuration(Class<C> configClass, String yamlFileName) throws IOException {
InputStream inputStream = new FileInputStream(new File("./src/test/resources/" + yamlFileName));
YAMLMapper mapper = new YAMLMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
return mapper.readValue(inputStream, configClass);
}
This works fine for each Yaml file located into the src/test/resources folder of the project-algo module.
To read from project-config module I tried the following code:
public static <C extends ConfigParent> C readConfiuration(Class<C> configClass, String yamlFileName) throws IOException {
InputStream inputStream = new FileInputStream(new File("./project-config/configs/" + yamlFileName));
YAMLMapper mapper = new YAMLMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
return mapper.readValue(inputStream, configClass);
}
and also
public static <C extends ConfigParent> C readConfiuration(Class<C> configClass, String yamlFileName) throws IOException {
Module specificModule = ModuleLayer.boot()
.findModule("project-config")
.orElseThrow(IOException::new);
InputStream inputStream = specificModule.getResourceAsStream(yamlFileName);
YAMLMapper mapper = new YAMLMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
return mapper.readValue(inputStream, configClass);
}
but it doesn't work.
Maybe can be helpful, poms are configured in the following way:
project pom.xml contains all the modules:
<modules>
<module>project-config</module>
<module>project-base</module>
<module>project-algo</module>
</modules>
project-algo pom.xml contains the dependency of project-base :
<dependency>
<groupId>com.company.project</groupId>
<artifactId>project-base</artifactId>
<version>${project.version}</version>
</dependency>
It is possible to read file without adding project-config as dependency of project-algo?
Seems project-config is a sibling module. Add its dependency in your project-algo pom and run "mvn clean package"
Instead of
InputStream inputStream = new FileInputStream(new File("./project-config/configs/" + yamlFileName));
I fix the problem using
InputStream inputStream = new FileInputStream(new File("../project-config/configs/" + yamlFileName));
There is no need to have the Project-Config as a dependency.
./ -> will check from the maven module location
../ -> will step back and will check from parent maven module
When setting the debug configurations for the default IntelliJ IDEA Java helloworld application (created upon making a new AWS Lambda project) the following response is shown:
Error: Cannot find handler 'helloworld.App::handleRequest' in project."
To fix this I've tried editing 'Handler' element inside template.yaml to include a filepath, though there had been no success.
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: HelloWorldFunction
Handler: helloworld.App::handleRequest
I noticed the Python AWS Lambda helloworld project (within the PyCharm counterpart) required me to change the root project folder (allowing the handler to be found), however, I cant seem to achieve this with the Java counterpart within IntelliJ.
The default project file structure is as follows:
bash
├── README.mdH
├── HelloWorldFunction
│ ├── pom.xml
│ └── src
│ ├── main
│ │ └── java
│ │ └── helloworld
│ │ ├── App.java
│ │ └── GatewayResponse.java
│ └── test
│ └── java
│ └── helloworld
│ └── AppTest.java
└── template.yaml
The relevant section of the template.yaml file contains:
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: HelloWorldFunction
Handler: helloworld.App::handleRequest
Runtime: java8
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
The App.java file contains the class
public class App implements RequestHandler<Object, Object> {
...
}
I would like the debug configuration to point to the correct Handler ( being "helloworld.App::handleRequest") so I can run the project on my local machine.
On project files, right click on HelloWorldFunction then find Mark directory as and choose Source Root. That should fix your problems.
I'm using google identity toolkit to make a library. When I give this library to others, their app crashes at startup complaining that NoClassDefFoundError on GitkitClientException.
To me this is strange because:
The GitkitClientException.class is in the final jar (in fact this happens to Spring Boot application we well)
I checked every method, none of my public method throws a GitkitClientException. My understanding is, if the Exception is handled internally and not thrown. The library user should not need the dependency.
EDIT:
I know when the library user add gitkitclient as their dependency as well they will not have this crash. But I really want this to be transparent.
The final fat jar looks like this: (this is a dropwizard app)
├── ch
│
├── com
│ ├── google
│ │ ├── common
│ │ ├── identitytoolkit
│ │
│ └── fasterxml
├── META_INF
├── net
│ └── models.go
├── org
└── about.html
└── jetty-dir.css
I am having a problems running the following code:
configService.setMainConfig("src/test/resources/MainConfig.xml");
From within a Junit #Before method.
Is this the way Maven builds out its target folder?
Access MainConfig.xml directly. The src/test/resources directory contents are placed in the root of your CLASSPATH.
More precisely: contents of src/test/resources are copied into target/test-classes, so if you have the following project structure:
.
└── src
└── test
├── java
│ └── foo
│ └── C.java
└── resources
├── a.xml
└── foo
└── b.xml
It will result with the following test CLASSPATH contents:
/foo/C.class
/a.xml
/foo/b.xml
To actually access the files from Java source, use
getClass().getResource("/MainConfig.xml").getFile().
I ran into the same problem today and I have found some solutions.
First, here is my file structure:
.
└── src
│ └── test
│ ├── java
│ │ └── mypackage
│ │ └── MyClassTest.java
│ └── resources
│ └── image.jpg
└── target
└── test-classes
├── image.jpg
└── mypackage
└── MyClassTest.class
What is not working: (Java 11 synthax)
var imgFile = new File("image.jpg"); // I was expecting that Junit could find the file.
var absPath = file.getAbsolutePath(); // /home/<user>/../<project-root>/image.jpg
var anyFileUnderThisPath = file.exists(); // false
What we can notice is that the absolute path does not point at all on my image! But if I had an image under at the project-root, then it would have worked.
Solution 1: Paths (introduced in Java 7)
var relPath = Paths.get("src", "test", "resources", "image.jpg"); // src/test/resources/image.jgp
var absPath = relPath.toFile().getAbsolutePath(); // /home/<user>/../<project-root>/src/test/resources/image.jpg
var anyFileUnderThisPath = new File(absPath).exists(); // true
As we can see, it points on the right file.
Solution 2: ClassLoader
var classLoader = getClass().getClassLoader();
var url = classLoader.getResource("image.jpg"); // file:/home/<user>/../<project-root>/target/test-classes/image.jpg
var file = new File(url.getFile()); // /home/<user>/../<project-root>/target/test-classes/image.jpg
var anyFileUnderThisPath = file.exists(); // true
Note that now the file is searched under the target directory! and it works.
Solution 3: File (Adaptation of the non-working example)
var absPath = new File("src/test/resources/image.jpg").getAbsolutePath();
var var anyFileUnderThisPath = new File(absPath).exists(); // true
Which works also after taking the absolute path and putting src/test/resources/ as prefix.
Summary
All three solutions works but having to put src/test/resources/ is, in my own opinion not elegant, and this is why I would prefer the 2nd solution (ClassLoader).
Sources:
Read file and resource in junit test
Java read a file from resources folder
I guess setMainConfig expects the path of a resource, that it will load using the ClassLoader, and not a relative file path. It would help if you linked to the javadoc of this mysterious configService.setMainConfig method.
If my guess is correct, then the path should just be MainConfig.xml. Mave copies the contents of src/test/resources to the target/test-classes (IIRC) folder. And this test-classes folder is in the classpath of the unit tests.