I'm trying to make documentation on the code I'm working with using Spring-boot , swagger2 and H2-database.
Here is the swaggerconfig
#Configuration
#EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors
.basePackage("se.dala.restserviceswagger.controller"))
.paths(PathSelectors.any())
.build();
}
}
And here is the Controller
#RestController
public class EmployeeController {
private final EmployeeRepository repository;
private final EmployeeResourceAssembler assembler;
public EmployeeController(EmployeeRepository repository, EmployeeResourceAssembler assembler) {
this.repository = repository;
this.assembler = assembler;
}
#GetMapping("/employees/{id}")
public Resource<Employee> get(#PathVariable Long id) {
Employee employee = repository.findById(id).orElseThrow(() -> new EmployeeNotFoundException(id));
return assembler.toResource(employee);
}
#GetMapping("/employees")
public Resources<Resource<Employee>> getAll() {
List<Resource<Employee>> employees = repository.findAll().stream()
.map(assembler::toResource)
.collect(Collectors.toList());
return new Resources<>(employees,
linkTo(methodOn(EmployeeController.class).getAll()).withSelfRel());
}
//Blanda inte ihop resource.getId() med employee.getId(). resource.getId() ger dig en URI.
#PostMapping("/employees")
public ResponseEntity<?> newEmployee(#RequestBody Employee newEmployee) throws URISyntaxException {
Resource<Employee> resource = assembler.toResource(repository.save(newEmployee));
return ResponseEntity.created(new URI(resource.getId().expand().getHref())).body(resource);
}
#PutMapping("/employees/{id}")
public ResponseEntity<?> replace(#RequestBody Employee newEmployee, #PathVariable Long id) throws URISyntaxException {
Employee updatedEmployee = repository.findById(id).map(employee -> {
employee.setName(newEmployee.getName());
employee.setRole(newEmployee.getRole());
return repository.save(employee);
}).orElseGet(() -> {
newEmployee.setId(id);
return repository.save(newEmployee);
});
Resource<Employee> resource = assembler.toResource(updatedEmployee);
return ResponseEntity.created(new URI(resource.getId().expand().getHref())).body(resource);
}
#DeleteMapping("/employees/{id}")
public ResponseEntity<?> delete(#PathVariable Long id) {
repository.deleteById(id);
return ResponseEntity.noContent().build();
}
}
And here is my pom.
<properties>
<java.version>1.8</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-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
When I go to http://localhost:8080/v2/api-docs I get it to work but not when I go to http://localhost:8080/swagger-ui.html. There I get:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Feb 14 15:22:38 CET 2019
There was an unexpected error (type=Not Found, status=404).
No message available
I don't have any Spring security or anything.
Use SwaggerConfig without extending WebMvcConfigurationSupport should work then.
Error is not related to security its telling that there is no mapped path with that url.
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors
.basePackage("se.dala.restserviceswagger.controller"))
.paths(PathSelectors.any())
.build();
}
}
Same for me becareful with Spring boot it will work until version 2.8.0
it does'nt work with version 3.0.0
tested with this
#Configuration
#EnableSwagger2
public class SwaggerConfig{
#Value("${application.version}")
private String version;
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("com.langton"))
.paths(PathSelectors.any()).build();
}
/**
* will add some importants information to the swagger docs
* #return
*/
private ApiInfo apiInfo() {
return new ApiInfo("Langton ant app", "rest api for langton ant app", version, null,
new Contact("name", "N/A", "email"), null, null, Collections.EMPTY_LIST);
}
}
and in main class
#SpringBootApplication
public class LangtonAntLauncher{
public static void main(String[] args) {
SpringApplication.run(LangtonAntLauncher.class, args);
}
}
Related
I am trying to connect my e-commerce project backend to swagger2. I have installed all the dependencies, yet I still cannot do it.
This is the dependency declared in my pom.xml file:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
This is one of my user controller files:
#RestController
#RequestMapping("/api")
#CrossOrigin
public class UserController {
#Autowired
private UserRepository userRepository;
#GetMapping("/")
public List<User> GetUsers() {
return userRepository.findAll();
}
#GetMapping("/{id}")
public User GetUser(#PathVariable String id) {
return userRepository.findById(id).orElse(null);
}
#PostMapping("/")
public User postMethodName(#RequestBody User user) {
return userRepository.save(user);
}
#PutMapping("/")
public User PutMapping(#RequestBody User newUser) {
User oldUser = userRepository.findById(newUser.getId()).orElse(null);
oldUser.setName(newUser.getName());
oldUser.setEmail(newUser.getEmail());
oldUser.setPassword(newUser.getPassword());
userRepository.save(oldUser);
return oldUser;
}
#DeleteMapping("/{id}")
public String DeleteUser(#PathVariable String id) {
userRepository.deleteById(id);
return id;
}
}
This is the code of my main application:
package com.omazon.ecommerce;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#SpringBootApplication
#EnableSwagger2
public class ECommerceApplication {
public static void main(String[] args) {
SpringApplication.run(ECommerceApplication.class, args);
}
}
Lastly, this is what I declared in the application.properties file:
spring.data.mongodb.uri=mongodb://localhost:27017/e-commerce
This is the picture of the error I got:
Swagger2's usage seems to require (or at least often includes) the concept of a Docket api via an instantiation such as new Docket() or new Docket(DocumentationType.SWAGGER_2). I don't see that in your code snippets, so wonder if that may be one issue.
Per the swagger docs, Docket is Springfox’s primary api configuration mechanism.
Specifically, this section regarding configuration may be helpful. Note the Docket instantiation:
...
#Bean //Don't forget the #Bean annotation
public Docket customImplementation(){
return new Docket()
.apiInfo(apiInfo());
//... more options available
...
There's also a more complete example in those same docs here.
For reference, there's another usage example in this tutorial.
I have a problem, I'm trying to use two Oracle databases in spring boot using DataSource, The DataSource wiht the #Primay annotation works fine but the oher one only gives me:
SQL Error: 942, SQLState: 42000
ORA-00942: table or view does not exist
I don't have idea what I should do now. Any help will be welcomed. Thanks!
application.properties
spring.datasource.url=jdbc\:oracle\:thin\:[connection] #Not showing for security
spring.datasource.password=[password]
spring.datasource.configuration.maximum-pool-size=30
spring.sgc-datasource.url=jdbc\:oracle\:[connection] #Not showing for security
spring.sgc-datasource.username=[user]
spring.sgc-datasource.password=[password]
spring.sgc-datasource.max-total=30
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
spring.jpa.database=default
spring.jpa.hibernate.ddl-auto=none
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.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.indra.vmo.edenorte</groupId>
<artifactId>InMpData</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>InMpData</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</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-starter-validation</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>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
DatabaseConfiguration.java
package com.indra.vmo.edenorte.config;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.zaxxer.hikari.HikariDataSource;
#Configuration(proxyBeanMethods = false)
public class DatabaseConfiguration {
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public DataSourceProperties inMpDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.configuration")
public HikariDataSource inMpDataSource(DataSourceProperties inMpDataSourceProperties) {
return inMpDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
#Bean
#ConfigurationProperties("spring.sgc-datasource")
public DataSourceProperties sgcDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#ConfigurationProperties("spring.sgc-datasource.configuration")
public HikariDataSource sgcDataSource(DataSourceProperties sgcDataSourceProperties) {
return sgcDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
}
Repository from 1st DB
package com.indra.vmo.edenorte.repository.inmp;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.indra.vmo.edenorte.entity.inmp.MpLocalidadesCoordenadas;
#Repository
public interface IMpLocalidadesCoordenadasRepository extends JpaRepository<MpLocalidadesCoordenadas, String> {
}
Repository from 2nd DB
package com.indra.vmo.edenorte.repository.sgc;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.indra.vmo.edenorte.entity.sgc.Clientes;
#Repository
public interface IClientesRepository extends JpaRepository<Clientes, Integer> {
#Query("select c from Clientes c where c.docId=?1")
public Clientes findBydocId(String docId);
#Query("select c from Clientes c where c.docId=?1 and c.tipDoc=?2")
public Clientes findBydocIdU(String docId, String tipDoc);
}
SpringBoot auto-config works perfectly for a single datasource. For multiple datasources, you will need to manually configure the EntityManagerFactory beans for each of the datasources. See this article
I could resolve the problem with the following changes in my code:
application.properties
I changed the spring.jpa.hibernate.ddl-auto from none to validate and made some other chages
#Credenciales Datasource (InMpData)
spring.datasource.url=jdbc\:oracle\:thin\:[connection] #Not showing for security
spring.datasource.username=[user]
spring.datasource.password=[password]
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
#Credenciales Datasource (SGC)
spring.sgcdatasource.url=jdbc\:oracle\:thin\:[connection] #Not showing for security
spring.sgcdatasource.username=[user]
spring.sgcdatasource.password=[password]
spring.sgcdatasource.driver-class-name=oracle.jdbc.driver.OracleDriver
#Hibernate config
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
spring.jpa.hibernate.ddl-auto=validate
# HikariCP settings
# spring.datasource.hikari.*
spring.datasource.hikari.connection-timeout=60000
spring.datasource.hikari.maximum-pool-size=5
pom.xml
Added a new dependency
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
Divided the DatabaseConfiguration.java in two separeated files InMpConfig.java and SgcConfig.java
InMpConfig.java
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "com.indra.vmo.edenorte.repository.inmp", entityManagerFactoryRef = "inMpEntityManagerFactory", transactionManagerRef = "inMpTransactionManager")
public class InMpConfig {
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public DataSourceProperties inMpDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.configuration")
public DataSource inMpDataSource() {
return inMpDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
/*Primary Entity manager*/
#Primary
#Bean(name = "inMpEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean inMpEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder.dataSource(inMpDataSource()).packages("com.indra.vmo.edenorte.entity.inmp").build();
}
#Primary
#Bean
public PlatformTransactionManager inMpTransactionManager(
final #Qualifier("inMpEntityManagerFactory") LocalContainerEntityManagerFactoryBean inMpEntityManagerFactory) {
return new JpaTransactionManager(inMpEntityManagerFactory.getObject());
}
}
SgcConfig.java
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "com.indra.vmo.edenorte.repository.sgc", entityManagerFactoryRef = "sgcEntityManagerFactory", transactionManagerRef = "sgcTransactionManager")
public class SgcConfig {
#Bean
#ConfigurationProperties("spring.sgcdatasource")
public DataSourceProperties sgcDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#ConfigurationProperties("spring.sgcdatasource.configuration")
public DataSource sgcDataSource() {
return sgcDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
#Bean(name = "sgcEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean sgcEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder.dataSource(sgcDataSource()).packages("com.indra.vmo.edenorte.entity.sgc").build();
}
#Bean(name = "sgcTransactionManager")
public PlatformTransactionManager sgcTransactionManager(
final #Qualifier("sgcEntityManagerFactory") LocalContainerEntityManagerFactoryBean sgcEntityManagerFactory) {
return new JpaTransactionManager(sgcEntityManagerFactory.getObject());
}
}
And made some changes to the models, such as add the #Table and #Column annotation
#Entity
#Data
#Table(name = "CLIENTES")
public class Clientes implements Serializable {
#Id
#NotNull
#Column(name = "COD_CLI")
private Integer codCli;
#Column(name = "USUARIO")
private String usuario;
#Column(name = "F_ACTUAL")
private Date fActual;
I hope this is helpful for someone else.
How to test a void method which throws an exception?
I've read many publications here and on others pages including Mockico docs form https://javadoc.io/static/org.mockito/mockito-core/3.12.4/org/mockito/Mockito.html#5. And my test still won't pass. I don't know what I'm doing wrong I always get red.
Maybe it is related to a wrongly implemented exception class.
Here is my code:
Repo:
import org.springframework.data.jpa.repository.JpaRepository;
import succeed.app.start.model.User;
public interface UserRepository extends JpaRepository<User, Long> {
}
Service interface:
public interface UserService {
void deleteUserById(long userId);
}
Service implementation:
#Service
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public void deleteUserById(long userId) {
userRepository.findById(userId).orElseThrow(() -> new ResourceNotFoundException("User", "ID", userId));
userRepository.deleteById(userId);
}
}
Exception class:
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
private final static long serialVersionUID = 1L;
private String resourceName;
private String fieldName;
private Object fieldValue;
public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) {
super(String.format("%s not found with %s : %s", resourceName, fieldName, fieldValue));
this.resourceName = resourceName;
this.fieldName = fieldName;
this.fieldValue = fieldValue;
}
public String getResourceName() {
return resourceName;
}
public String getFieldName() {
return fieldName;
}
public Object getFieldValue() {
return fieldValue;
}
}
Test class:
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.doThrow;
import succeed.app.start.exception.ResourceNotFoundException;
import succeed.app.start.repository.UserRepository;
#ExtendWith(MockitoExtension.class)
public class UserServiceImplTest {
#Mock
UserRepository userRepository;
#Mock
UserServiceImpl userService;
#Test
#DisplayName("Should throw ResourceNotFoundException when user doesn't exist.")
void shouldThrowsResourceNotFoundException() {
final long nonExistingId = 12902450235L;
doThrow(new ResourceNotFoundException("User", "ID", nonExistingId)).when(userService).deleteUserById(nonExistingId);
userService.deleteUserById(nonExistingId);
}
}
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.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>succeed.app</groupId>
<artifactId>start</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>start</name>
<description>App to organize and achieve goals.</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-starter-security</artifactId>
</dependency>
<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.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</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>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</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>
There are a couple of things wrong here.
First, other than the message in the #Display annotation, your test doesn't really expect the exception to be thrown. You need to explicitly code this behavior, e.g. by using assertThrows.
Second, you're mocking the UserService, so the test won't really do anything - in the same method, you've defined some fake behavior and then tested it. Instead, you should mock the UserRepository and then make test that the UserService calls it correctly:
#ExtendWith(MockitoExtension.class)
public class UserServiceImplTest {
#Mock
UserRepository userRepository;
#InjectMocks
UserServiceImpl userService;
#Test
#DisplayName("Should throw ResourceNotFoundException when user doesn't exist.")
void shouldThrowsResourceNotFoundException() {
final long nonExistingId = 12902450235L;
doReturn(Optional.empty()).when(userRepository).findById(nonExistingId);
assertThrows(
ResourceNotFoundException.class,
() -> userService.deleteUserById(nonExistingId));
}
}
I am trying to test one test case using controller class with service interface and interface impl class. But it's always failing and returning either null pointer exception or not found custom exception even mocking the method to return mock values.
Controller.class
#RestController
public class RestAPIController {
#Autowired
RestAPIService restAPIService;
#PostMapping(path = "list/{id}")
public ResponseEntity<List<Employee>> findByID(#PathVariable(value = "id") String id)
throws RestAPIException {
List<Employee> list = restAPIService.findByID(id);
if (list == null || list.isEmpty()) {
throw new IDNotFoundException(id);
}
return new ResponseEntity<>(list, HttpStatus.OK);
}
Service Interface:
#Service
public interface RestAPIService {
public List<Employee> findByID(#Param("id") String id) throws RestAPIException;
}
Service impl class:
#Service
public class RestAPIServiceImpl implements RestAPIService {
#Override
public List<Employee> findByID(String id) throws RestAPIException {
return serviceUtils.transformationObj(repository.findByID(id));
}
}
Test Class
#Mock
RestAPIService restAPIServiceImpl;
#InjectMocks
RestAPIController restAPIController;
#Test
public void testListByIDController() throws RestAPIException {
Mockito.when(restAPIServiceImpl.findByID("1")).thenReturn(baseDTOData());
ResponseEntity<List<Employee>> expectedList = restAPIController.findByID("1");
assertEquals(1, expectedList.getBody().size());
}
private List<Employee> baseDTOData() {
List<Employee> list = new ArrayList<>();
Employee e = new Employee();
e.setId("2");
list.add(e);
return list;
}
pom.xml (using JUnit5)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!-- exclude junit 4 -->
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Junit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<!-- Mockito extention -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
The above code is failing and enters into IDNotFoundException but mock return is not working.
Can anyone please help on this.
This is my first WebApp builded using Spring and i'm going mad because when i call my RestController everytime gives me 404. I tried to use the Class/Annotaion configuration instead of the XML configuration and i think that is here that the problem lives.
Here are my config classes, pom and controller.
Sorry for the huge amount of code.
For the api call i use localhost:8080/Polito/metric
Initailizer
package com.poli.config;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
#Order(1)
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[] { RootConfig.class, SecurityConfig.class };
}
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebAppConfig.class };
}
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
RootConfig
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories("com.poli")
#ComponentScan("com.poli")
#PropertySource("classpath:application.properties")
public class RootConfig {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
private static final String PROPERTY_NAME_HIBERNATE_DDL_AUTO = "hibernate.hbm2ddl.auto";
private static final String PROPERTY_NAME_HIBERNATE_EJB_NAMING_STRATEGY = "hibernate.ejb.naming_strategy";
private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
#Resource
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
sessionFactoryBean.setHibernateProperties(hibProperties());
return sessionFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
return properties;
}
#Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN);
Properties jpaProperties = new Properties();
jpaProperties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_DDL_AUTO,
env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DDL_AUTO));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_EJB_NAMING_STRATEGY,
env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_EJB_NAMING_STRATEGY));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL,
env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL,
env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
}
SecurityConfig
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
private UserDetailsService customUserDetailsService;
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.userDetailsService(customUserDetailsService)
.authorizeRequests()
.antMatchers("/personal/**").hasRole("USER")
.and()
.formLogin()
.loginPage("/login.html")
.defaultSuccessUrl("/index.html")
.failureUrl("/error-login.html")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/index.html");
}
}
WebAppConfig
#Configuration
#EnableWebMvc
#ComponentScan("com.poli")
public class WebAppConfig {
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
}
SecurityInitializer
#Order(2)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
MetricRESTController
#RestController()
#RequestMapping("/metric")
public class MetricRESTController {
#Autowired
private MetricService metricService;
#RequestMapping(method = RequestMethod.POST, value="/")
#ResponseStatus(value=HttpStatus.CREATED)
public void post(#RequestBody Metric metric){
metricService.addMetric(metric);
}
#RequestMapping(method = RequestMethod.GET, value = "/{uuid}")
public List<Metric> get(#PathVariable("uuid") String uuid){
return metricService.findByUuid(uuid);
}
#RequestMapping(method = RequestMethod.GET, value = "/")
public List<Metric> get(){
return metricService.findAllMetrics();
}
}
And finally 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>Polito</groupId>
<artifactId>Polito</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<finalName>Polito</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
</plugin>
</plugins>
</build>
<properties>
<spring.version>4.2.1.RELEASE</spring.version>
<spring.security.version>4.0.2.RELEASE</spring.security.version>
<jstl.version>1.2</jstl.version>
<mysql.connector.version>5.1.30</mysql.connector.version>
<logback.version>1.1.2</logback.version>
<slf4j.version>1.7.6</slf4j.version>
<hibernate.version>4.2.11.Final</hibernate.version>
<dbcp.version>1.4</dbcp.version>
<servletapi.version>2.5</servletapi.version>
</properties>
<dependencies>
<!-- database pool -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>${dbcp.version}</version>
</dependency>
<!-- Hibernate ORM -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- Spring 3 dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring + aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- ORM integration, e.g Hibernate -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<!-- Spring Security JSP Taglib -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<!-- jstl for jsp page -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<!-- MySql Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servletapi.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>