Could not autowire bean in test class - spring-mvc

I have a project with Spring MVC and Spring Boot and I use IntelliJ.
My Project is like this :
main -> java -> mypackage -> authentification -> WebSecurityConfig.java
-> configuration -> ApplicationConfiguration.java
-> controller -> WelcomeMessageController.java
-> service -> WelcomeMessageService.java
-> Impl -> WelcomeMessageServiceImpl.java
test -> java -> mypackage -> WelcomeMessageTest.java
I annotate the service implementation with #Service.
I annotate the configuration file with
#Configuration
#ComponentScan(basePackages = "mypackage")
In the controller, I inject the service with
#Autowired
WelcomeMessageService welcomeMessageService;
In the test class, I inject the same service with the same annotation:
#Autowired
WelcomeMessageService welcomeMessageService;
I annotate the test class with :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ApplicationConfiguration.class, loader = SpringApplicationContextLoader.class)
#WebAppConfiguration
In the controller, the injection works fine but in the test class, IntelliJ says:
Could not autowire. No beans of type WelcomeService found.
When I run the test it works, but I don't understand why IntelliJ says that it can't find the bean.
I found this topics that says that it happens some time with IntelliJ but I don't want to use the #SuppressWarnings annotation.
Does anyone have another solution to solve this problem ?

For me it was a component scan issue my models are in a separate module then my Spring Boot App. Normally, #SpringBootApplication has a #ComponentScan which when not specified will scan as follows:
Either {#link #basePackageClasses} or {#link #basePackages} (or
its alias * {#link #value}) may be specified to define specific
packages to scan. If specific * packages are not defined, scanning
will occur from the package of the * class that declares this
annotation.
If your SpringBootApp Main class is on a different package then you want to specify the ComponentScan. Same thing if you are using multiple modules, specify it on your Configuration class.
Config class Annotations:
#Configuration
#ComponentScan(basePackages = "app.data")
Testclass Annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = { PropertyPlaceholderAutoConfiguration.class, DynamoConfig.class })

I had the same issue of not being able to AutowWire beans into the Integration test classes. Your question helped me in solving that with the addition of "ContextConfiguration" annocation instead of "SpringApplicationConfiguration" which I was using.
However the only difference I can see now is that you are missing the #EnableAutoConfiguration in the Application class (which extendends SpringBootServletInitializer) or the class where you have your #Configuration.
Hopefully that should resolve your issue. Bottom line is this is caused to inappropriate annotations at in this very specific case.

Related

bundle's service (autowire) not available in controller's method

I'd like to use https://github.com/tedious/TedivmStashBundle bundle in my symfony 4 project. Added by composer, configured in /config/stash.yaml file and according to the profiler bar, it's working basically.
Now, I want to use to caching values in my controller. I've try to add the service stash by its name to the method's parameter, using the same name as the example says:
$pool = $this->container->get('stash');
but the framework did not find the service. It can't be added like the example explained neither.
How can I use this bundle as a service (autowired) in my symfony 4 app?
UPDATE
services.yaml:
stash.default_cache:
class: Tedivm\StashBundle\Service\CacheService
public: true
arguments:
$name: 'stash'
Tedivm\StashBundle\Service\CacheService: '#stash.default_cache'
Controller:
public function something(Request $request, CacheService $service, ...
It's looks like working now :)
Thanx for the suggestion (and the correct solution later) to #Cerad
Here is an example of how to approach this sort of problem when dealing with bundles that are not quite ready for autowire.
Start by installing a test project:
symfony new --full stash --version=lts
composer require tedivm/stash-bundle
Note that the bundle does not directly support Symfony 5 hence the lts. Note also that the bundles does not support Flex so you have to add your own config/packages/stash.yaml file per the bundle's readme file.
# config/packages/stash.yaml
stash:
drivers: [ FileSystem ]
FileSystem: ~
At this point we can determine which service we need to inject:
bin/console debug:container stash
Information for Service "stash.default_cache"
=============================================
Class CacheService
---------------- -----------------------------------------
Option Value
---------------- -----------------------------------------
Service ID stash.default_cache
Class Tedivm\StashBundle\Service\CacheService
Most of the time you would like to use an interface for injection but a peek at the source code reveals that the bundle does not use interfaces. As a side note, calling a third party service 'stash' is not a good idea. It really should have been 'tedivm.stash' but I digress.
We can now create an alias and then typehint against it:
# config/services.yaml
Tedivm\StashBundle\Service\CacheService : '#stash' # alias for typehinting
# Controller class
public function index(CacheService $cacheService)
{
return new Response('Cache ' . get_class($cacheService));
}
And that should do it.

Servlet class is not a javax.servlet.Servlet while deploying a bundle in felix jetty

I am trying to deploy an OSGI bundle in felix jetty. BootStrap is my class which extends HttpServlet.
I am getting the below Exception at deployment stage :
ins.server.servlet.HttpServlet30Dispatcher is not assignable from javax.servlet.http.HttpServlet
2018-07-11T07:46:55,044 WARN sure-rest-neo [] web-reactor - unavailable
javax.servlet.UnavailableException: Servlet class com.nokia.mdf.sure.neo.utils.Bootstrap is not a javax.servlet.Servlet
at org.eclipse.jetty.servlet.ServletHolder.checkServletType(ServletHolder.java:519) ~[jetty-servlet-9.3.10.v20160621.jar:9.3.10.v20160621]
at org.eclipse.jetty.servlet.ServletHolder.doStart(ServletHolder.java:379) ~[jetty-servlet-9.3.10.v20160621.jar:9.3.10.v20160621]
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) ~[jetty-util-9.3.10.v20160621.jar:9.3.10.v20160621]
at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:874) ~[jetty-servlet-9.3.10.v20160621.jar:9.3.10.v20160621]
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:349) ~[jetty-servlet-9.3.10.v20160621.jar:9.3.10.v20160621]
at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1404) ~[jetty-webapp-9.3.10.v20160621.jar:9.3.10.v20160621]
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1366) ~[jetty-webapp-9.3.10.v20160621.jar:9.3.10.v20160621]
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:778) ~[jetty-server-9.3.10.v20160621.jar:9.3.10.v20160621]
at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:262) ~[jetty-servlet-9.3.10.v20160621.jar:9.3.10.v20160621]
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:520) ~[jetty-webapp-9.3.10.v20160621.jar:9.3.10.v20160621]
I have embedded all dependencies including the transitive ones. How to resolve this, which I assume is due to jar conflict ?
The problem is exactly with embedding dependencies. When you embed the javax.servlet package then your bundle will use the embedded class while jetty will use the class available from an exported package. So while these classes are named the same there are different instances in the classloaders which leads to exactly this kind of error.
To generally solve this you make sure that ideally only one bundle exports each package and all bundles that need it import the package. So the easiest solution is to not embed dependencies.
If that does not work for you then you can try to import and export the javax.servlet package in your bundle. This allows the OSGi environment to decide which package it will actually wire and avoid having the same class names with different instances in bundles.

how to set active profile for gradle build of spring boot application?

Here is the DbConfig of my spring-boot application.
#Configuration
#EnableTransactionManagement
public class DBConfig
{
#Bean
public LocalSessionFactoryBean sessionFactory()
{
....
}
#Bean
public DataSource aaDataSource()
{
.....
}
public PlatformTransactionManager transactionManager()
{
....
}
private Properties hibernateProperties()
{
....
}
}
Here is my test class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class ApplicationTests {
#Test
public void contextLoads() {
}
}
Its a gradle project.
when I run gradlew clean build locally, I get successful build since my connection settings in application.properties matches my sql connection.
But when I run from jenkins box in our qa environment (the database is qa one), the build fails with following exception.
java.lang.IllegalStateException: Failed to load ApplicationContext
....
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean]: Factory method 'entityManagerFactory' threw exception; nested exception is com.zaxxer.hikari.pool.PoolInitializationException: Exception during pool initialization
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(Abstract
.....
Caused by: com.zaxxer.hikari.pool.PoolInitializationException: Exception during pool initialization
at com.zaxxer.hikari.pool.BaseHikariPool.initializeConnections(BaseHikariPool.java:544)
at com.zaxxer.hikari.pool.BaseHikariPool.<init>(BaseHikariPool.java:171)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:60)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:48)
.....
Caused by: java.sql.SQLException: Access denied for user 'admin1'#'localhost' (using password: YES)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:998)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3835)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3771)
I tried running gradlew clean build -Dspring.profiles.active=qa with application-qa.properties in the src/main/resources/ that have qa db settings. The build still failed with same exception.
I have two options.
run the build skipping datasource bean creation. I still need my units tests to be run since they don't rely on datasource
or pass the right settings to gradle build so that application context is created.
I prefer second option to get it working
If your requirement is that you control this externally (i.e., via the command line when launching Gradle), you can then modify your Gradle test task configuration as follows.
test {
systemProperty("spring.profiles.active", project.properties.get("springProfiles"))
// ...
}
And then you can set a value for springProfiles like this: gradlew clean build -PspringProfiles=ci (where ci is the name of the profile you want active on the CI server).
The above will make spring.profiles.active available as a JVM system property for your tests; however, you'd still need to set the active profiles for the Spring TestContext Framework.
To do that, you need to annotate your test class with #ActiveProfiles, but instead of passing in static profiles you'd need to implement a custom ActiveProfilesResolver and register it via #ActiveProfiles(resolver = MyCustomResolver.class). Your customer resolver could then read then simply return the value of the spring.profiles.active system property.
Another option is to implement a custom ApplicationContextInitializer that programmatically sets the active profiles (similar to the custom ActiveProfilesResolver). You can configure one of those via #SpringApplicationConfiguration(initializers = MyCustomInitializer.class).
And yet another option would be to programmatically set the active profiles directly in your SpringApplication -- for example, based on a system property or environment variable.
So, you have several options.

Unit testing a symfony service class with phpunit

I have a basic class GenericHelper.php in directory Foo/BarBundle/Helper
I registered it as a service in Foo/BarBundle/Resources/config/services.yml:
parameters:
generic_helper.class: Foo\BarBundle\Helper\GenericHelper
services:
generic_helper:
class: %generic_helper.class%
and I'm able to access it in a command by doing the following:
$helper = $this->getContainer()->get('generic_helper');
Now, I'd like to unit test that class with PHPUnit; I have the following code (similar to http://symfony.com/doc/2.0/book/testing.html#unit-tests):
namespace Foo\BarBundle\Tests\Helper;
use Foo\BarBundle\Helper\GenericHelper;
class GenericHelperTest extends \PHPUnit_Framework_TestCase {
public function testSomeMethod() {
$helper = new GenericHelper(); //line 10
$this->assertEquals($helper->someMethod(), SOME_RESULT);
}
}
Running PHPUnit results in the following error:
PHP Fatal error: Class 'Foo\BarBundle\Helper\GenericHelper' not found in /DIR/src/Foo/BarBundle/Tests/Helper/GenericHelperTest.php on line 10
Grepping for 'GenericHelper' only yields a few results:
the Class itself and the Test class
the services.yml file
appDevDebugProjectContainer files in app/cache/dev/, which have all the service getters
Question(s):
Does Symfony prevent PHPUnit from directly constructing a service class?
Is there a way to do this without creating a Symfony Container then accessing the service (as done here: Access Symfony 2 container via Unit test?)? I mean, it's still just a basic class...
Running phpunit with the -c flag pointing to the directory containing the phpunit.xml.dist file solved the issue. Doing this includes bootstrap.php.cache and therefore the autoloading stuff necessary.

seam solder (former weld-extensions project) is not initialized

I want to use logger in my java web application.
I'm using JBossAS 6.0.0.final, cdi (weld), jsf ... etc. Seam solder proposes to use an abstract logger is not tying to a concrete implementation (slf4j, log4j, etc) using jboss-logging api.
In order to get this logger in your code will need to write
# Inject
org.jboss.logging.Logger log
seam-solder.jar has the producer for this logger.
package org.jboss.seam.solder.log;
...
class LoggerProducers
{
# Produces
org.jboss.logging.Logger produceLog (InjectionPoint injectionPoint) {}
}
When I deploying my application, I get an error
15:51:18,300 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to Start: name=vfs:///C:/Java/jboss-6.0.0.Final/server/default/deploy/kamis-web-client.5.0.0-SNAPSHOT.ear_WeldBootstrapBean state=Create: org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [Logger] with qualifiers [#Default] at injection point [[field] #Inject private ru.kamis.suite.webclient.web.breadcrumbs.BreadcrumbsManager.log]
This is due to the seam-solder.jar has not META-INF/beans.xml file, and it is necessary for cdi container.
If to add beans.xml file in seam-solder.jar manually, then the application works WELL.
How to do without hacks?
To build my application I use maven, so my solution is not comfortable and NOT fine.
PS: Former weld-extensions project contained META-INF/beans.xml file in jar.
with seam-solder-3.0.0.Beta1 there should be no need to modify the jar

Resources