I'm trying to run some unit tests in my Spring Boot application and getting the following errors:
I can't tell if this is because it can't connect to my database in Heroku (ClearDB) or if I have some annotation wrong within my code.
I have the environment variables being loaded into my application-dev.properties file at runtime, all that information can be seen at the bottom.
Error
java.lang.NullPointerException
at com.algoq.algoq.services.AlgorithmService.getSubscribers(AlgorithmService.java:26)
at com.algoq.algoq.ExampleTest.subscriberListNull(ExampleTest.java:42)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Test Class
package com.algoq.algoq;
import com.algoq.algoq.models.Subscriber;
import com.algoq.algoq.respositories.SubscriberRepository;
import com.algoq.algoq.services.AlgorithmService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import static org.assertj.core.api.Assertions.assertThat;
#RunWith(SpringRunner.class)
#TestConfiguration
#SpringBootTest(classes = {
AlgoQApplication.class,
})
public class ExampleTest extends AlgoQApplicationTests {
#Autowired
private AlgorithmService aService;
#MockBean
private SubscriberRepository employeeRepository;
#Bean
public AlgorithmService aService() {
return new AlgorithmService();
}
#Test
public void subscriberListNull() throws Exception {
ArrayList<Subscriber> subs = aService.getSubscribers();
assertThat(subs).isEmpty();
}
}
Service Class
package com.algoq.algoq.services;
import com.algoq.algoq.models.Subscriber;
import com.algoq.algoq.respositories.SubscriberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
#Service
public class AlgorithmService {
#Autowired
private SubscriberRepository subRep;
/**
* Gets a list of subscribers to return to the API
* #return
*/
public ArrayList<Subscriber> getSubscribers() {
ArrayList<Subscriber> subscribers = new ArrayList<>();
subRep.findAll()
.forEach(subscribers::add);
return subscribers;
}
/**
* Adds a new subscriber to the database
* #param sub
* #return
*/
public void addSubscriber(Subscriber sub) {
subRep.save(sub);
}
/**
* Finds a single user id
* #param email
* #return
*/
public List<Subscriber> getSubscriber(String email) {
return subRep.findByEmailAddress(email);
}
}
POM
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
<groupId>com.algoQ</groupId>
<artifactId>algo-q</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>algo-q</name>
<description>An algorithm a day keeps the brain up to date</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.9</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.12</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-standalone</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<!--<dependency>-->
<!--<groupId>com.h2database</groupId>-->
<!--<artifactId>h2</artifactId>-->
<!--<version>1.4.196</version>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
<!--<dependency>-->
<!--<groupId>com.h2database</groupId>-->
<!--<artifactId>h2</artifactId>-->
<!--<version>1.4.194</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.pygments</groupId>
<artifactId>pygments</artifactId>
<version>1.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
App Properties
server.port = 5600
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=${MAIL_USER}
spring.mail.password=${MAIL_PASS}
#mail properties
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.thymeleaf.cache=false
spring.thymeleaf.mode=HTML5
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url = ${MYSQL_HOST}
spring.datasource.username = ${MYSQL_USERNAME}
spring.datasource.password = ${MYSQL_PASSWORD}
spring.datasource.tomcat.max-active=20
spring.datasource.maxIdle=2
spring.datasource.tomcat.remove-abandoned=true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
You are using #MockBean which, underneath, uses Mockito.mock to create a mock of your bean. The default behavior of a mock is to return default values and in this case it will return null as the default value. Hence it will break on the forEach
What you need to do is tell your mock what to do on a specific method call. In your case you might want to return an empty list. In your test method you would need to add something along these lines.
#Test
public void subscriberListNull() throws Exception {
Mockito.when(employeeService.findAll)).thenReturn(new ArrayList());
ArrayList<Subscriber> subs = aService.getSubscribers();
assertThat(subs).isEmpty();
}
This is also inline with the default for Spring Data JPA as that will never return null from a collection returning method. If there are no results you will get an empty collection.
Related
I'm very new to Spring Boot and software development.
I want to redirect http requests to https counterpart. Https and the rest of the functionality seems to work fine
Thank you for your input!
`
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>taco-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>taco-cloud</name>
<description>Taco Cloud Example</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
`
`
package tacos.config;
import com.fasterxml.jackson.databind.annotation.JsonAppend;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import tacos.model.User;
import tacos.repository.UserRepository;
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
public class SecurityConfig {
#Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Bean
public UserDetailsService userDetailsService(UserRepository userRepository){
return username -> {
User user = userRepository.findByUsername(username);
if (user != null) return user;
throw new UsernameNotFoundException("User " + username + "not found");
};
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception{
return httpSecurity.authorizeRequests().
antMatchers("/design","/orders","/orders/*").hasRole("USER").
antMatchers("/", "/**").permitAll().
antMatchers("/h2-console/**").permitAll().
and().
csrf().ignoringAntMatchers("/h2-console/**").
and().
headers().frameOptions().sameOrigin().
and().
formLogin().loginPage("/login").
loginProcessingUrl("/authenticate").
usernameParameter("user").
passwordParameter("pwd").
defaultSuccessUrl("/design", true).and().
oauth2Login().loginPage("/login").and().
logout().
and().
requiresChannel().anyRequest().requiresSecure().
and().
portMapper().http(8080)
.mapsTo(8443).
and().build();
}
}
`
I saw a number of questions here where answer was to add portMapper().http(8080).mapsTo(8443) to configuration. But for me this doesn't solve the issue.
I saw other much more cumbersome solutions involving TomcatEmbeddedServletContainerFactory
With lots of googling and trial and error I found this solution https://www.javadevjournal.com/spring-boot/spring-boot-ssl/
But I'm still wondering why the above solution didn't work
#Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {#Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(redirectConnector());
return tomcat;
}
private Connector redirectConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8443);
return connector;
}
I have a test project where I'm trying to setup e2e api tests using rest-assured. Tests run fine if I run them from the feature files, however, when I try to run them with maven, 0 tests run. I believe there is something funky with my pom.xml but I can't figure it out...
My project structure looks like:this
My pom.xml:
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.0</version>
</parent>
<artifactId>qa-automation-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<groupId>com</groupId>
<packaging>jar</packaging>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-bom</artifactId>
<version>7.2.3</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-path</artifactId>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>xml-path</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<properties>
<configurationParameters>
cucumber.junit-platform.naming-strategy=long
</configurationParameters>
</properties>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
My Application.java
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
#PropertySources({
#PropertySource("classpath:application.properties")
})
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
My CucumberSpringConfiguration.class
import io.cucumber.spring.CucumberContextConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import com.Application;
#CucumberContextConfiguration
#SpringBootTest(classes = Application.class)
public class CucumberSpringConfiguration {
}
My CucumberTest.java
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
#Suite
#IncludeEngines("cucumber")
#SelectClasspathResource("src/test/resources/example")
#ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example")
public class CucumberTest {
}
I'm not really familiar with Spring though so I'm pretty sure I'm not using it correctly in my ApiTestStepDef.java
package com.example;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import io.cucumber.java.en.Given;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.Assertions;
import org.springframework.beans.factory.annotation.Autowired;
import com.client.RestAssuredClient;
import com.model.User;
import com.utils.Helper;
import static io.restassured.RestAssured.given;
public class ApiTestStepDef {
private Response response;
private RequestSpecification request;
private User user;
private User responseBody;
#Autowired
private RestAssuredClient restAssuredClient;
#Given("{string} endpoint")
public void setBaseUsersURI(String url){
request =
given().log().all().
spec(restAssuredClient.createReqSpec(url));
}
#When("user posts request with details {string} {string} {string}")
public void sendRequest(String name, String gender, String status){
user = new User(name, gender, Helper.createRandomEmail(), status);
response =
request.given().log().all().
body(user).
when().
post().
then().log().all().
extract().response();
}
#Then("response status code is {int} and response contains correct user details")
public void checkResponseStatusCode(int statusCode){
response.then().spec(restAssuredClient.createResSpec(statusCode));
responseBody = response.getBody().as(User.class);
Assertions.assertEquals(user.getGender(), responseBody.getGender());
Assertions.assertEquals(user.getStatus(), responseBody.getStatus());
Assertions.assertEquals(user.getEmail(), responseBody.getEmail());
Assertions.assertEquals(user.getName(), responseBody.getName());
}
}
And RestAssuredClient.java
package com.client;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import static io.restassured.RestAssured.oauth2;
#Component
public class RestAssuredClient {
#Value("${access.token}")
private String accessToken;
#Value("${base.uri}")
private String baseUri;
public ResponseSpecification createResSpec(int statusCode){
return
new ResponseSpecBuilder()
.expectStatusCode(statusCode)
.expectContentType(ContentType.JSON)
.build();
}
public RequestSpecification createReqSpec(String url){
return new RequestSpecBuilder()
.setBaseUri(baseUri)
.setContentType(ContentType.JSON)
.setAuth(oauth2(accessToken))
.setBasePath(url)
.build();
}
}
#SelectClasspathResource("src/test/resources/example")
Typically src/test/resources is not part of the classpath.
After running mvn test have a look at target/test-classes to understand the structure of what is on the classpath.
I'm trying to run spring boot with spring data as basically as possible with swing.
However, even though all seems to be properly configured, when I try to run it, I get an error message saying it couldn't find my Service bean.
package db.westworld.dao;
import db.westworld.entities.RobotEntity;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface RobotRepository extends CrudRepository<RobotEntity, Integer> {
}
package db.westworld.service;
import db.westworld.entities.RobotEntity;
import java.util.Optional;
public interface IRobotService {
Optional<RobotEntity> findById(int id);
}
package db.westworld.service;
import db.westworld.dao.RobotRepository;
import db.westworld.entities.RobotEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
#Service
public class RobotService implements IRobotService {
private final RobotRepository robotRepository;
#Autowired
RobotService(RobotRepository robotRepository) {
this.robotRepository = robotRepository;
}
#Override
public Optional<RobotEntity> findById(int id) {
return robotRepository.findById(id);
}
public void saveRobot(RobotEntity robot) {
robotRepository.save(robot);
}
}
package db.westworld;
import db.westworld.view.RegisterRobot;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.awt.*;
#SpringBootApplication
public class WestworldApplication {
public static void main(String[] args) {
var ctx = new SpringApplicationBuilder(RegisterRobot.class).headless(false).run(args);
EventQueue.invokeLater(() -> {
var ex = ctx.getBean(RegisterRobot.class);
ex.setVisible(true);
});
}
}
package db.westworld.view;
import db.westworld.entities.RobotEntity;
import db.westworld.service.RobotService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import javax.swing.*;
import java.awt.event.*;
import java.util.Date;
#Controller
public class RegisterRobot extends JDialog {
private RobotService robotService;
#Autowired
public void setRobotService (RobotService robotService) {
this.robotService = robotService;
}
private void onOK() {
RobotEntity robot = new RobotEntity();
robot.setCreatedAt(new Date());
robot.setId(1);
robotService.saveRobot(robot);
dispose();
}
}
Error message:
Parameter 0 of method setRobotService in db.westworld.view.RegisterRobot required a bean of type 'db.westworld.service.RobotService' that could not be found.
Action:
Consider defining a bean of type 'db.westworld.service.RobotService' in your configuration.
(the JDialog implementation just includes the basics)
The same also happens when I try to autowire the repository.
Also, in case needed, here's my pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <groupId>db</groupId>
<artifactId>westworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>westworld</name>
<description>westworldSpringBoot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The parameter to new SpringApplicationBuilder() must be the class annotate with #SpringBootApplication, as shown in every Spring Boot example I've ever seen, e.g. Create an Application class in the "Getting Started - Building an Application with Spring Boot" guide.
Something is missing or misconfigured for JUnits - I can't find.
Getting a 404 instead of 200 in Junits. The application at http://localhost:8080/app shows the expected response.
pom.xml
<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.github.anandchakru</groupId>
<artifactId>jtest</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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-devtools</artifactId>
</dependency>
<!-- DB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<!-- commons -->
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<!-- logging -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml [both main & test are identical]
logging:
level:
org.springframework: INFO
org.hibernate: ERROR
jtest: DEBUG
file: jtest.log
spring:
datasource:
url: jdbc:mysql://localhost:3306/cifi3?useSSL=false&allowPublicKeyRetrieval=true
username: tester
password: tester
jpa:
database-platform: org.hibernate.dialect.PostgreSQLDialect
hibernate:
ddl-auto: create
JTestInit.java
#Configuration
#EntityScan({ "jtest" })
#ComponentScan({ "jtest" })
#SpringBootApplication
public class JTestInit {
private static final Logger logger = LoggerFactory.getLogger("jtest");
public static void main(String[] args) throws Exception {
SpringApplication.run(JTestInit.class, args);
logger.debug("Initialized CifiCore.");
}
}
AppRepo.java
#RepositoryRestResource(path = "app")
public interface AppRepo extends PagingAndSortingRepository<App, Long> {}
App.java
#Entity
#Table(name = "app")
public class App {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long appId;
private String appName;
//getters,setters
}
AppRepoTest.java
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import com.fasterxml.jackson.databind.ObjectMapper;
#WebMvcTest
#RunWith(SpringRunner.class)
#Import({ JTestInit.class })
public class AppRepoTest {
#Autowired
private MockMvc mockMvc;
ObjectMapper json = new ObjectMapper();
#Test
public void testFindAll() throws Exception {
mockMvc.perform(get("/app/")).andDo(print()).andExpect(status().isOk());
}
}
Browser Response:
{
"_embedded" : {
"apps" : [ ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/app{?page,size,sort}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:8080/profile/app"
},
"search" : {
"href" : "http://localhost:8080/app/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 0,
"totalPages" : 0,
"number" : 0
}
}
**AppRepoTest - Why??????**
java.lang.AssertionError: Status expected:<200> but was:<404>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:55)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:82)
at org.springframework.test.web.servlet.result.StatusResultMatchers.lambda$matcher$9(StatusResultMatchers.java:619)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:195)
at jtest.AppRepoTest.testFindAll(AppRepoTest.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
#WebMvcTest should be used only for the Controllers. Hence, #RepositoryRestResource class was not initialized.
Replacing it with #AutoConfigureMockMvc and #SpringBootTest did the trick.
Other similar Test utility annotations:
#WebMvcTest - for controllers
#JsonTest - for JSON marshaling and unmarshalling
#DataJpaTest - for repositories
#RestClientTests - for REST clients
#SpringBootTest - for everything else
It is a spring boot 2.0.0 application which was running earlier, but this error started after I added dependencies for spring-cloud-stream.I tried removing spring-fox dependency but it only removed the nested exception.
The complete error after removing spring-fox dependency:
ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
The complete pom.xml is:
<?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.foo.bar.application</groupId>
<artifactId>application-reviews-manager</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>generic-name</name>
<description>Manager</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.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>
<application.utils.version>1.0.0</application.utils.version>
<application.utils.build.number>SNAPSHOT</application.utils.build.number>
<application.rnr.repositories.version>1.0.0</application.rnr.repositories.version>
<application.rnr.repositories.build.number>SNAPSHOT</application.rnr.repositories.build.number>
<dcp.config.version>0.0.1</dcp.config.version>
<dcp.config.build.number>SNAPSHOT</dcp.config.build.number>
<aspectj.version>1.8.9</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>com.foo.bar.application</groupId>
<artifactId>application-rnr-repositories</artifactId>
<version>${application.rnr.repositories.version}-${application.rnr.repositories.build.number}</version>
</dependency>
<dependency>
<groupId>com.foo.bar.application</groupId>
<artifactId>application-utils</artifactId>
<version>${application.utils.version}-${application.utils.build.number}</version>
</dependency>
<dependency>
<groupId>com.foo.dcp.commons.config</groupId>
<artifactId>dcp-config-client</artifactId>
<version>${dcp.config.version}-${dcp.config.build.number}</version>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>5.6.3</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>5.6.3</version>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>1.58</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.elasticsearch.test</groupId>
<artifactId>framework</artifactId>
<version>5.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
I'm just a starter in spring-cloud-stream, so any help would be appreciated.
Edit:
We found out that the mistake is in the way or place the annotation
#EnableBinding is used.
The relevant pieces of codes are:
Application.java
package com.foo.bar;
import com.foo.bar.configuration.FooStreams;
import com.foo.bar.configuration.BarStreams;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.context.annotation.Bean;
import com.externalpackage.config.client.AppConfiguration;
import com.foo.bar.storage.repository.CustomElasticRestClient;
#SpringBootApplication
#EnableBinding({FooStreams.class, BarStreams.class})
public class FooApplication {
public static void main(String[] args) {
SpringApplication.run(FooApplication.class, args);
}
#Bean
public AppConfiguration appConfiguration() {
return AppConfiguration.instance();
}
#Bean
public CustomElasticRestClient highLevelElasticClient(AppConfiguration appConfiguration) throws Exception {
return new CustomElasticRestClient(appConfiguration);
}
}
FooStreams.java
package com.foo.bar.configuration;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
public interface FooStreams {
String OUTPUT = "foo-out";
#Output(value = OUTPUT)
MessageChannel postFooToOutChanel();
}
BarStreams.java
package com.tesco.foo.bar.configuration;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
public interface BarStreams {
String OUTPUT = "bar-out";
#Output(value = OUTPUT)
MessageChannel postBarToOutChanel();
}
KafkaPublisherService.java:
package com.foo.bar.service;
import com.foo.bar.configuration.FooStreams;
import com.foo.bar.configuration.BarStreams;
import com.foo.bar.domain.Foo;
import com.foo.bar.domain.Bar;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.MimeTypeUtils;
#Service
#Slf4j
public class KafkaPublisherService {
#Autowired
private BarStreams barStreams;
#Autowired
private FooStreams fooStreams;
public void sendBar(final Bar bar) {
log.info("Publishing bar to kafka {}", bar);
MessageChannel messageChannel = barStreams.postBarToOutChanel();
messageChannel.send(MessageBuilder
.withPayload(bar)
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
.build());
}
public void sendFoo(final Foo foo) {
log.info("Publishing foo to kafka {}", foo);
MessageChannel messageChannel = fooStreams.postFooToOutChanel();
messageChannel.send(MessageBuilder
.withPayload(foo)
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
.build());
}
}
application.properties
spring.cloud.stream.kafka.binder.brokers=localhost:9092
spring.cloud.stream.bindings.foo-out.destination=feedback
spring.cloud.stream.bindings.foo-out.contentType=application/json
spring.cloud.stream.bindings.bar-out.destination=review
spring.cloud.stream.bindings.bar-out.contentType=application/json