filesystem resolver and transitive dependencies / master configurations - java

I have setup Ivy with a filesystem resolver as explained in this answer. I.e. placing my jars in a 'lib' directory and configuring a filesystem resolver to pick them up from there (instead of using the default ibiblio resolver).
The file ivysettings.xml is as follows:
<ivysettings>
<caches defaultCacheDir="${ivy.settings.dir}/cache"/>
<settings defaultResolver="local"/>
<resolvers>
<filesystem name="local">
<artifact pattern="${ivy.settings.dir}/lib/[artifact]-[revision].[ext]"/>
</filesystem>
</resolvers>
</ivysettings>
My ivy.xml is also very simple and for test purposes I only define a single configuration:
<?xml version="1.0" encoding="ISO-8859-1"?>
<ivy-module version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
<info organisation="foo" module="foo" status="foo"/>
<configurations>
<conf name="theConf" description="just one configuration"/>
</configurations>
<dependencies>
<dependency org="org.apache.commons" name="commons-lang3" rev="3.1" conf="theConf->default"/>
</dependencies>
</ivy-module>
The above works and the dependency is properly retrieved from the lib directory. However I've noticed that if I change the dependency element in the ivy.xml file to fetch the "master" as opposed to the "default" configuration:
<dependency org="org.apache.commons" name="commons-lang3" rev="3.1" conf="theConf->master"/>
… then it no longer works and I get the following:
resolve: [ivy:resolve] :: Apache Ivy 2.4.0-local-20161112135640 -
20161112135640 :: http://ant.apache.org/ivy/ :: [ivy:resolve] ::
loading settings :: file =
/home/mperdikeas/play/ivy-with-local-filesystem/ivysettings.xml
[ivy:resolve] :: resolving dependencies :: foo#foo;working#mp-t420
[ivy:resolve] confs: [theConf] [ivy:resolve] found
org.apache.commons#commons-lang3;3.1 in local [ivy:resolve] ::
resolution report :: resolve 66ms :: artifacts dl 0ms
---------------------------------------------------------------------
| | modules || artifacts |
| conf | number| search|dwnlded|evicted|| number|dwnlded|
---------------------------------------------------------------------
| theConf | 1 | 0 | 0 | 0 || 0 | 0 |
---------------------------------------------------------------------
[ivy:resolve] [ivy:resolve] :: problems summary :: [ivy:resolve] ::::
WARNINGS [ivy:resolve]
:::::::::::::::::::::::::::::::::::::::::::::: [ivy:resolve] ::
UNRESOLVED DEPENDENCIES :: [ivy:resolve]
:::::::::::::::::::::::::::::::::::::::::::::: [ivy:resolve] ::
org.apache.commons#commons-lang3;3.1: configuration not found in
org.apache.commons#commons-lang3;3.1: 'master'. It was required from
foo#foo;working#mp-t420 theConf [ivy:resolve]
:::::::::::::::::::::::::::::::::::::::::::::: [ivy:resolve]
[ivy:resolve] :: USE VERBOSE OR DEBUG MESSAGE LEVEL FOR MORE DETAILS
So even though the module is found it's "master" configuration is not found.
To make this work I either need to change theConf->master to theConf->default or simply remove the conf mapping altogether.
Further reflecting upon this I realized that I also don't understand how a filesystem resolver that's picking up jars laid out flat insider a directory is supposed to distinguish between different configurations and fetch, e.g. only compile time versus transitive dependencies of a module.
At any rate having to always use the "default" configuration causes me problems as I have to modify my ivy.xml file. When I resolve using the ibiblio resolver I typically have in my ivy.xml either:
conf="compile->master"
… or:
conf="runtime->default"
… depending on whether I want the transitive dependencies or not. I would like to keep the same ivy.xml file regardless of the resolver I have configured to use in ivysettings.xml.
My questions are:
is it possible to keep the same ivy.xml file for both the ibiblio and the filesystem resolver and what to do with "master" configurations in such a case?
how are configurations understood by a filesystem resolver that's picking up jars that are laid flat inside a directory?
is it possible to configure a filesystem resolver such that transitive dependencies can also be fetched with a dependency and what should be the file system structure in such a case?
I am simply copying jars inside the directory that the filesystem resolver is looking at. Should I be using some importation mechanism instead (e.g. to create the proper directory structure that might perhaps allow the resolver to also fetch transitive dependencies).

I gave up using a flat directory structure with just a bunch of jars. It is clear to me now that in addition to the jars, declarative files need to be present to properly identify the dependencies of each module.
What I have discovered works is to use the ivy:install task to import the dependencies I need from the ibiblio resolver into my local filesystem resolver. More or less as described in this post.
I've created a build-import-Maven-dependencies-to-local.xml script to automate this process. With some added "cleverness" (which is not crucial and you can dispense with) for aligning all the dependencies visually line after line it looks like the following (the gist is the last target, "install"):
<project name="local repository importation" default="install-deps-locally"
xmlns:contrib="http://net.sf.antcontrib"
xmlns:ivy="antlib:org.apache.ivy.ant">
<taskdef uri="http://net.sf.antcontrib" resource="net/sf/antcontrib/antlib.xml" classpath="${basedir}/tools/ant-contrib.jar" />
<target name="install-deps-locally" description="local at non default location">
<!-- "iw" starts for "Import Wrapper" and "d" stands for "dependency" -->
<antcall target="iw"><param name="d" value="javax.servlet javax.servlet-api 3.1.0" /></antcall>
<antcall target="iw"><param name="d" value="com.google.code.gson gson 2.8.0" /></antcall>
<antcall target="iw"><param name="d" value="junit junit 4.12" /></antcall>
</target>
<target name="iw"> <!-- "iw" stands for "Import Wrapper" and "d" stands for "dependency" -->
<property name="REGULAR_EXPRESSION" value="(\S*)(\s*)(\S*)(\s*)(\S*)"/>
<contrib:propertyregex property="organisation"
input="${d}"
regexp="${REGULAR_EXPRESSION}"
select="\1"
casesensitive="false"/>
<contrib:propertyregex property="module"
input="${d}"
regexp="${REGULAR_EXPRESSION}"
select="\3"
casesensitive="false"/>
<contrib:propertyregex property="revision"
input="${d}"
regexp="${REGULAR_EXPRESSION}"
select="\5"
casesensitive="false"/>
<antcall target="install">
<param name="organisation" value="${organisation}"/>
<param name="module" value="${module}"/>
<param name="revision" value="${revision}"/>
</antcall>
</target>
<target name="install" description="import module from public Maven repository into local repository">
<ivy:settings id="ivysettings-ibiblio-to-local" file="ivysettings-ibiblio-to-local.xml"/>
<ivy:install settingsRef="ivysettings-ibiblio-to-local"
organisation="${organisation}"
module="${module}"
revision="${revision}"
from="public"
to="local"
transitive="true"
overwrite="true"/>
</target>
</project>
Resolvers "public" and "local" are defined in the ivysettings.file and correspond to ibiblio and filesystem respectively.
This creates the correct structure and places ivy-x.y.z.xml files that provide the necessary information. This is a partial example of the directory structure that got created in my system and the files that are present.
$ tree repo/ | head -20
repo/
├── avalon-framework
│   └── avalon-framework
│   ├── ivys
│   │   ├── ivy-4.1.5.xml
│   │   ├── ivy-4.1.5.xml.md5
│   │   └── ivy-4.1.5.xml.sha1
│   └── jars
│   ├── avalon-framework-4.1.5.jar
│   ├── avalon-framework-4.1.5.jar.md5
│   └── avalon-framework-4.1.5.jar.sha1
├── com.google.code.findbugs
│   └── jsr305
│   ├── ivys
│   │   ├── ivy-1.3.9.xml
│   │   ├── ivy-1.3.9.xml.md5
│   │   └── ivy-1.3.9.xml.sha1
│   └── jars
│   ├── jsr305-1.3.9.jar
│   ├── jsr305-1.3.9.jar.md5
Once this is in place the filesystem resolver works like a charm for both transitive (default) and compile-time (master) dependencies.

Related

How to log the pom artifact and version

In ProjectA, I have a MethodA in ClassA, and ProjectA jar is added in different projects as a Maven dependency, and different projects are calling MethodA.
Requirement is
Whenever MethodA of ClassA is called by any other project, we would require to log the called project artifact id and version, considering ProjectA dependency is added in these projects pom.xml.
NOTE
Below works only on self project (ProjectA), creation of property file and turning on maven resource filtering
Create a property file
src/main/resources/project.properties
with the below content
version=${project.version}
artifactId=${project.artifactId}
Now turn on maven resource filtering
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
MethodA
public class ClassA {
final static Logger logger = Logger.getLogger(ClassA.class);
public void MethodA{
final Properties properties = new Properties();
properties.load(this.getClassLoader().getResourceAsStream("project.properties"));
logger.info(properties.getProperty("version"));
logger.info(properties.getProperty("artifactId"));
}
}
When called MethodA in Project B, I get the below output in logger
version=${project.version}
artifactId=${project.artifactId} which is incorrect.
Expected output:
version = 1.0.0
artifactId = ProjectB
Is there any better way to log the calling project artifact id? If MethodA is called by ProjectC, we want to get ProjectC artifactid and version.
Requirement: We have 30+ projects calling MethodA from ProjectA, so we should not make any changes in the calling projects.
Solution A: Maven resource filtering
Your POM snippet should replace the variables correctly, if you put it in the right POM section:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
You can inspect the result in the target/classes folder. After I fixed your faulty pseudo code by adding an empty argument list () to your method name and replaced the nonsensical this.getClassLoader() by getClass().getClassLoader(), the code even compiles and does something meaningful. Do you ever test before you post something to a public platform like StackOverflow?
import java.io.IOException;
import java.util.Properties;
public class ClassA {
public void methodA() throws IOException {
final Properties properties = new Properties();
properties.load(getClass().getClassLoader().getResourceAsStream("project.properties"));
System.out.println(properties.getProperty("version"));
System.out.println(properties.getProperty("artifactId"));
}
public static void main(String[] args) throws IOException {
new ClassA().methodA();
}
}
Console log when running from IntelliJ IDEA after mvn compile (because we need Maven to process the resources and copy them to target/classes):
1.9.8-SNAPSHOT
util
Or whatever your module name and version are.
If you see the variable names instead, either your classpath does not point to the JAR but to the source directory somehow, or you have multiple modules with a project.properties file and in one of them forgot resource filtering. Whichever file is found first on the class path, will be loaded. So in a multi-module project, you better use different file names, otherwise it is more or less a lottery which one if found first.
The next problem would then be for your aspect or other module to know which resource file to load, so that better be linked to class or package names somehow in order for the other module to be able to guess the resource file from the package name. You do need clean package name separation between modules then. I really wonder if it is worth the trouble.
Solution B: Templating Maven Plugin + package-info.java + custom annotation
Another idea would be to use resource filtering or a plugin like org.codehaus.mojo:templating-maven-plugin for replacing the versions directly into package annotation values in a package-info.java file and then simply fetch the values during runtime from the package info. I made a quick & dirty local test with that plugin, and it works nicely. I recommend to keep it simple for now and just fix your resource filtering problem. If you need the more generic solution I just described, please let me know.
Project structure
Update: I extracted the quick solution I hacked into one of my projects into a new Maven multi-module project in order to show you a clean solution as follows:
Say, we have a parent POM with 3 sub-modules:
annotation - contains an annotation to be used on packages in package-info.java files. Can easily be modified to also be applicable to classes.
library - example library to be accessed by an application module
application - example application
You can find the full project on GitHub:
https://github.com/kriegaex/SO_Maven_ArtifactInfoRuntime_68321439
The project's directory layout is as follows:
$ tree
.
├── annotation
│   ├── pom.xml
│   └── src
│   └── main
│   └── java
│   └── de
│   └── scrum_master
│   └── stackoverflow
│   └── q68321439
│   └── annotation
│   └── MavenModuleInfo.java
├── application
│   ├── pom.xml
│   └── src
│   ├── main
│   │   ├── java
│   │   │   └── de
│   │   │   └── scrum_master
│   │   │   └── stackoverflow
│   │   │   └── q68321439
│   │   │   └── application
│   │   │   └── Application.java
│   │   └── java-templates
│   │   └── de
│   │   └── scrum_master
│   │   └── stackoverflow
│   │   └── q68321439
│   │   └── application
│   │   └── package-info.java
│   └── test
│   └── java
│   └── de
│   └── scrum_master
│   └── stackoverflow
│   └── q68321439
│   └── application
│   └── ModuleInfoTest.java
├── library
│   ├── pom.xml
│   └── src
│   └── main
│   ├── java
│   │   └── de
│   │   └── scrum_master
│   │   └── stackoverflow
│   │   └── q68321439
│   │   └── library
│   │   └── LibraryClass.java
│   └── java-templates
│   └── de
│   └── scrum_master
│   └── stackoverflow
│   └── q68321439
│   └── library
│   └── package-info.java
└── pom.xml
Please note the src/java-templates directories in both the library and the application modules, containing package-info.java files. The directory name is the default for Templating Maven Plugin, making plugin configuration less verbose.
Parent POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.scrum-master.stackoverflow.q68321439</groupId>
<artifactId>maven-artifact-info-runtime</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<modules>
<module>annotation</module>
<module>library</module>
<module>application</module>
</modules>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<id>filter-src</id>
<goals>
<goal>filter-sources</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Module annotation
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.scrum-master.stackoverflow.q68321439</groupId>
<artifactId>maven-artifact-info-runtime</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>annotation</artifactId>
</project>
package de.scrum_master.stackoverflow.q68321439.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PACKAGE)
public #interface MavenModuleInfo {
String groupId();
String artifactId();
String version();
}
Module library
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.scrum-master.stackoverflow.q68321439</groupId>
<artifactId>maven-artifact-info-runtime</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>library</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>de.scrum-master.stackoverflow.q68321439</groupId>
<artifactId>annotation</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
package de.scrum_master.stackoverflow.q68321439.library;
public class LibraryClass {}
Please note that the following file needs to be located in library/src/main/java-templates/de/scrum_master/stackoverflow/q68321439/library/package-info.java. Here you can see how we use Maven properties to be replaced by their corresponding values during the build process by Templating Maven Plugin:
/**
* This is the package description (...)
*/
#MavenModuleInfo(groupId = "${project.groupId}", artifactId = "${project.artifactId}", version = "${project.version}")
package de.scrum_master.stackoverflow.q68321439.library;
import de.scrum_master.stackoverflow.q68321439.annotation.MavenModuleInfo;
Module application
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.scrum-master.stackoverflow.q68321439</groupId>
<artifactId>maven-artifact-info-runtime</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>application</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>de.scrum-master.stackoverflow.q68321439</groupId>
<artifactId>annotation</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>de.scrum-master.stackoverflow.q68321439</groupId>
<artifactId>library</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>de.scrum-master.stackoverflow.q68321439</groupId>
<artifactId>library</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
package de.scrum_master.stackoverflow.q68321439.application;
public class Application {
public static void main(String[] args) {}
}
Please note that the following file needs to be located in application/src/main/java-templates/de/scrum_master/stackoverflow/q68321439/application/package-info.java. Here you can see how we use Maven properties to be replaced by their corresponding values during the build process by Templating Maven Plugin:
/**
* This is the package description (...)
*/
#MavenModuleInfo(groupId = "${project.groupId}", artifactId = "${project.artifactId}", version = "${project.version}")
package de.scrum_master.stackoverflow.q68321439.application;
import de.scrum_master.stackoverflow.q68321439.annotation.MavenModuleInfo;
package de.scrum_master.stackoverflow.q68321439.application;
import de.scrum_master.stackoverflow.q68321439.annotation.MavenModuleInfo;
import de.scrum_master.stackoverflow.q68321439.library.LibraryClass;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ModuleInfoTest {
#Test
public void test() {
String groupId = "de.scrum-master.stackoverflow.q68321439";
MavenModuleInfo libMavenInfo = logAndGetMavenModuleInfo("Library Maven info", LibraryClass.class.getPackage());
assertEquals(groupId, libMavenInfo.groupId());
assertEquals("library", libMavenInfo.artifactId());
MavenModuleInfo appMavenInfo = logAndGetMavenModuleInfo("Application Maven info", Application.class.getPackage());
assertEquals(groupId, appMavenInfo.groupId());
assertEquals("application", appMavenInfo.artifactId());
}
private MavenModuleInfo logAndGetMavenModuleInfo(String message, Package aPackage) {
MavenModuleInfo moduleInfo = aPackage.getAnnotation(MavenModuleInfo.class);
System.out.println(message);
System.out.println(" " + moduleInfo.groupId());
System.out.println(" " + moduleInfo.artifactId());
System.out.println(" " + moduleInfo.version());
return moduleInfo;
}
}
Run Maven build
Now run the Maven build via mvn clean test:
(...)
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) # application ---
[INFO] Surefire report directory: C:\Users\alexa\Documents\java-src\SO_Maven_ArtifactInfoRuntime_68321439\application\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running de.scrum_master.stackoverflow.q68321439.application.ModuleInfoTest
Library Maven info
de.scrum-master.stackoverflow.q68321439
library
1.0-SNAPSHOT
Application Maven info
de.scrum-master.stackoverflow.q68321439
application
1.0-SNAPSHOT
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.094 sec
(...)
Identifying the caller
Assuming that all calling modules implement the same scheme with package info + special annotation, you can print the caller info like this:
package de.scrum_master.stackoverflow.q68321439.library;
import de.scrum_master.stackoverflow.q68321439.annotation.MavenModuleInfo;
public class LibraryClass {
public void doSomething() {
StackTraceElement callerStackTraceElement = new Exception().getStackTrace()[1];
try {
Class<?> callerClass = Class.forName(callerStackTraceElement.getClassName());
MavenModuleInfo mavenModuleInfo = callerClass.getPackage().getAnnotation(MavenModuleInfo.class);
System.out.println(mavenModuleInfo.groupId());
System.out.println(mavenModuleInfo.artifactId());
System.out.println(mavenModuleInfo.version());
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void doSomethingJava9() {
Class<?> callerClass = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass();
MavenModuleInfo mavenModuleInfo = callerClass.getPackage().getAnnotation(MavenModuleInfo.class);
System.out.println(mavenModuleInfo.groupId());
System.out.println(mavenModuleInfo.artifactId());
System.out.println(mavenModuleInfo.version());
}
}
While doSomething() also works in old Java versions (tested on Java 8), on Java 9+ you can use the JEP 259 Stack-Walking API as shown in doSomethingJava9(). In that case, you do not need to manually parse an exception stack trace and handle exceptions.
Solution C: Identifying the calling JAR via URL classloader
Assuming that you use my sample project and call the library from the application module (like in the previous section), a quick & dirty way to print JAR information would be this:
Add this method to LibraryClass:
public void doSomethingClassLoader() {
StackTraceElement callerStackTraceElement = new Exception().getStackTrace()[1];
try {
Class<?> callerClass = Class.forName(callerStackTraceElement.getClassName());
// Cheap way of getting Maven artifact name - TODO: parse
System.out.println(
callerClass
.getClassLoader()
.getResource(callerStackTraceElement.getClassName().replaceAll("[.]", "/") + ".class")
);
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
Again, on Java 9+ you could make the code nicer by using the Stack-Walking API, see above.
Call the method from Application:
public class Application {
public static void main(String[] args) {
// new LibraryClass().doSomething();
// new LibraryClass().doSomethingJava9();
new LibraryClass().doSomethingClassLoader();
}
}
Now build the Maven application from the command line and run with 3 different classpaths, pointing to
the target/classes directory
the JAR in the target directory
the JAR in the local Maven repository
in order to see what kind of information gets printed to the console:
$ mvn install
(...)
$ java -cp "annotation\target\annotation-1.0-SNAPSHOT.jar;library\target\library-1.0-SNAPSHOT.jar;application\target\classes" de.scrum_master.stackoverflow.q68321439.application.Application
file:/C:/Users/alexa/Documents/java-src/SO_Maven_ArtifactInfoRuntime_68321439/application/target/classes/de/scrum_master/stackoverflow/q68321439/application/Application.class
$ java -cp "annotation\target\annotation-1.0-SNAPSHOT.jar;library\target\library-1.0-SNAPSHOT.jar;application\target\application-1.0-SNAPSHOT.jar" de.scrum_master.stackoverflow.q68321439.application.Application
jar:file:/C:/Users/alexa/Documents/java-src/SO_Maven_ArtifactInfoRuntime_68321439/application/target/application-1.0-SNAPSHOT.jar!/de/scrum_master/stackoverflow/q68321439/application/Application.class
$ java -cp "annotation\target\annotation-1.0-SNAPSHOT.jar;library\target\library-1.0-SNAPSHOT.jar;c:\Users\Alexa\.m2\repository\de\scrum-master\stackoverflow\q68321439\application\1.0-SNAPSHOT\application-1.0-SNAPSHOT.jar" de.scrum_master.stackoverflow.q68321439.application.Application
jar:file:/C:/Users/alexa/.m2/repository/de/scrum-master/stackoverflow/q68321439/application/1.0-SNAPSHOT/application-1.0-SNAPSHOT.jar!/de/scrum_master/stackoverflow/q68321439/application/Application.class
As you can see
in case 1, you can indirectly infer the Maven artifact from the project path,
in case 2, you see artifact ID and version in the JAR name and the group ID indirectly in the project path,
in case 3, you see artifact ID and version in the JAR name and the group ID directly in the Maven repository path.
Of course, you could parse that information and print it in a more structured way, but I suggest to simply print it like this and let the human brain reading the log do the parsing.
Like I said in a comment before, this works nicely in the case I showed you, also with different projects, not just in a single multi-module project. What kinds of information you would see in case of an application server deployment or uber JAR situation, strongly depends on the exact situation. There is no single, generic answer, and I cannot do your whole job for you. I showed you several options, now you can select one.
SOLUTION to the scenario explained in the post main description and considering pom present at root of every project .
Note - Please look at #kriegaex suggestions for the better approach.
Add maven-model Dependency:
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>3.3.1</version>
</dependency>
This dependency has methods which helps to get all pom related informations at the runtime and across projects.
quick example:
model.getArtifactId() -> gets you the artifact id of the project.
> import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import org.apache.log4j.Logger;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
public class MavenTest {
private static String FILE_NAME = "pom.xml";
private MavenXpp3Reader reader;
private Logger log = Logger.getLogger(MavenUtil.class.getName());
private Model model;
public MavenUtil() throws FileNotFoundException, IOException, XmlPullParserException {
this(FILE_NAME);
}
public MavenUtil(String absoluteFilePath) throws FileNotFoundException, IOException, XmlPullParserException {
log.info("[" + this.getClass().getSimpleName() + "]");
reader = new MavenXpp3Reader();
FileReader fr = null;
try {
fr = new FileReader(absoluteFilePath);
model = reader.read(fr);
} finally {
if (fr != null)
fr.close();
}
}
public String[] populateBuildInfo() {
String[] buildInfo = { model.getArtifactId().toUpperCase() + ":" + model.getVersion() };
return buildInfo;
}
public String getArtifactId(String absoluteFilePath) {
return model.getArtifactId();
}
}

Spring Boot failed to load property source from location 'classpath:/application.xml'

When I deploy a Spring Boot application packaged in an ear in Jboss 7.x EAP I get the following error:
server.default-host./pepe: org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./pepe: java.lang.RuntimeException: java.lang.IllegalStateException: Failed to load property source from location 'classpath:/application.xml'
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:85)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at org.jboss.threads.JBossThread.run(JBossThread.java:320)
Caused by: java.lang.RuntimeException: java.lang.IllegalStateException: Failed to load property source from location 'classpath:/application.xml'
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:231)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:100)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:82)
... 6 more
Caused by: java.lang.IllegalStateException: Failed to load property source from location 'classpath:/application.xml'
at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadIntoGroup(ConfigFileApplicationListener.java:476)
at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:465)
at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:386)
at org.springframework.boot.context.config.ConfigFileApplicationListener.addPropertySources(ConfigFileApplicationListener.java:225)
at org.springframework.boot.context.config.ConfigFileApplicationListener.postProcessEnvironment(ConfigFileApplicationListener.java:195)
at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEnvironmentPreparedEvent(ConfigFileApplicationListener.java:182)
at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEvent(ConfigFileApplicationListener.java:168)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:122)
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:74)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:325)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:296)
at org.springframework.boot.web.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:154)
at org.springframework.boot.web.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:134)
at org.springframework.boot.web.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:87)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:169)
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:184)
The structure of the ear is as follows:
├── META-INF
│   ├── application.xml
│   └── jboss-deployment-structure.xml
├── evaluateboot_be-web-0.0.1-SNAPSHOT.war
└── lib
├── asm-5.0.4.jar
├── aspectjweaver-1.8.13.jar
├── bcpkix-jdk15on-1.55.jar
├── bcprov-jdk15on-1.55.jar
├── bval-core-1.1.2.jar
├── cache-api-1.0.0.jar
├── ccf2-8.0.0.4_MAPFRE.jar
├── cxf-core-3.1.12.jar
├── cxf-rt-bindings-soap-3.1.12.jar
├── cxf-rt-databinding-jaxb-3.1.12.jar
├── cxf-rt-frontend-jaxws-3.1.12.jar
├── cxf-rt-frontend-simple-3.1.12.jar
├── cxf-rt-security-3.1.12.jar
├── cxf-rt-security-saml-3.1.12.jar
├── cxf-rt-transports-http-3.1.12.jar
├── cxf-rt-ws-security-3.1.12.jar
├── cxf-rt-wsdl-3.1.12.jar
├── cxf-spring-boot-autoconfigure-3.1.12.jar
├── cxf-spring-boot-starter-jaxws-3.1.12.jar
├── dom4j-1.6.1.jar
├── ehcache-2.10.4.jar
├── evaluateboot-bo-0.0.1-SNAPSHOT.jar
├── evaluateboot_be-commons-0.0.1-SNAPSHOT.jar
├── evaluateboot_be-crud-dl-api-0.0.1-SNAPSHOT.jar
├── evaluateboot_be-crud-sr-api-0.0.1-SNAPSHOT.jar
├── evaluateboot_be-crud-sr-impl-0.0.1-SNAPSHOT.jar
├── evaluateboot_be.zeroConfig-0.0.1-SNAPSHOT.jar
├── guava-19.0.jar
├── hibernate-validator-5.3.6.Final.jar
├── httpclient-4.5.3.jar
├── httpcore-4.4.8.jar
├── jackson-annotations-2.8.0.jar
├── jackson-core-2.8.10.jar
├── jackson-databind-2.8.10.jar
├── jasypt-1.9.2.jar
├── jaxen-1.1.1_CXF_MAPFRE.jar
├── jboss-logging-3.3.1.Final.jar
├── jcl-over-slf4j-1.7.25.jar
├── jdom-1.1.jar
├── joda-time-2.9.9.jar
├── jul-to-slf4j-1.7.25.jar
├── log4j-over-slf4j-1.7.25.jar
├── logback-classic-1.1.11.jar
├── spring-aspects-4.3.13.RELEASE.jar
├── spring-beans-4.3.13.RELEASE.jar
├── spring-boot-1.5.9.RELEASE.jar
├── spring-boot-actuator-1.5.9.RELEASE.jar
├── spring-boot-autoconfigure-1.5.9.RELEASE.jar
├── spring-boot-starter-1.5.9.RELEASE.jar
...
The version of spring boot that I am using is 1.5.9.
Why is Spring Boot trying to load the ear deployment descriptor, which is in the META-INF folder?
This same ear deploys correctly in Websphere 8.5.5.x
After carefully reviewing the generated artifacts, I have found that the problem that causes this error is because one of the artifacts has the following plugin:
<plugin>
<groupId> org.apache.maven.plugins </ groupId>
<artifactId> maven-jar-plugin </ artifactId>
<configuration>
<archive>
<manifest>
<addClasspath> true </ addClasspath>
</ manifest>
<manifestEntries>
<Class-Path> ./ META-INF / </ Class-Path>
</ manifestEntries>
</ archive>
</ configuration>
</ plugin>
This is causing it to generate the META-INF file:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: jose
Class-Path: ./ META-INF/ bval-core-1.1.2.jar gaia-core-2.4.0-SNAPSHOT.
jar gaia-commons-devutils-2.4.0-SNAPSHOT.jar gaiafrontend-proxy-2.4.0
-SNAPSHOT.jar gaia-commons-2.4.0-SNAPSHOT.jar MAPFRE_ARQOS_CORE_VIDA.
ArquitecturaCoreVidaFramework-14.1.12.jar MAPFRE_ARQOS_COMMONS_STANDA
LONE.CommonsExceptions-14.1.12.jar MAPFRE_ARQOS_COMMONS_STANDALONE.En
cryptionServiceProvider-14.1.12.jar MAPFRE_ARQOS_COMMONS_STANDALONE.U
tils-14.1.12.jar MAPFRE_ARQOS_COMMONS_STANDALONE.Log4M-14.1.12.jar MA
PFRE_ARQOS_COMMONS_STANDALONE.CacheServiceProvider-14.1.12.jar MAPFRE
_ARQOS_COMMONS_STANDALONE.Tron21ConnectorErrorExchange-14.1.12.jar do
m4j-1.6.1.jar jaxen-1.1.1_CXF_MAPFRE.jar xercesImpl-2.8.0.jar jdom-1.
1.jar ctgclient-8.0.0.4_MAPFRE.jar ctgserver-8.0.0.4_MAPFRE.jar ccf2-
8.0.0.4_MAPFRE.jar cicseci-8.0.0.4_MAPFRE.jar cicsecitools-8.0.0.4_MA
PFRE.jar cicsframe-8.0.0.4_MAPFRE.jar security-8.0.0.4_MAPFRE.jar spr
ing-aspects-4.3.13.RELEASE.jar spring-core-4.3.13.RELEASE.jar commons
-logging-1.2.jar spring-context-4.3.13.RELEASE.jar spring-context-sup
port-4.3.13.RELEASE.jar spring-beans-4.3.13.RELEASE.jar spring-expres
sion-4.3.13.RELEASE.jar spring-aop-4.3.13.RELEASE.jar spring-oxm-4.3.
13.RELEASE.jar spring-tx-4.3.13.RELEASE.jar spring-web-4.3.13.RELEASE
.jar spring-webmvc-4.3.13.RELEASE.jar spring-security-core-4.2.3.RELE
ASE.jar aopalliance-1.0.jar spring-security-ldap-4.2.3.RELEASE.jar sp
ring-ldap-core-2.3.2.RELEASE.jar spring-security-config-4.2.3.RELEASE
.jar spring-security-web-4.2.3.RELEASE.jar spring-boot-1.5.9.RELEASE.
jar spring-boot-autoconfigure-1.5.9.RELEASE.jar jackson-core-2.8.10.j
ar jackson-databind-2.8.10.jar jackson-annotations-2.8.0.jar cxf-core
-3.1.12.jar woodstox-core-asl-4.4.1.jar stax2-api-3.1.4.jar xmlschema
-core-2.2.2.jar cxf-rt-bindings-soap-3.1.12.jar cxf-rt-databinding-ja
xb-3.1.12.jar cxf-rt-frontend-simple-3.1.12.jar cxf-rt-frontend-jaxws
-3.1.12.jar asm-5.0.4.jar cxf-rt-transports-http-3.1.12.jar cxf-rt-ws
-security-3.1.12.jar cxf-rt-security-saml-3.1.12.jar cxf-rt-security-
3.1.12.jar wss4j-policy-2.1.10.jar neethi-3.0.3.jar wss4j-ws-security
-stax-2.1.10.jar wss4j-bindings-2.1.10.jar wss4j-ws-security-policy-s
tax-2.1.10.jar cxf-rt-wsdl-3.1.12.jar wsdl4j-1.6.3.jar logback-core-1
.1.11.jar logback-classic-1.1.11.jar slf4j-api-1.7.25.jar commons-io-
2.4.jar commons-codec-1.10.jar commons-pool-1.6.jar commons-lang-2.6.
jar commons-lang3-3.3.2.jar commons-collections-3.2.2.jar commons-bea
nutils-1.9.3.jar validation-api-1.1.0.Final.jar cache-api-1.0.0.jar j
oda-time-2.9.9.jar swagger-annotations-1.5.10.jar lombok-1.16.18.jar
guava-19.0.jar aspectjweaver-1.8.13.jar coherence-12.1.2.0.jar ehcach
e-2.10.4.jar wss4j-1.6.7.jar wss4j-ws-security-common-2.0.9.jar xmlse
c-2.0.7.jar jasypt-1.9.2.jar wss4j-ws-security-dom-2.0.9.jar gaiaback
end-core-2.4.0-SNAPSHOT.jar gaia-context-2.4.0-SNAPSHOT.jar spring-jd
bc-4.3.13.RELEASE.jar springfox-swagger2-2.6.1.jar swagger-models-1.5
.10.jar springfox-spi-2.6.1.jar springfox-core-2.6.1.jar springfox-sc
hema-2.6.1.jar springfox-swagger-common-2.6.1.jar springfox-spring-we
b-2.6.1.jar classmate-1.3.4.jar spring-plugin-core-1.2.0.RELEASE.jar
spring-plugin-metadata-1.2.0.RELEASE.jar mapstruct-1.0.0.Final.jar sp
ringfox-swagger-ui-2.6.1.jar gaiabackend-remote-2.4.0-SNAPSHOT.jar ga
ia-plinvoker-2.4.0-SNAPSHOT.jar plinvoker-1.0.0-20180208.232239-4.jar
cxf-spring-boot-starter-jaxws-3.1.12.jar spring-boot-starter-1.5.9.R
ELEASE.jar spring-boot-starter-logging-1.5.9.RELEASE.jar jul-to-slf4j
-1.7.25.jar log4j-over-slf4j-1.7.25.jar snakeyaml-1.17.jar spring-boo
t-starter-web-1.5.9.RELEASE.jar spring-boot-starter-tomcat-1.5.9.RELE
ASE.jar tomcat-embed-core-8.5.23.jar tomcat-annotations-api-8.5.23.ja
r tomcat-embed-el-8.5.23.jar tomcat-embed-websocket-8.5.23.jar hibern
ate-validator-5.3.6.Final.jar jboss-logging-3.3.1.Final.jar cxf-sprin
g-boot-autoconfigure-3.1.12.jar jcl-over-slf4j-1.7.25.jar
Created-By: Apache Maven 3.5.0
Build-Jdk: 1.8.0_20
Removing the entry from the plugin:
<manifestEntries>
<Class-Path> ./ META-INF / </ Class-Path>
</ manifestEntries>
The application.xml file of the ear device is no longer scanned
Actually the application.xml and jboss-deployment-structure.xml file should be present inside the WEB-INF. Could you please check the project structure. If it is a new project, you can use this URL (https://start.spring.io/) to create the project structure. Can you refer the below URL:
https://docs.jboss.org/jbossas/docs/Server_Configuration_Guide/4/html/ch01s04s02.html
verify the complete structure including the war packaging.

NoClassDefFoundError in app, classpath is correct (at first sight). Why?

I run my app.jar as java -jar app.jar and see the next error:
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/thrift/transport/TTransportException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: org.apache.thrift.transport.TTransportException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
app.jar structure:
.
├── lib
│   ├── ... (some *.jar files)
│   ├── libthrift-0.9.3.jar
│   └── ... (some *.jar files)
├── META-INF
│   ├── MANIFEST.MF
│   └── maven
│   └── groupId-name
│   └── artifactId-name
│   ├── pom.properties
│   └── pom.xml
└── ... *.class files of app
In META-INF/MANIFEST.MF declared a classpath as:
Class-Path: lib/libthrift-0.9.3.jar lib/...(other *.jar's from lib/ folder)
libthrift-0.9.3.jar structure:
.
├── META-INF
│   ├── LICENSE.txt
│   ├── MANIFEST.MF
│   └── NOTICE.txt
└── org
└── apache
└── ... some packages with files
├── transport
│   ├── ... some files
│   ├── TTransportException.class
│   └── ...
└── ...
As are you see, class org.apache.transport.TTransportException exists and must be accessible in runtime. But don't. Why so?
First: by default in java if you have not used any special tools/frameworks (like spring-boot) you cannot have jars inside jar.
Second: The entries in in your Manifest file (like Class-Path: lib/libthrift-0.9.3.jar etc) reference not the jars inside jar but the jars in file system near the jar. I.e the file structure to run your app with java -jar app.jar should be:
./
/libs --> all 3-d party jars here
app.jar
If you want to have all in one jar one of the variants is to use so called 'uber-jar' - in that case all the 3-d party classes are extracted from their jars and packaged together with your own classes in one jar.
For example for maven build Shade Plugin can be used.
While packaging the app.jar, simply put the external/3rd party libraries like libthrift-0.9.3.jar in a folder/directory called "lib" just beside the app.jar. Let you Manifest entries remain the same. While executing, use java -cp . -jar app.jar. Else, like inigo said, simply use a tool like eclipse and pack all libraries inside the jar. Another option is simply to extract all class files from the external jars like thrift and package them into your app.jar. In that case you can run it simply like you want.

where does jitpack download build artifacts to?

This hello world project runs fine, but where is the hello_api-latest.jar file? (Regardless that the client doesn't actually "need" the JAR, it should still download.)
The JAR is on the classpath:
thufir#mordor:~/NetBeansProjects/hello_client$
thufir#mordor:~/NetBeansProjects/hello_client$ gradle clean build;java -jar build/libs/hello_client.jar
:clean
:compileJava
:processResources UP-TO-DATE
:classes
:jar
:startScripts
:distTar
:distZip
:assemble
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build
BUILD SUCCESSFUL
Total time: 1.229 secs
hello world
thufir#mordor:~/NetBeansProjects/hello_client$
thufir#mordor:~/NetBeansProjects/hello_client$ jar -xf build/libs/hello_client.jar
thufir#mordor:~/NetBeansProjects/hello_client$
thufir#mordor:~/NetBeansProjects/hello_client$ cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
Main-Class: net.bounceme.mordor.Main
Class-Path: hello_api-latest.jar
thufir#mordor:~/NetBeansProjects/hello_client$
thufir#mordor:~/NetBeansProjects/hello_client$ tree build
build
├── classes
│   └── main
│   └── net
│   └── bounceme
│   └── mordor
│   └── Main.class
├── dependency-cache
├── distributions
│   ├── hello_client.tar
│   └── hello_client.zip
├── libs
│   └── hello_client.jar
├── scripts
│   ├── hello_client
│   └── hello_client.bat
└── tmp
├── compileJava
│   └── emptySourcePathRef
└── jar
└── MANIFEST.MF
13 directories, 7 files
thufir#mordor:~/NetBeansProjects/hello_client$
build file:
apply plugin: 'java'
apply plugin: 'application'
sourceCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
if (!hasProperty('mainClass')) {
ext.mainClass = 'Main'
}
mainClassName = 'net.bounceme.mordor.Main'
repositories {
mavenCentral()
maven { url "https://jitpack.io" }
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.10'
compile 'com.github.THUFIR:hello_api:latest'
}
jar {
manifest {
attributes ('Main-Class': 'net.bounceme.mordor.Main',
"Class-Path": configurations.compile.collect { it.getName() }.join(' '))
}
}
Notably, the jitpack dependency doesn't show in Netbeans:
The build artifact at the end of the log would seem to indicate that the JAR, hello_api-latest.jar, was found:
latest
commit 244c611ae48dc95daee544fbfb5767ae1f961e10
Author: thufir
Date: Fri Feb 5 05:39:47 2016 -0800
increment
submodule status:
Run gradle build
Gradle build script
WARNING: Gradle wrapper not found. Please add. Using default gradle to build.
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
------------------------------------------------------------
Gradle 2.7
------------------------------------------------------------
Build time: 2015-09-14 07:26:16 UTC
Build number: none
Revision: c41505168da69fb0650f4e31c9e01b50ffc97893
Groovy: 2.3.10
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.8.0_60 (Oracle Corporation 25.60-b23)
OS: Linux 3.14.32-xxxx-grs-ipv6-64 amd64
0m0.684s
Getting a list of gradle tasks
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
Found javadoc task
WARNING:
Gradle 'install' task not found. Please add the 'maven' or 'android-maven' plugin.
See the documentation and examples: https://jitpack.io/docs/
Looking for android-library
Looking for com.android.application
Adding maven plugin
Running: gradle clean -Pgroup=com.github.THUFIR -Pversion=latest -xtest install
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
:clean UP-TO-DATE
:compileJava
Download https://repo1.maven.org/maven2/org/codehaus/groovy/groovy-all/2.4.1/groovy-all-2.4.1.pom
Download https://repo1.maven.org/maven2/org/codehaus/groovy/groovy-all/2.4.1/groovy-all-2.4.1.jar
:processResources UP-TO-DATE
:classes
:jar
:install
BUILD SUCCESSFUL
Total time: 1.883 secs
Gradle exit code 0
Looking for artifacts...
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
Found artifact: com.github.THUFIR:hello_api:latest
EXIT_CODE=0
2016-03-10T09:47:34.133966887Z
Exit code: 0
Build artifacts:
com.github.THUFIR:hello_api:latest
Files:
com/github/THUFIR/hello_api/latest
com/github/THUFIR/hello_api/latest/build.log
com/github/THUFIR/hello_api/latest/hello_api-latest.jar
com/github/THUFIR/hello_api/latest/hello_api-latest.pom
com/github/THUFIR/hello_api/latest/hello_api-latest.pom.md5
com/github/THUFIR/hello_api/latest/hello_api-latest.pom.sha1
but where was it downloaded to?
see also:
https://stackoverflow.com/a/22724504/262852
https://stackoverflow.com/a/30094915/262852
https://stackoverflow.com/a/34329145/262852
UPDATE
here it is:
thufir#mordor:~$
thufir#mordor:~$ tree .gradle/ | grep latest
│   │   │   └── latest
│   │   │   │   └── hello_api-latest.pom
│   │   │   └── hello_api-latest.jar
│   │   │   │   └── latest
│   │   │   │   └── latest
thufir#mordor:~$
As with any external dependency, it is downloaded to the gradle cache. The default location is ~/.gradle

#Pathvariable not found compilation error [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
Im trying to execute a Spring MVC project using Maven but get a compilation error while maven packaging -
Error
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.0:compile (default-compile) on project CounterWebApp: Compilation failure
[ERROR] /home/prem1980/apache-maven/all_maven_projects/java_webapp_project/CounterWebApp/src/main/java/com/mkyong/controller/BaseController.java:[23,36] cannot find symbol
[ERROR] symbol : class PathVariable
[ERROR] location: class com.mkyong.controller.BaseController
java file
package com.mkyong.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/")
public class BaseController {
#RequestMapping(value="/welcome", method = RequestMethod.GET)
public String welcome(ModelMap model) {
model.addAttribute("message", "Maven Web Project + Spring 3 MVC - welcome()");
//Spring uses InternalResourceViewResolver and return back index.jsp
return "index";
}
#RequestMapping(value="/welcome/{name}", method = RequestMethod.GET)
public String welcomeName(#PathVariable String name, ModelMap model) {
model.addAttribute("message", "Maven Web Project + Spring 3 MVC - " + name);
return "index";
}
}
Project structure
[pr#web449 CounterWebApp]$ tree .
.
├── pom.xml
├── src
│   └── main
│   ├── java
│   │   └── com
│   │   └── mkyong
│   │   └── controller
│   │   └── BaseController.java
│   ├── resources
│   └── webapp
│   └── WEB-INF
│   ├── index.jsp
│   ├── mvc-dispatcher-servlet.xml
│   └── web.xml
└── target
├── classes
├── generated-sources
│   └── annotations
└── maven-status
└── maven-compiler-plugin
└── compile
└── default-compile
└── createdFiles.lst
Add the import statement
import org.springframework.web.bind.annotation.PathVariable;
I think you are missing the spring-web jar in your classpath. The spring-web jar contains that annotation.
Ensure that your pom.xml contains:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
Ensure you have spring-web jar.
If you check where org.springframework.web.bind.annotation.PathVariable is located you will find that it is within above jar:
http://mvnrepository.com/artifact/org.springframework/spring-web/3.0.4.RELEASE
Of course the jar version may be different, just ensure to use yours. You can find spring-web versions here:
http://mvnrepository.com/artifact/org.springframework/spring-web
And as Reimeus pointed in his answer, you need the import as well.

Categories