Seems my Junit test runs in runtime, the datasource missing - java

I used a H2 database in unit test, use java configuration:
#Configuration #EnableJpaRepositories(basePackageClasses = AdvertisementRepository.class) public class EmbeddedDatabaseConfig {
/**
* Creates DataSource for an embedded Database (H2).
*/
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
and set scope to test in pom.xml:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.184</version>
<scope>test</scope>
</dependency>
It's successfully build and in JUnit test, but when I run it on server, it reports error:
java.lang.ClassNotFoundException: org.h2.Driver
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1274)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1108)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:250)
at org.springframework.jdbc.datasource.embedded.H2EmbeddedDatabaseConfigurer.getInstance(H2EmbeddedDatabaseConfigurer.java:48)
at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseConfigurerFactory.getConfigurer(EmbeddedDatabaseConfigurerFactory.java:39)
... 51 more
I'm confused: the junit test won't run in runtime, right? why my code automatically read the java config class, and not found driver class?

While I will not be able to point out the exact issue, the problem you are facing is that org.h2.Driver is not available while trying to run the test. As mentioned in one of the comments make sure that jar is available in the classpath.
PS: If you are using an Ant build and trying to run test before deploying to production, make sure the jar is available before ANT runs your tests.

Related

Spring Boot Microservices JUnit Test- Controller Test- JWT JwtGrantedAuthoritiesConverter Issue

I tried to implement some controller test with the usage of jwt in Spring Boot Microservices.
When I run the test method shown below, I got this error
java.lang.NoClassDefFoundError: org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverter
Caused by: java.lang.ClassNotFoundException: org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter
Here is the code snippets shown below.
#Test
public void test_WhenPlaceOrderWithWrongAccess_thenThrow403() throws Exception {
OrderRequest orderRequest = getMockOrderRequest();
MvcResult mvcResult
= mockMvc.perform(MockMvcRequestBuilders.post("/order/placeOrder")
.with(jwt().authorities(new SimpleGrantedAuthority("ADMIN"))) // HERE IS THE ERROR LINE
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(orderRequest))
).andExpect(MockMvcResultMatchers.status().isForbidden())
.andReturn();
}
Even if I added spring-security-oauth2-resource-server dependency in pom.xml of order service, It didn't help me fix the issue.
Here are the issue shown below after adding spring-security-oauth2-resource-server dependency in pom.xml of order service.
java.lang.NoClassDefFoundError: org/springframework/security/oauth2/jwt/Jwt$Builder
Caused by: java.lang.ClassNotFoundException: org.springframework.security.oauth2.jwt.Jwt$Builder
How can I fix the issue?
Here is the link of example : Link
Probably, you only need the dependencies
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
but not spring-security-oauth2-resource-server
Double check that spring-security-oauth2-resource-server dependency is correctly declared: scope compile (must be there at runtime and test) and version 5.2 or above (JwtGrantedAuthoritiesConverter was not there before). You might pull it as transitive dependency of spring-boot-starter-oauth2-resource-server. So basically, check that:
spring-boot-starter-oauth2-resource-server is declared dependency for each resource-server module
security-configuration is there for each resource-server module
JwtDecoder is mocked for each unit-test (#WebMvcTest) and integration test with mocked authentication (#SpringBootTest with #AutoConfigureMockMvc)
Sorry to tell you that, but your code is a mess:
no parent pom to manage modules versions (had to manually mvn install modules in the right order.
you test security rules in modules with no security configuration
some resource-servers do not pull spring-boot-starter-oauth2-resource-server (products service for instance)
you write integration tests (#SpringBootTest) to unit test controllers (should be #WebMvcTest with #MockBean dependencies)
have to run configuration server for test to run (you should configure unit-tests to run in isolation from the rest of the world, starting with external services like cloud-config)
...
Cleanup your mess before asking us to look into your code.
For now, all I can tell you is to follow those tutorials. It covers in details resource-servers security configuration and testing. It also demoes how to use annotations in place of jwt() MockMvc post-processor. Annotations are more readable to me and also enable to setup security context when testing secured services:
#WithMockJwtAuth("ROLE_USER")
#Test
public void test_WhenPlaceOrder_DoPayment_Success() throws Exception {
OrderRequest orderRequest = getMockOrderRequest();
MvcResult mvcResult
= mockMvc.perform(MockMvcRequestBuilders.post("/order/placeOrder")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(orderRequest))
).andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
...
}

How can I use the SQLServerDriver in IntelliJ when I run/debug a file's main()?

I am able to use the SQLServerDriver when I run my project through maven and can successfully read/write to my db. I'm testing some changes in a specific file and I'm trying to test that individual file by right-clicking the file and running the file.
When it gets to run the setup code it throws an exception (java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver).
The code:
Connection conn = null;
Class.forName(dbDriverMsSQL);
conn = DriverManager.getConnection(dbConnectionString);
with this separately defined:
public static String dbDriverMsSQL = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
I'm using the following dependency in my pom.xml:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>7.4.1.jre8</version>
<scope>test</scope>
</dependency>
Is there some additional setting that I have to configure to be able to read/write from my main()?
Posting #TomStroemer 's comment to mark this resolved:
Your dependency scope is test - do you use this code in a Test? If not this might cause the error. You can also try Class.forName(SQLServerDriver.class); If IntelliJ can't find the import you have a problem with your depenencies.
I removed the scope and I could run successfully.

Caused by: java.lang.NoSuchMethodError: org.springframework.data.mongodb.core.MongoTemplate.<init>(Lcom/mongodb/Mongo;Ljava/lang/String;)V

While trying to run Spring-boot application (v2.1.0) getting below error:
Description:
An attempt was made to call the method org.springframework.data.mongodb.core.MongoTemplate.(Lcom/mongodb/Mongo;Ljava/lang/String;)V but it does not exist. Its class, org.springframework.data.mongodb.core.MongoTemplate, is available from the following locations:
file:/C:/Users/npatil/.m2/repository/org/springframework/data/spring-data-mongodb/2.1.2.RELEASE/spring-data-mongodb-2.1.2.RELEASE.jar!/org/springframework/data/mongodb/core/MongoTemplate.class
It was loaded from the following location:
file:/C:/Users/npatil/.m2/repository/org/springframework/data/spring-data-mongodb/2.1.2.RELEASE/spring-data-mongodb-2.1.2.RELEASE.jar
Action:
Correct the classpath of your application so that it contains a single, compatible version of org.springframework.data.mongodb.core.MongoTemplate
Below is a snnipet from my pom:
<dependencies>
.
.
<dependency>
<groupId>com.github.mongobee</groupId>
<artifactId>mongobee</artifactId>
<version>0.13</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
.
.
</dependencies>
Version of some of the jars that could help are:
spring-data-mongodb : 2.1.2.RELEASE
spring-web : 5.1.2.RELEASE
mongo-java-driver : 3.8.2.RELEASE
Deleted .m2 and did mvn clean install, but even that did not resolve the issue. Any help would be greatly appreciated.
Looks like jar is corrupted or missing,
check all spring related jar are 4.x or higher version
if that doent work then:
Mongobee depends on Spring 4.x jars which may conflicts with Spring boot 2.x
try the below way
#Bean
public Mongobee mongobee(){
Mongobee mongobee = new Mongobee("mongodb://localhost:27017/seed");
mongobee.setChangeLogsScanPackage(InitialData.class.getPackageName());
mongobee.setMongoTemplate(template);
return mongobee;
}
You need change Mongobee by Mongock if you use Springboot 2. The syntax is almost the same because the Mongock project is the continuation of the Mongobee project.
Springboot:
#Bean
public SpringBootMongock mongock(ApplicationContext springContext, MongoClient mongoClient) {
return (SpringBootMongock) new SpringBootMongockBuilder(mongoClient, "yourDbName", "com.package.to.be.scanned.for.changesets")
.setApplicationContext(springContext)
.setLockQuickConfig()
.build();
}
Spring:
#Bean
public SpringMongock mongock() {
MongoClient mongoclient = new MongoClient(new MongoClientURI("yourDbName", yourMongoClientBuilder));
return new SpringMongockBuilder(mongoclient, "yourDbName", "com.package.to.be.scanned.for.changesets")
.setLockQuickConfig()
.build();
}

Problems with Testing Spring Boot Application with Multi Maven Project Setup

I am currently running into some problems with spring boot and multi maven project structure. I am using Spring Boot 4.3.1.
My project structure looks as follows:
parent
-- pom.xml
-- application
-- pom.xml
-- src
-- main
-- java
-- Application.java (annotated with #SpringBootApplication)
-- test
-- java
-- MyApplicationTest.java (annotated with #SpringBootTest)
-- library
-- pom.xml
-- src
-- main
-- java (...)
-- test
-- java
-- MyLibraryTest.java (annotated with #SpringBootTest)
application module has a dependency on library.
MyApplicationTest works perfectly fine, but running MyLibraryTest instead, I fail with the following error:
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test at org.springframework.util.Assert.state(Assert.java:392)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.getOr FindConfigurationClasses(SpringBootTestContextBootstrapper.java:173)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.processMergedContextConfiguration(SpringBootTestContextBootstrapper.java:133)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:409)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:305)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildTestContext(AbstractTestContextBootstrapper.java:112)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.buildTestContext(SpringBootTestContextBootstrapper.java:78)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:120)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:105)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTestContextManager(SpringJUnit4ClassRunner.java:152)
My first guess is that library needs a dependency on application, but this causes a cycle.
Is there any solution to that problem?
How can I structure my application correctly?
thanks a lot for suggestions.
MyLibraryTest looks as follow:
#RunWith(SpringRunner.class)
#SpringBootTest
#Transactional
public class MyLibraryTest {
#Autowired
private MyService service;
#Test
public void testMyService_Save() {...}
}
You need to make sure that the library module's pom.xml includes -
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
which is required for the module to use the #SpringBootTest annotation. You might already be using the same in your app module but is not included in the library module.
Well post the Edit, found the question to be possibly a duplicate of Unable to find a #SpringBootConfiguration when doing a JpaTest
Also quoting from Thomas's answer from the same thread, here
The thing about #DataJpaTest and a few other annotations is that they
look for a #SpringBootConfiguration annotation in the current package,
and if they cannot find it there, they traverse the package hierarchy
until they find it.
For example, if the fully qualified name for your test class was
com.example.test.JpaTest and the one for your application was
com.example.Application, then your test class would be able to find
the #SpringBootApplication (and therein, the
#SpringBootConfiguration).
If the application resided in a different branch of the package
hierarchy, however, like com.example.application.Application, it would
not find it.
which seems to be the case for you, where you are trying to test an application in a different module itself. Hence the error that you see.

JPA/EclipseLink: Understanding ClassLoader issues

EDIT: Although a (good) answer was given and awarded, this only covers a rather unimportant part of my question. The main parts of this question are still open.
I use EclipseLink (2.6.2) in a cloud project. The project is a web application packaged as a WAR file and deployed on Apache Tomcat 8. The persistence context is set up using Java code, where I specify the entities to use using entityManagerFactoryBean.setPackagesToScan(packagesToScan). This configuration normally works as expected, where exactly the entity classes in the specified packages are found.
I now fail to understand when to use which classloader, especially when considering Tomcat, running tests, and using different connection pool implementations.
When running on Apache Tomcat including Tomcat's connection pool, the DataSource instance is created using the spring-cloud-connector plugin (spring-cloud-spring-service-connector).
In this setting everything works as expected, as long as I don't change the classloader as described below (otherwise I face ClassNotFoundExceptions for the entity classes).
When running unit tests with the help of JUnit and spring-test, the DataSource instance is created using the in-memory database H2 (using EmbeddedDatabaseBuilder from spring-jdbc). In this setting I have to specify JPA to use the classloader used for the DataSource instance (key eclipselink.classloader in the JPA properties map), otherwise I get "Object ... is not a known Entity type".
When running tests in an embedded Apache Tomcat 8, I don't see any message indicating the connection pool in use. In this setting I also have to set the classloader as for the unit tests.
If I add commons-dbcp (2.1.1) to my project and explicitly configure the spring-cloud-connector plugin to use it instead of Tomcat's connection pool, I can run the application on Tomcat without configuring the classloader, but it also works with the classloader specification described above.
For the tests the commons-dbcp does not change anything compared to the scenarios outlined above (as the corresponding configuration is not used).
Summary:
Tomcat (Tomcat CP): only using the unmodified classloader for JPA
Tomcat (DBCP): both variants
Tests: only using DataSource's classloader for JPA
Could you help me understand the differences here, and suggest a simple solution suitable for all cases? I assume that DBCP and Spring use a different classloader than Tomcat (and Tomcat's connection pool).
If you need further information, I will happily add it.
EDIT: I added an example project with a big README on how to reproduce.
https://github.com/C-Otto/classloaderexample
"I get another error when I start using mvn tomcat7:run, use Tomcat's
connection pool (CloudDatabaseConfig) and do not re-configure the
classloder (JpaConfig):"
You must configure the PostreSQL dependency on the maven plugin. You are getting ClassNot found because the PostgreSQL JAR is not in the path:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
</configuration>
<!-- For any extra dependencies needed when running embedded Tomcat (not WAR dependencies) add them below -->
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1206-jdbc41</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
Also have a look at https://tomcat.apache.org/maven-plugin-2.2/run-mojo-features.html
I forgot to include the class loader change on (JpaConfigWithDatasourceClassloader.getJPAProperties):
properties.put(CLASSLOADER, new java.net.URLClassLoader(
((java.net.URLClassLoader)classLoader).getURLs(), JpaConfigWithDatasourceClassloader.class.getClassLoader() )
) ;
With this you can run all variants using tomcat7:run

Categories