Could not instantiate TestExecutionListener - java

When I run my selenium test below from within Eclipse, I get a series of Could not instantiate TestExecutionListener messages in my log.
This is the actual test.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SeleniumConfig.class)
public final class TestWebpage {
private static final Logger LOG = Logger.getLogger(TestWebpage.class);
#Autowired
private WebDriver driver;
#Test
public void testLoadingPage() {
LOG.debug("Hello World!");
}
}
And this is the log
0 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
5 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Could not instantiate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute]
6 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Could not instantiate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource]
7 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Could not instantiate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [javax/servlet/ServletContext]
8 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.support.DependencyInjectionTestExecutionListener#152c95a3, org.springframework.test.context.support.DirtiesContextTestExecutionListener#22140b31]
127 [main] INFO org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext#35523de0: startup date [Wed Oct 01 01:20:22 EST 2014]; root of context hierarchy
3961 [main] DEBUG org.rmb.selenium.external.TestWebpage - Hello World!
3963 [Thread-8] INFO org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext#35523de0: startup date [Wed Oct 01 01:20:22 EST 2014]; root of context hierarchy
Note that I am using Spring 4.1.0.RELEASE.
One Solution, three Extra Dependencies
I noticed in the answer to a previous question the suggestion to add #WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SeleniumConfig.class)
#WebAppConfiguration
public final class TestWebpage {
Which I then needed three extra dependencies in my pom.xml to support:
javax.servlet-api
spring-jdbc
spring-web
Why do I need all this extra when I am not actually using JDBC at all, or anything using spring-web/servlet - this is just a selenium test with some of my own configuration.
Is there an easier way? Am I missing something bigger?
Config Class
This is the class I configure my tests with.
public final class SeleniumConfig {
#Bean
public String baseUrl() {
return "http://localhost:8888/";
}
#Bean
public WebDriver driver() {
return new CloseableFirefoxDriver();
}
class CloseableFirefoxDriver extends FirefoxDriver implements DisposableBean {
public void destroy() throws Exception {
quit();
}
}
}
POM
My pom.xml (before I added the extra dependencies).
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>WebAppWithSeleniumTest</groupId>
<artifactId>WebAppWithSeleniumTest</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>WebAppWithSeleniumTest Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.43.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
<build>
<finalName>WebAppWithSeleniumTest</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<targetPath>${basedir}/target/classes</targetPath>
<includes>
<include>log4j.properties</include>
</includes>
</resource>
</resources>
</build>
<description>Web App with Selenium Tests - a base</description>
<properties>
<spring.version>4.1.0.RELEASE</spring.version>
</properties>
</project>

If I leave in the three extra dependencies
javax.servlet-api
spring-jdbc
spring-web
I can leave my test class defined as this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SeleniumConfig.class)
public final class TestWebpage {
and I will get this logging:
0 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
20 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener#3997ebf6, org.springframework.test.context.support.DependencyInjectionTestExecutionListener#25048104, org.springframework.test.context.support.DirtiesContextTestExecutionListener#4ab24098, org.springframework.test.context.transaction.TransactionalTestExecutionListener#7caee177, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener#3d548b94]
132 [main] INFO org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext#6f55137: startup date [Wed Oct 01 21:55:02 EST 2014]; root of context hierarchy
4183 [main] DEBUG org.rmb.selenium.external.TestWebpage - Hello World!
4186 [Thread-8] INFO org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext#6f55137: startup date [Wed Oct 01 21:55:02 EST 2014]; root of context hierarchy
No errors, but obviously Spring is doing a fair bit of work in the background.
Alternatively, I can remove the three extra dependencies and add this minimal #TestExecutionListeners annotation.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SeleniumConfig.class)
#TestExecutionListeners(listeners = {DependencyInjectionTestExecutionListener.class})
public final class TestWebpage {
I get logging as below:
0 [main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.support.DependencyInjectionTestExecutionListener#4fce6eaf]
117 [main] INFO org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext#42695958: startup date [Wed Oct 01 21:59:05 EST 2014]; root of context hierarchy
4189 [main] DEBUG org.rmb.selenium.external.TestWebpage - Hello World!
4190 [Thread-8] INFO org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext#42695958: startup date [Wed Oct 01 21:59:05 EST 2014]; root of context hierarchy
At least no errors.
As to why I need any of this, I don't understand yet. I am leaving this here as a reference, at the very least to show the minimal changes required to get rid of the Could not instantiate TestExecutionListener messages.

To stay close to the original Spring implementation, use this instead:
#TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class })
as defined in org.springframework.test.context.TestContextManager:
private static final String[] DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES = new String[] {
"org.springframework.test.context.web.ServletTestExecutionListener",
"org.springframework.test.context.support.DependencyInjectionTestExecutionListener",
"org.springframework.test.context.support.DirtiesContextTestExecutionListener",
"org.springframework.test.context.transaction.TransactionalTestExecutionListener" };
Only ServletTestExecutionListener should be evicted.

Any INFO messages like:
Could not instantiate TestExecutionListener org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
Can safely be ignored if you are not using or testing JDBC or WEB related spring features. That is just an INFO message telling us that Spring did not activate these listeners as the required dependencies (pom dependencies) have not been added. Which is fine, in case you are not using those features.
However lets say you are using #Sql to load some test data into a database, AND you see this warning, THEN we need to wire in required dependencies (spring-jdbc with test scope in your project pom.xml) in order for the required listener (SqlScriptsTestExecutionListener in this case) to be activated by Spring

At least for my setup using TestNG, the original answer was not quite enough. I had to add the following annotation:
#TestExecutionListeners(inheritListeners = false, listeners =
{DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})

Related

Maven Surefire Plugin not logging from org.junit.jupiter.api package

I'm getting some inconsistent behaviour in my unit test logging when either:
Running tests via IntelliJ's Run interface
Running tests via mvn test
I really want to see the following log statements when running mvn test, however they do not seem to be visible:
May 12, 2022 12:00:13 PM org.junit.jupiter.api.ClassOrderer$Random <clinit>
CONFIG: ClassOrderer.Random default seed: 155513463168987
May 12, 2022 12:00:13 PM org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter logSuccessMessage
CONFIG: Using default class orderer 'org.junit.jupiter.api.ClassOrderer$Random' set via the 'junit.jupiter.testclass.order.default' configuration parameter.
May 12, 2022 12:00:13 PM org.junit.jupiter.api.MethodOrderer$Random <clinit>
CONFIG: MethodOrderer.Random default seed: 155513483010989
Inside my pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.config.file>
${project.build.testOutputDirectory}/logging.properties
</java.util.logging.config.file>
</systemPropertyVariables>
</configuration>
</plugin>
Contents of src/test/resources/logging.properties:
.level=CONFIG
.handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=CONFIG
When running tests via IntelliJ's Run interface, I can see the following output, with the desired logs towards the bottom:
/Users/ian.jones/Library/Java/JavaVirtualMachines/openjdk-17.0.2/Contents/Home/bin/java -ea -Djava.util.logging.config.file=/Users/ian.jones/Development/my-app/target/test-classes/logging.properties -Didea.test.cyclic.buffer.size=1048576 -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=61653:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath [omitted for brevity] com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 com.myorg.OpenApiDocsGeneratorTest
May 12, 2022 12:00:13 PM org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry loadTestEngines
CONFIG: Discovered TestEngines with IDs: [junit-jupiter (group ID: org.junit.jupiter, artifact ID: junit-jupiter-engine, version: 5.8.2, location: jar:file:/Users/ian.jones/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.8.2/junit-jupiter-engine-5.8.2.jar!/org/junit/jupiter/engine/JupiterTestEngine.class)]
May 12, 2022 12:00:13 PM org.junit.platform.launcher.core.ServiceLoaderRegistry load
CONFIG: Loaded PostDiscoveryFilter instances: []
May 12, 2022 12:00:13 PM org.junit.platform.launcher.core.ServiceLoaderRegistry load
CONFIG: Loaded LauncherDiscoveryListener instances: []
May 12, 2022 12:00:13 PM org.junit.platform.launcher.core.ServiceLoaderRegistry load
CONFIG: Loaded TestExecutionListener instances: [org.junit.platform.launcher.listeners.UniqueIdTrackingListener#2781e022]
May 12, 2022 12:00:13 PM org.junit.platform.launcher.core.LauncherConfigurationParameters loadClasspathResource
CONFIG: Loading JUnit Platform configuration parameters from classpath resource [file:/Users/ian.jones/Development/my-app/target/test-classes/junit-platform.properties].
May 12, 2022 12:00:13 PM org.junit.platform.launcher.core.ServiceLoaderRegistry load
CONFIG: Loaded LauncherSessionListener instances: []
May 12, 2022 12:00:13 PM org.junit.platform.launcher.core.LauncherConfigurationParameters loadClasspathResource
CONFIG: Loading JUnit Platform configuration parameters from classpath resource [file:/Users/ian.jones/Development/my-app/target/test-classes/junit-platform.properties].
May 12, 2022 12:00:13 PM org.junit.jupiter.api.ClassOrderer$Random <clinit>
CONFIG: ClassOrderer.Random default seed: 155513463168987
May 12, 2022 12:00:13 PM org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter logSuccessMessage
CONFIG: Using default class orderer 'org.junit.jupiter.api.ClassOrderer$Random' set via the 'junit.jupiter.testclass.order.default' configuration parameter.
May 12, 2022 12:00:13 PM org.junit.jupiter.api.MethodOrderer$Random <clinit>
CONFIG: MethodOrderer.Random default seed: 155513483010989
May 12, 2022 12:00:13 PM org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter logSuccessMessage
CONFIG: Using default method orderer 'org.junit.jupiter.api.MethodOrderer$Random' set via the 'junit.jupiter.testmethod.order.default' configuration parameter.
However, when running mvn clean install, the logs which are important to me do not appear:
[INFO] --- maven-surefire-plugin:3.0.0-M5:test (default-test) # my-app ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[ERROR] May 12, 2022 12:10:06 PM org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry loadTestEngines
[ERROR] CONFIG: Discovered TestEngines with IDs: [junit-jupiter (group ID: org.junit.jupiter, artifact ID: junit-jupiter-engine, version: 5.8.2, location: jar:file:/Users/ian.jones/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.8.2/junit-jupiter-engine-5.8.2.jar!/org/junit/jupiter/engine/JupiterTestEngine.class)]
[ERROR] May 12, 2022 12:10:06 PM org.junit.platform.launcher.core.ServiceLoaderRegistry load
[ERROR] CONFIG: Loaded PostDiscoveryFilter instances: []
[ERROR] May 12, 2022 12:10:06 PM org.junit.platform.launcher.core.ServiceLoaderRegistry load
[ERROR] CONFIG: Loaded LauncherDiscoveryListener instances: []
[ERROR] May 12, 2022 12:10:06 PM org.junit.platform.launcher.core.ServiceLoaderRegistry load
[ERROR] CONFIG: Loaded TestExecutionListener instances: [org.junit.platform.launcher.listeners.UniqueIdTrackingListener#76c3e77a]
[ERROR] May 12, 2022 12:10:06 PM org.junit.platform.launcher.core.LauncherConfigurationParameters loadClasspathResource
[ERROR] CONFIG: Loading JUnit Platform configuration parameters from classpath resource [file:/Users/ian.jones/Development/my-app/target/test-classes/junit-platform.properties].
[ERROR] May 12, 2022 12:10:06 PM org.junit.platform.launcher.core.ServiceLoaderRegistry load
[ERROR] CONFIG: Loaded LauncherSessionListener instances: []
[INFO] Running ...
I have tried changing the version of maven-surefire-plugin to 3.0.0-M4 or 3.0.0-M6 but in both cases, this results in all the CONFIG logs disappearing from the output.
I have also tried explicitly setting the handlers for the classes in question, e.g.:
org.junit.jupiter.api.MethodOrderer$Random.handlers=java.util.logging.ConsoleHandler
But all this does is result in duplicate output log lines when running tests with Run, and doesn't change the output when running tests with mvn test.
Clearly it's partially working in that it is reading logging.config in both cases (if I remove this file, all CONFIG logs disappear when running mvn test) - but I have no idea why the behaviour is different, or how to fix that.
EDIT: Minimal pom.xml file
Here's a minimal pom.xml demonstrating the issue (I'm using Maven 3.8.5)
<?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>org.example</groupId>
<artifactId>surefire-problem-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.config.file>
${project.build.testOutputDirectory}/logging.properties
</java.util.logging.config.file>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
Introduction
Let's consider the following versions as the current versions:
Maven Surefire Plugin 3.0.0-M7.
JUnit 5.8.2.
Root cause analysis
Analysis
Maven Surefire Plugin uses its JUnitPlatformProvider class. It may be observed in the output right before the «Tests» section:
<…>
[INFO] --- maven-surefire-plugin:3.0.0-M7:test (default-test) # the-project ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
<…>
Please, see the implementation of the JUnitPlatformProvider.setupJunitLogger() method: maven-surefire/JUnitPlatformProvider.java at surefire-3.0.0-M7 · apache/maven-surefire:
private static void setupJunitLogger()
{
Logger logger = Logger.getLogger( "org.junit" );
if ( logger.getLevel() == null )
{
logger.setLevel( WARNING );
}
}
Please, note the condition:
logger.getLevel() == null
Please, see the documentation of the Logger.getLevel() method:
public Level getLevel()
Get the log Level that has been specified for this Logger. The result may be null, which means that this logger's effective level will be inherited from its parent.
Returns:
this Logger's level
Please, note the statement:
The result may be null, which means that this logger's effective level will be inherited from its parent.
Analysis summary
This is (see the «Analysis» subsection) why:
A parent logger configuration is not taken into account by Maven Surefire Plugin.
It does not seem to be a user-friendly behavior.
Maybe, it is worth reporting it as a Maven Surefire Plugin issue.
It is necessary to introduce the explicit logger configuration for the org.junit package.
Solution
It is necessary to introduce the explicit logger configuration for the org.junit package:
org.junit.level=CONFIG
Follow-up: Checking provided complete pom.xml file
I have used the provided complete pom.xml file with the following preconditions.
I had used the same preconditions to test the solution.
Preconditions
Added test classes
Added 3 test classes annotated with #TestMethodOrder(MethodOrderer.Random.class) like this one:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
#TestMethodOrder(MethodOrderer.Random.class)
public class Application1Test {
#Test
public void shouldAnswerWithTrue() {
Assertions.assertTrue(true);
}
#Test
public void shouldAnswerWithTrue2() {
Assertions.assertTrue(true);
}
}
Enabled parallel test execution
The content of the src/test/resources/junit-platform.properties file:
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
Added JUnit-related log level
The content of the src/test/resources/logging.properties:
.level=CONFIG
.handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=CONFIG
org.junit.level=CONFIG
Output
$ ./mvnw clean test 2>&1 | grep -F 'MethodOrderer.Random'
CONFIG: MethodOrderer.Random default seed: 7225497639767

spring boot - #PostConstruct not called on #Component

I am new to spring, and I have created a new spring boot project using https://start.spring.io/ with no further dependencies, unzipped the zip file and opened the project in IntelliJ IDEA. I have not done any further configurations. I am now trying to setup a bean with a #PostConstruct method - however, the method is never invoked by spring.
These are my classes:
SpringTestApplication.java
package com.habichty.test.testspring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
#SpringBootApplication
public class SpringTestApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringTestApplication.class, args);
context.getBean(TestBean.class).testMethod();
}
}
TestBean.java
package com.habichty.test.testspring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component
public class TestBean {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private int a = 1;
public TestBean()
{
log.debug("Constructor of TestBean called.");
}
#PostConstruct
public void init()
{
log.debug("init()-Method of TestBean called.");
a = 2;
}
public void testMethod()
{
log.debug("Test Method of TestBean called. a=" + a);
}
}
When I start the application, this is my output:
:: Spring Boot :: (v1.5.9.RELEASE)
2018-01-22 13:15:57.960 INFO 12035 --- [ main] c.h.t.testspring.SpringTestApplication : Starting SpringTestApplication on pbtp with PID 12035 (/home/pat/prj/testspring/testspring/target/classes started by pat in /home/pat/prj/testspring/testspring)
2018-01-22 13:15:57.962 DEBUG 12035 --- [ main] c.h.t.testspring.SpringTestApplication : Running with Spring Boot v1.5.9.RELEASE, Spring v4.3.13.RELEASE
2018-01-22 13:15:57.962 INFO 12035 --- [ main] c.h.t.testspring.SpringTestApplication : No active profile set, falling back to default profiles: default
2018-01-22 13:15:58.018 INFO 12035 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext#2931522b: startup date [Mon Jan 22 13:15:58 CET 2018]; root of context hierarchy
2018-01-22 13:15:58.510 DEBUG 12035 --- [ main] com.habichty.test.testspring.TestBean : Constructor of TestBean called.
2018-01-22 13:15:58.793 INFO 12035 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-01-22 13:15:58.822 INFO 12035 --- [ main] c.h.t.testspring.SpringTestApplication : Started SpringTestApplication in 1.073 seconds (JVM running for 2.025)
2018-01-22 13:15:58.822 DEBUG 12035 --- [ main] com.habichty.test.testspring.TestBean : Test Method of TestBean called. a=1
2018-01-22 13:15:58.826 INFO 12035 --- [ Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#2931522b: startup date [Mon Jan 22 13:15:58 CET 2018]; root of context hierarchy
2018-01-22 13:15:58.828 INFO 12035 --- [ Thread-1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
As you can see, spring initializes the TestBean and also executes the testMethod() - but the init()-Method, annotated with #PostConstruct, is not invoked.
What am I doing wrong?
Any help is very appreciated.
UPDATE 1
In my application.properties, I have configured:
logging.level.com = DEBUG
Changing this to logging.level.root = DEBUG results in a massively bigger log. However, it still does not contain the debug message of my init() method.
UPDATE 2 Added package and import statements.
UPDATE 3 To further clarify that this is not a logging issue, I have added an new int to the code that should be altered by the init()-Method. As far as I understood the concept of the #PostConstruct annotation, it should be executed prior to any other method execution. As a consequence, the output of testMethod() should now contain a=2. In the updated output, you may see that this is not the case.
UPDATE 4 This is my 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>com.habichty.test.testspring</groupId>
<artifactId>springTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springTest</name>
<description>springTest</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The output of java -version:
java version "9.0.1"
Java(TM) SE Runtime Environment (build 9.0.1+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)
Due to the new module system in Java9 SpringBoot-1.5.9 fails to process #PostConstruct as the annotation class is not on the classpath. The problem (or similar) is described here and here. There are a few ways to resolve it:
run the application with Java8, or, if still on Java9:
add javax.annotation:javax.annotation-api dependency to the POM, or
upgrade to a newer Spring-Boot of version 2.0.0+ (which is still PRERELEASE as of this writing) which incorporates that dependency;
I know this Problem is already solved, but as it is the first Stackoverflow Question that came up when I googled this problem I will leave this here:
I had the same issue and my error was that I had a typo in my package names. My class which was calling name had a different packagename than my SpringBootApplication class. So my main application was not finding my component.
So always check your package names if you have a similiar problems.
I guess you did not define something like
logging.level.root=debug
in your application.properties?
Without = no logs
With =
2018-01-22 12:34:06.117 DEBUG 8516 --- [main] com.example.demo.TestBean : Constructor of TestBean called.
...
2018-01-22 12:34:06.117 DEBUG 8516 --- [main] com.example.demo.TestBean : init()-Method of TestBean called.
...
2018-01-22 12:34:06.241 DEBUG 8516 --- [main] com.example.demo.TestBean : Test Method of TestBean called.
If you are using Java 9 or higher, then you will encounter an error when using #PostConstruct and #PreDestroy in your code.
Eclipse is unable to import #PostConstruct or #PreDestroy
When using Java 9 and higher, javax.annotation has been removed from its default classpath. That's why Eclipse can't find it.
Solution
Download the javax.annotation-api-1.3.2.jar from
https://search.maven.org/remotecontent?filepath=javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar
Copy the JAR file to the lib folder of your project
Use the following steps to add it to your Java Build Path.
Right-click your project, select Properties
On the left-hand side, click Java Build Path
In the top-center of dialog, click Libraries
Click Classpath and then Click Add JARs ...
Navigate to the JAR file /lib/javax.annotation-api-1.3.2.jar
Click OK then click Apply and Close
Eclipse will perform a rebuild of your project and it will resolve the related build errors.

Spring cloud config cannot load native config file unless the filename is application

Something strange happened to me. I have no idea about how to solve it that the spring cloud config cannot load native or cloud config file unless it's filename is 'application.yml/application.properties'.
The below code is my configuration:
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>micro-certification-config-center</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
ConfigServer:
#SpringBootApplication
#EnableConfigServer
public class ConfigServer {
public static void main(String[] args) {
SpringApplication.run(ConfigServer.class, args);
}
}
application.yml:
server:
port: 8000
spring:
cloud:
config:
server:
native:
search-locations: classpath:/shared
profiles:
active: native
The shared folder structor:
resources
-- shared
-- -- application-dev.yml
-- -- sms-dev.yml
It looks good and run well with no errors, but when I visit http://127.0.0.1:8000/configCenter/dev/master, it only shows the application property source.
The response:
{
"name": "configCenter",
"profiles": [
"dev"
],
"label": "master",
"version": null,
"state": null,
"propertySources": [
{
"name": "classpath:/shared/application-dev.yml",
"source": {
"logging.level.org.springframework.security": "INFO",
"eureka.instance.prefer-ip-address": true,
"eureka.client.serviceUrl.defaultZone": "http://registry:8761/eureka/",
"security.oauth2.resource.user-info-uri": "http://auth-service:5000/uaa/users/current",
"spring.rabbitmq.host": "rabbitmq"
}
}
]
}
The server console:
2017-08-24 22:34:08.055 INFO 30010 --- [nio-8000-exec-4] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext#4a931797: startup date [Thu Aug 24 22:34:08 CST 2017]; root of context hierarchy
2017-08-24 22:34:08.062 INFO 30010 --- [nio-8000-exec-4] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2017-08-24 22:34:08.075 INFO 30010 --- [nio-8000-exec-4] o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: classpath:/shared/application-dev.yml
2017-08-24 22:34:08.075 INFO 30010 --- [nio-8000-exec-4] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#4a931797: startup date [Thu Aug 24 22:34:08 CST 2017]; root of context hierarchy
All above shows the 'application.yml' file only worked.
Can someone help me? Thanks very much!
The external config can help you that. The detail is here: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
You can change this default application config to the external one by command like in the guide line:
If you don’t like application.properties as the configuration file
name you can switch to another by specifying a spring.config.name
environment property. You can also refer to an explicit location using
the spring.config.location environment property (comma-separated list
of directory locations, or file paths).
$ java -jar myproject.jar --spring.config.name=myproject or
$ java -jar myproject.jar
--spring.config.location=classpath:/default.properties,classpath:/override.properties
Or in your code you can put it like:
new SpringApplicationBuilder(Application.class)
.properties("spring.config.name:YOUR_EXTERNAL_CONFIG_FILE")
.build()
.run(args);
}
Hope this help.
As #spencergibb said, if I want to load sms-dev.yml, I should rename application.name to sms.

Spring Boot web application doesn't serve standard endpoints

I have a problem with a Spring Boot Application that is supposed to run from command line and at the same time serve some metrics from the standard /metrics endpoint. When I just created the application all the metrics were served correctly, but at some point I seem to have "broken" something and my application stopped serving from default endpoints. I can't just revert to the initial state because there's a lot of code already and I don't want to lose version control history. Maybe someone could point at what I am doing wrong?
I don't override dispatcher servlet and don't add any custom filters.
Spring Boot version 1.3.7.
Error when accessing /metrics or any other default endpoint:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing
this as a fallback.
Mon Oct 03 17:53:12 PDT 2016 There was an unexpected error (type=Not
Found, status=404). No message available
Application file:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Runner.class, args);
}
}
Main runner file:
#EnableConfigurationProperties(ApplicationProperties.class)
#SpringBootApplication
public class Runner implements CommandLineRunner {
#Override
public void run(String... strings) throws Exception {
// shortened ...
}
}
POM file fragment:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.7.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
Debug output shows that the filters are created:
2016-10-03 17:26:14.461 DEBUG 85880 --- [ost-startStop-1] o.s.b.c.e.ServletContextInitializerBeans : Added existing Servlet initializer bean 'dispatcherServletRegistration'; order=2147483647, resource=class path resource [org/springframework/boot/autoconfigure/web/DispatcherServletAutoConfiguration$DispatcherServletConfiguration.class]
2016-10-03 17:26:14.720 DEBUG 85880 --- [ost-startStop-1] o.s.b.c.e.ServletContextInitializerBeans : Created Filter initializer for bean 'metricFilter'; order=-2147483648, resource=class path resource [org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfiguration.class]
I created a sample clean application to compare and there are lines in output that I don't have in my app:
2016-10-03 18:06:48.075 DEBUG 86858 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : 2 request handler methods found on class org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint: {public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)={[/{name:.*}],methods=[GET],produces=[application/json]}, public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()={[],methods=[GET],produces=[application/json]}}
2016-10-03 18:06:48.076 INFO 86858 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/metrics/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2016-10-03 18:06:48.076 INFO 86858 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/metrics || /metrics.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
So, the filters/servlet seem to be created but not mapped in my app.
What am I possibly missing here?
OK I was stupid. Could say it twice.
So, after all, the problem was my bad memory. I actually was overriding application properties like this:
management.contextPath=/services/admin
Guess what, my /metrics was there all the time. It was just under /services/admin/metrics, which I completely forgot to have overridden. Duh.

What's wrong within the usage of BeanFactoryAnnotationUtils?

I'm trying to do simple call to the method
BeanFactoryAnnotationUtils.qualifiedBeanOfType
Here the pom.xml of the project :
<?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>beanfactoryannotationutils.sample</groupId>
<artifactId>BeanFactoryAnnotationUtilsProblem</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.1.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!-- Spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
The Application.java class
#SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
ListableBeanFactory beanFactory = ctx.getBeanFactory();
// This is working ... (#Autowired with #Qualifier(...) too)
Map<String, QualifiedInterface> qualifiedBeans = beanFactory.getBeansOfType(QualifiedInterface.class);
System.out.println("Existing qualified beans ...");
for (QualifiedInterface qualifiedBean : qualifiedBeans.values()) {
System.out.println(" " + qualifiedBean.toString());
for (Annotation annotation : qualifiedBean.getClass().getAnnotations()) {
System.out.println(" - " + annotation.toString());
}
}
// This is working too ...
Map<String, Object> qualifiedBeansFromCtx = ctx.getBeansWithAnnotation(Qualifier.class);
System.out.println("Existing qualified beans from context ...");
for (Object qualifiedBean : qualifiedBeansFromCtx.values()) {
System.out.println(" " + qualifiedBean.toString());
for (Annotation annotation : qualifiedBean.getClass().getAnnotations()) {
System.out.println(" - " + annotation.toString());
}
}
// This is not ...
QualifiedInterface processor = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
beanFactory, QualifiedInterface.class, "QualifierA");
System.out.println("The selected processor should be A " + processor);
}
}
An interface QualifiedInterface.java
public interface QualifiedInterface {
}
Two beans QualifiedA.java
#Component
#Qualifier("QualifierA")
public class QualifiedA implements QualifiedInterface {
#Override
public String toString() {
return "QualifiedA";
}
}
and QualifiedB.java :
#Component
#Qualifier("QualifierB")
public class QualifiedB implements QualifiedInterface {
#Override
public String toString() {
return "QualifiedB";
}
}
The whole in the same package and application, now run it :
2015-12-24 15:08:34.468 INFO 9524 --- [ main] l.p.e.b.Application : Starting Application on DTBE-DEV4 with PID 9524 (D:\Workspace_netbeans\BeanFactoryAnnotationUtilsProblem\target\classes started by eguenichon in D:\Workspace_netbeans\BeanFactoryAnnotationUtilsProblem)
2015-12-24 15:08:34.478 INFO 9524 --- [ main] l.p.e.b.Application : No profiles are active
2015-12-24 15:08:34.618 INFO 9524 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext#11e18e8c: startup date [Thu Dec 24 15:08:34 CET 2015]; root of context hierarchy
2015-12-24 15:08:37.516 INFO 9524 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2015-12-24 15:08:37.524 INFO 9524 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
2015-12-24 15:08:37.672 INFO 9524 --- [ main] l.p.e.b.Application : Started Application in 3.715 seconds (JVM running for 4.355)
Existing qualified beans ...
QualifiedA
- #org.springframework.stereotype.Component(value=)
- #org.springframework.beans.factory.annotation.Qualifier(value=QualifierA)
QualifiedB
- #org.springframework.stereotype.Component(value=)
- #org.springframework.beans.factory.annotation.Qualifier(value=QualifierB)
Existing qualified beans from context ...
QualifiedA
- #org.springframework.stereotype.Component(value=)
- #org.springframework.beans.factory.annotation.Qualifier(value=QualifierA)
QualifiedB
- #org.springframework.stereotype.Component(value=)
- #org.springframework.beans.factory.annotation.Qualifier(value=QualifierB)
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'QualifierA' is defined: No matching QualifiedInterface bean found for qualifier 'QualifierA' - neither qualifier match nor bean name match!
at org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils.qualifiedBeanOfType(BeanFactoryAnnotationUtils.java:100)
at org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils.qualifiedBeanOfType(BeanFactoryAnnotationUtils.java:56)
at beanfactoryannotation.sample.beanfactoryannotationutilsproblem.Application.main(Application.java:45)
2015-12-24 15:08:37.684 INFO 9524 --- [ Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#11e18e8c: startup date [Thu Dec 24 15:08:34 CET 2015]; root of context hierarchy
2015-12-24 15:08:37.686 INFO 9524 --- [ Thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 0
2015-12-24 15:08:37.691 INFO 9524 --- [ Thread-1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
The BeanFactoryAnnotationUtils.qualifiedBeanOfType doesn't seems to works as the qualified beans exists in the context but could not be retrieved. Do you have an idea of what's the problem is here ?
Thanks !
This is not provided before Spring 4.3 due to the default specification of the BeanFactoryAnnotationUtils class.
See : https://jira.spring.io/browse/SPR-13819
While looking at the code behind the BeanFactoryAnnotationUtils.qualifiedBeanOfType(...) method, I noticed that the qualifier is checked from an AbstractBeanDefinition object. When I dump this object on our example I can notice that the "qualifiers" map is empty ?!?!?
It looks like a bug in the way Spring loads the bean definition with annotated qualifiers.
There is already an open issue that looks quite similar: https://jira.spring.io/browse/SPR-13452
I guess you could open another one specifically with your test case.

Categories

Resources