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();
}
}
Related
I have a Spring project with the following structure:
.
├── pom.xml
├── core-module
│ ├── pom.xml
│ └── src
│ ├── main
│ │ ├── java
│ │ └── resources
│ │ ├── applicationContext.xml
│ │ └── file.xml
│ └── test
│ ├── java
│ └── resources
│ ├── file.xml
│ └── foo.xml
└── web-module
├── pom.xml
└── src
├── main
│ └── java
└── test
└── java
In my applicationContext.xml file, I have the following import:
<import resource="classpath:file.xml" />
In production I want to use the file.xml defined in main, and during tests I want to use the one defined in the test folder; it's actually what is happenning when I run the tests of the core-module.
However, when I run the tests of the web-module, this is not the case, the file used is the one of the main folder.
How to perform what I want?
Some notes:
web-module has a test-jar dependency to core-module, so tests resources are included;
if I go inside the target directory, the file.xml is the good one in the test-classes folder;
when running web-module tests, if I put a breakpoint in the Spring code, then a getClass().getClassLoader().getResource() on file.xml returns the one defined in main, but if I run the same method on the foo.xml file it returns me the only one available in the test folder, so both files seems to be present, but it acts as if the main takes over the test resource...
Thank you!
I'm trying to use application.properties to bean datasource but it seems that spring boot does not find the file or something like.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Here my structure:
.
├── build.gradle
└── src
└── main
├── java
│ └── com
│ └── companies
│ ├── CompanyApplication.java
│ ├── config
│ │ └── WebMvcConfig.java
│ ├── controller
│ │ └── HelloWorldController.java
│ └── model
│ ├── Article.java
│ ├── daoInterface
│ │ └── ArticleDaoInterface.java
│ ├── daoTemplates
│ │ └── ArticleDao.java
│ └── mappers
│ └── ArticleMapper.java
├── resources
│ └── application.properties
└── webapp
└── WEB-INF
└── pages
└── hello.jsp
I've try to move application.properties file from resources to config and nothing.
application.properties:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/name
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
build.gradle
buildscript {
repositories {
//Required repos
mavenCentral()
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
}
dependencies {
//Required dependency for spring-boot plugin
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.2.6.RELEASE"
}
}
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'spring-boot'
jar {
baseName = 'companies'
version = '0.2'
}
war {
baseName = 'companies'
version = '0.1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
compile("org.springframework.boot:spring-boot-starter")
compile("org.springframework:spring-jdbc")
compile('org.springframework.boot:spring-boot-starter-jdbc:1.2.6.RELEASE')
testCompile("junit:junit")
//Required dependency for JSP
compile 'org.apache.tomcat.embed:tomcat-embed-jasper'
}
And where I'm trying to autowire the dataSource:
package com.companies.model.daoTemplates;
import com.companies.model.Article;
import com.companies.model.daoInterface.ArticleDaoInterface;
import com.companies.model.mappers.ArticleMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.util.List;
#Repository
public class ArticleDao implements ArticleDaoInterface {
private JdbcTemplate jdbcTemplateObject;
private final String DB_NAME = "articles";
#Override
#Autowired
public void setDataSource(DataSource ds) {
this.jdbcTemplateObject = new JdbcTemplate(ds);
}
#Override
public List<Article> listArticle() {
String SQL = "select * from " + DB_NAME + " where inactive = false ORDER BY name";
List <Article> article = jdbcTemplateObject.query(SQL,
new ArticleMapper());
return article;
}
}
CompanyApplication.java
package com.companies;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class CompanyApplication {
public static void main(String[] args) {
SpringApplication.run(CompanyApplication.class, args);
}
}
I cannot find where I'm failing at.
As #M. Deinum mentioned in his comment it seems to be a dependency configuration problem. You need a dependency on spring-jdbc for an embedded database to be auto-configured.
Please make sure you've followed on the documentation
You should also check out this spring-boot-jdb sample
Spring boot is mostly based on the principle than putting a specific jar in the classpath will trigger the activation of the related functionality. Spring boot is scanning the classpath at startup and will start "everything he found" except if you disable it by using annotation.
So to have Spring Boot initializing a DataSource you must have one of the following dependencies:
- spring-boot-starter-jdbc : will allow to use the DataSource and JDBC stuff.
- spring-boot-starter-data-jpa : will load the JPA and so the DataSource as a sub-module
I got a similar error and I solved it by adding the following dependency
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.5.0</version>
</dependency>
This should be the correct declaration of your runner class:
package com.companies;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class CompanyApplication {
public static void main(String[] args) {
System.exit(SpringApplication.exit(
SpringApplication.run(CompanyApplication.class, args)));
}
}
Amidst other things, it will auto-initialize your DataSource from the application.properties.
EDIT: in your application.properties you should have entries similar to these, which are specific for an Oracle DataSource:
spring.datasource.url=jdbc:oracle:thin:#<hostaddr>:<port>:<instance_name>
spring.datasource.username=<username>
spring.datasource.password=<password>
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
I've faced this problem and figured out that implementation of DataSource is placed in Tomcat libs. So for 8th tomcat you going to include org.apache.tomcat.jdbc.pool.DataSource class that placed in org.apache.tomcat:tomcat-jdbc:jar:8.0.36
I had the same problem. In my case I solved it by adding the dependency for the mysql java connector.
I have a tree that looks like this:
In the java folder, I have a package, com.example.project which has a Main class and an Application class that subclasses ResourceConfig
#ApplicationPath("api")
public class Application extends ResourceConfig {
public Application() {
packages("com.example.project");
property(MustacheMvcFeature.TEMPLATE_BASE_PATH, "templates");
register(MustacheMvcFeature.class);
register(MyRequestFilter.class);
}
}
In development, I run the Main class and start a Grizzly server:
public class Main {
public static HttpServer startServer(String BASE_URI) {
final Application app = new Application();
return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), app);
}
public static void main(String[] args) throws IOException {
String BASE_URI = "http://localhost:8080/api";
final HttpServer server = startServer(BASE_URI);
server.getServerConfiguration().addHttpHandler(
new StaticHttpHandler("src/main/webapp"), "/");
System.out.println(String.format(
"Jersey app started with WADL available at "
+ "%s/application.wadl\nHit enter to stop it...", BASE_URI)
);
System.in.read();
}
}
Everything works fine with the Grizzly server. I'm now trying to deploy to tomcat.
I use mvn package to create a war file. In my pom file, I have:
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
I put the war file in the webapps directory under a tomcat instance and it gets exploded there. My static content is served.
The layout of the directory that comes from the WAR file looks like this:
[vagrant#vagrant-centos6 project]$ tree .
.
├── index.html
| ... <webapp content>
├── META-INF
│ ├── MANIFEST.MF
│ └── maven
│ └── com.example.project
│ └── project
│ ├── pom.properties
│ └── pom.xml
└── WEB-INF
├── classes
│ ├── com
│ │ └── example
│ │ └── project
│ │ ├── Application.class
│ │ ├── Main.class
| | ...
│ ├── filter-dev.properties
│ ├── filter-test.properties
│ ├── hibernate.cfg.xml
│ └── templates
│ └── foo.mustache
└── lib
...
I can not locate any of my REST services. Everything I try is 404.
Directory in tomcat webapps is project, javax.ws.rs.ApplicationPath is api, #Path is service. So, I would hope to get a response from /project/api/service, for instance. But, after trying many combinations, everything is 404.
You need to add jersey-servlet.jar to your war file.
In pom.xml, that might look like this:
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
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.
In an android project, I want to use a shared model library with the REST Server(JPA)
Project structure:
├── android
│ └ ...
│
├── model
│ ├── build.gradle
│ └── src
│ └── com
│ └── model // error at runtime
│ └── Customer.java
├── server
│ ├── build.gradle
│ └── src
│ └── com
│ └── server
│ ├── Application.java
│ ├── CustomerController.java
│ ├── CustomerRepository.java
│ └── model // works fine
│ └── Customer.java
├── build.gradle
I am using gradle sub-projects to manage the dependency which works fine at compile time.
But when I run the Application, Spring can't resolve the JPA annotations.
When I move the model class to the server project, it works fine.
Exception in thread "main" org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [...] Instantiation of bean failed;
[...]
Not an managed type: class com.model.Customer
root build.gradle
buildscript { ... }
allprojects {
repositories {
mavenCentral()
}
}
project(":android") { ... }
project(":model") {
apply plugin: "java"
}
project(":server") {
apply plugin: "java"
dependencies {
compile project(":model")
}
}
Is there a solution to include JPA models from a gradle sub-project ?
The reason is mostly to prevent duplicate code between the android and server appication
You Customer entity will not be found by default because it is not in a sub-pacakge of your Application class. Try using the #EntityScan annotation (see http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-separate-entity-definitions-from-spring-configuration).