How to create unit tests with MockMvc for your REST controller - spring-boot

I have a REST controller and I want to create Unit tests for my controller and I'm not interested in loading the spring context.
Having a spring-boot application, the requirement is to use junit5 and MockMvc.

Here is a working example with MockMvc, creating simple unit tests for the REST controller.
Here is the Dictionary REST controller.
#Slf4j
#RequiredArgsConstructor
#RestController
#RequestMapping(DICTIONARY_ENDPOINT_URL)
public class DictionaryController {
protected static final String DICTIONARY_ENDPOINT_URL = "/dictionaries";
private final DictionaryService dictionaryService;
#GetMapping(value = "download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<byte[]> downloadDictionariesFile() throws FileNotFoundException {
log.info("Called download dictionaries file endpoint.");
final String fileRelativePath = dictionaryService.getDictionariesFileRelativePath();
return ResponseEntity.ok()
.header("Content-Disposition", "attachment; filename=" + getDictionariesFileByRelativePath(fileRelativePath))
.body(dictionaryService.getDictionaryFileContent(fileRelativePath));
}
}
Here is the DictionaryControllerTest
package <...>;
import <...>.DictionaryService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.io.FileNotFoundException;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#ExtendWith(MockitoExtension.class)
class DictionaryControllerTest {
private String dictionaryFilePath = "<<path to the file>>";
private String dictionaryFileContent = "<<content here>>";
private String errorMessage = "Dictionary file, does not exists!";
private String endpointUrl = "/dictionaries/download";
#Mock
private DictionaryService dictionaryService;
#InjectMocks
private DictionaryController dictionaryController;
private MockMvc mockMvc;
#BeforeEach
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(dictionaryController).build();
}
#Test
#DisplayName("Should return response with content file")
void downloadDictionariesFile_validRequest_success() throws Exception {
when(dictionaryService.getDictionariesFileRelativePath())
.thenReturn(dictionaryFilePath);
when(dictionaryService.getDictionaryFileContent(anyString()))
.thenReturn(dictionaryFileContent.getBytes());
mockMvc.perform(get(endpointUrl))
.andExpect(status().isOk())
.andExpect(content().string(containsString(dictionaryFileContent)));
verify(dictionaryService).getDictionariesFileRelativePath();
verify(dictionaryService).getDictionaryFileContent(any());
}
}
Here are a few lines of my pom.xml file
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/>
</parent>
<dependencies>
<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>
</dependencies>

Related

Spring Boot controllers are returning a 404

Spring Boot controllers are returning a 404 on all endpoints
trying to get basic controller returning data
Package structure is setup correctly all packages are sub packages of the main package
annotations look fine been using spring casually for a bit but im clueless im expecting at least hello world im assuming its some spring garbage goin on with it not finding the bean idk no luck finding anything out of conventional configuration. plz help thanks
package com.bookieburglar.api.services;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
//#EnableJpaRepositories(basePackages = "com.bookieburlgar.api.services")
#ComponentScan(basePackages = "com.bookieburglar.api.services")
#SpringBootApplication
public class BookieBurglarApplication {
public static void main(String[] args) {
SpringApplication.run(BookieBurglarApplication.class, args);
}
}
Odds.java
package com.bookieburglar.api.services.models;
import java.util.List;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
public class Odds {
#Id
#JsonProperty("id")
private String id;
#JsonProperty("sport_key")
private String sport_key;
#JsonProperty("sport_title")
private String sport_title;
#JsonProperty("commence_time")
private String commence_time;
#JsonProperty("home_team")
private String home_team;
#JsonProperty("away_team")
private String away_team;
#JsonProperty("bookmakers")
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "odds_id")
private List<Bookmaker> bookmakers;
public Odds(String id, String sportKey, String sportTitle, String commenceTime,
String homeTeam, String awayTeam, List<Bookmaker> bookmakers) {
this.id = id;
this.sport_key = sportKey;
this.sport_title = sportTitle;
this.commence_time = commenceTime;
this.home_team = homeTeam;
this.away_team = awayTeam;
this.bookmakers = bookmakers;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSportKey() {
return sport_key;
}
public void setSportKey(String sportKey) {
this.sport_key = sportKey;
}
public String getSportTitle() {
return sport_title;
}
public void setSportTitle(String sportTitle) {
this.sport_title = sportTitle;
}
public String getCommenceTime() {
return commence_time;
}
public void setCommenceTime(String commenceTime) {
this.commence_time = commenceTime;
}
public String getHomeTeam() {
return home_team;
}
public void setHomeTeam(String homeTeam) {
this.home_team = homeTeam;
}
public String getAwayTeam() {
return away_team;
}
public void setAwayTeam(String awayTeam) {
this.away_team = awayTeam;
}
public List<Bookmaker> getBookmakers() {
return bookmakers;
}
public void setBookmakers(List<Bookmaker> bookmakers) {
this.bookmakers = bookmakers;
}
}
OddsController
package com.bookieburglar.api.services.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.bookieburglar.api.services.services.OddsAPIService;
import com.bookieburglar.api.services.services.OddsService;
import com.bookieburglar.api.services.models.Odds;
import com.bookieburglar.api.services.repositories.OddsRepository;
#RestController
#RequestMapping("/Odds")
public class OddsController {
#Autowired
private OddsService oddsService;
#Autowired
private OddsAPIService oddsAPIService;
#GetMapping("/")
public String getOdds() {
return "WORLD";
//return (List<Odds>) OddsRepository.findAll();
}
// #GetMapping("/{id}")
// public Odds getOdds(#PathVariable String id) {
// return OddsRepository.findById(id).orElse(null);
// }
#PostMapping("/create")
public Odds createOdds(#RequestBody Odds Odds) {
System.out.println("frthoo");
return oddsService.saveOdds(Odds);
}
#GetMapping("/refresh")
#ResponseBody
public String refreshOdds() {
System.out.println("ttgb5");
//return oddsAPIService.refreshOdds();
return "yoo";
}
// #PutMapping("/{id}")
// public Odds updateOdds(#PathVariable String id, #RequestBody Odds Odds) {
// Odds.setId(id);
// return OddsRepository.save(Odds);
// }
//
// #DeleteMapping("/{id}")
// public void deleteOdds(#PathVariable String id) {
// OddsRepository.deleteById(id);
// }
}
OddsServices
package com.bookieburglar.api.services.services;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.bookieburglar.api.services.models.Odds;
import com.bookieburglar.api.services.repositories.OddsRepository;
#Service
public class OddsService {
#Autowired
private OddsRepository oddsRepository;
public List<Odds> getAllOdds() {
return (List<Odds>) oddsRepository.findAll();
}
public Optional<Odds> findOddsById(String id) {
return oddsRepository.findById(id);
}
// public List<Odds> findOddsBySportTitle(String sportTitle) {
// return oddsRepository.findBySportTitle(sportTitle);
// }
//
// public List<Odds> findOddsByHomeTeam(String homeTeam) {
// return oddsRepository.findByHomeTeam(homeTeam);
// }
//
// public List<Odds> findOddsByAwayTeam(String awayTeam) {
// return oddsRepository.findByAwayTeam(awayTeam);
// }
public Odds saveOdds(Odds odds) {
return oddsRepository.save(odds);
}
public void deleteOdds(String id) {
oddsRepository.deleteById(id);
}
}
OddsRepository
package com.bookieburglar.api.services.repositories;
import java.util.List;
import org.springframework.stereotype.Repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.bookieburglar.api.services.models.Odds;
#Repository
public interface OddsRepository extends JpaRepository<Odds, String> {
List<Odds> findAll();
// additional methods can be defined here, for example, to search for odds by sport key or teams
}
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>3.0.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bookieburglar.api</groupId>
<artifactId>services</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Bookie Burglar</name>
<description>API for BookieBurglar</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
In #ComponentScan annotation. Package name is incorrect.
#ComponentScan(basePackages = "com.bookieburlgar.api.services")
It should be
#ComponentScan(basePackages = "com.bookieburglar.api.services")

Spring Security not working properly in my spring boot project?

I am using spring security with JWT token in my spring boot application and I am trying to use spring security related features(like isauthenticated,hasRole,hasAuthority,etc) in my jsp page but they are not working. Facing same issue in my controller whereas In RESTController, They works fine with #preauthorize tag.
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.6.7</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.bdtool</groupId>
<artifactId>BD-Tool</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>BD-Tool</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.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</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-web-services</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-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client</artifactId>
<version>1.31.5</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-gson</artifactId>
<version>1.22.0</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client-jackson2</artifactId>
<version>1.20.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Here is my config class:-
package com.bdtool.config;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Resource(name = "jwtUserDetailsService")
private UserDetailsService userDetailsService;
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests().antMatchers("/", "/index", "/resources/**", "/JS/**", "/register", "/authenticate", "/login",
"/signout", "/signup", "/forgotPassword", "/submitSignupDetails")
.permitAll().anyRequest().authenticated().and().exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public JwtRequestFilter authenticationTokenFilterBean() throws Exception {
return new JwtRequestFilter();
}
}
Here is my JwtRequestFilter
package com.bdtool.config;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.bdtool.service.JwtTokenBeanService;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.jsonwebtoken.ExpiredJwtException;
#Component
#JsonSerialize
public class JwtRequestFilter extends OncePerRequestFilter {
#Autowired
private JwtUserDetailsService JwtUserDetailsService;
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Autowired
JwtTokenBeanService jwtTokenBeanService;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ") ) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
System.out.println("From jwt req filter:-"+username);
} catch (IllegalArgumentException e) {
throw new ServletException("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
throw new ServletException("JWT Token has expired");
}
} else {
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.JwtUserDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
Here is JwttokenUtil
package com.bdtool.config;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
#Component
public class JwtTokenUtil implements Serializable {
private static final long serialVersionUID = 1L;
public static final long JWT_TOKEN_VALIDITY = 60 * 60;
#Value("${jwt.secret}")
private String secret;
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userDetails.getUsername());
}
private String doGenerateToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
.signWith(SignatureAlgorithm.HS512, secret).compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
Userdetailservice class:-
package com.bdtool.config;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.bdtool.bean.Users;
import com.bdtool.dao.UsersDao;
#Service
public class JwtUserDetailsService implements UserDetailsService {
#Autowired
private UsersDao userdao;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Users user=userdao.findUserData(username);
if (user == null) {
throw new UsernameNotFoundException("User not found with username: " + username);
}
List<GrantedAuthority> authrole = new ArrayList<GrantedAuthority>() ;
authrole.add(new SimpleGrantedAuthority(user.getUserType()));
return new org.springframework.security.core.userdetails.User(username, user.getUserPassword(),
authrole);
}
}
AuthenticateController :-
package com.bdtool.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.bdtool.bean.Users;
import com.bdtool.config.JwtTokenUtil;
import com.bdtool.config.JwtUserDetailsService;
import com.bdtool.dao.UsersDao;
import com.bdtool.model.JwtRequest;
import com.bdtool.model.JwtResponse;
#RestController
#CrossOrigin
public class AuthenticateController {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Autowired
private JwtUserDetailsService userDetailsService;
#PostMapping(value = "/authenticate")
public ResponseEntity<?> createAuthenticationToken(JwtRequest jwtRequest) {
try {
authenticate(jwtRequest.getUsername(), jwtRequest.getPassword());
final UserDetails userDetails = userDetailsService.loadUserByUsername(jwtRequest.getUsername());
final String token = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new JwtResponse(token));
}catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(e.getMessage(),HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private void authenticate(String username, String password) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (DisabledException e) {
e.printStackTrace();
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) {
e.printStackTrace();
throw new Exception("Invalid Credentials", e);
}
}
}
JwtAuthenticationEntryPoint:-
package com.bdtool.config;
import java.io.IOException;
import java.io.Serializable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
#Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
AJAX->
$("#somebutton").click(function() {
jQuery.ajax({
url: 'logout',
type: 'GET',
headers: {
'Authorization': 'Bearer ' + sessionStorage.getItem("Token")
},
success: function() {
console.log("ok");
}
});
});
My JSP code:-
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%# taglib prefix="sec"
uri="http://www.springframework.org/security/tags"%>
class="menu-arrow"></span></a>
<ul>
<sec:authorize access="isAuthenticated()">
<li>Project Dashboard</li>
<li>Product Dashboard</li>
</sec:authorize>
</ul></li>
This seams over-complicated to me. I have a sample resource-server retrieving authorities from a JPA repo here and web security config is no more complicated than:
#EnableGlobalMethodSecurity(prePostEnabled = true)
public static class WebSecurityConfig {
#Bean
public ExpressionInterceptUrlRegistryPostProcessor expressionInterceptUrlRegistryPostProcessor() {
return (ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) -> registry
.antMatchers("/secured-route")
.hasRole("AUTHORIZED_PERSONNEL")
.anyRequest()
.authenticated();
}
#Bean
public SynchronizedJwt2AuthenticationConverter<JwtAuthenticationToken> authenticationConverter(
ClaimSet2AuthoritiesConverter<ClaimSet> authoritiesConverter) {
return jwt -> new JwtAuthenticationToken(jwt, authoritiesConverter.convert(new UnmodifiableClaimSet(jwt.getClaims())));
}
#Bean
public ClaimSet2AuthoritiesConverter<ClaimSet> authoritiesConverter(UserAuthorityRepository authoritiesRepo) {
return new PersistedGrantedAuthoritiesRetriever(authoritiesRepo);
}
}
It makes usage of a few #ConditionalOnMissingBean auto-configured by spring-boot, but you can find the list in source (and they are not so many).
PS
A way more efficient approach is adding authorities to JWT access-tokens (inside authorization-server): SQL request is executed only when a new token is emitted, not at each request.
It is easy to map authorities from JWT private claims.
Other PS
The Java version you are using is very deprecated and Spring versions comming this fall will require Java 17 as minimum
Last PS
your boot version is deprecated too and WebSecurityConfigurerAdapter should not be used anymore, in favor of providing a SecurityFiterChain #Bean (this already works in the boot version you use)

Unable to map collection com.bank.model.Customer.account I got this error while running my test case

I got Unable to map collection com.bank.model.Customer.account error while running my controller test case..please give a solution.
I using OneTOMany association b/w customer and Account, here I used List to store the accounts.
I don't know why got this type error I am going share that error too
My controller test
'''
package com.bank.controller;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import com.bank.model.Account;
import com.bank.model.Customer;
import com.bank.repository.AccountRepository;
import com.bank.service.AccountService;
import com.bank.service.CustomerService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class testController {
#Autowired
private MockMvc mockMvc;
#Autowired
private WebApplicationContext context;
ObjectMapper objectMapper=new ObjectMapper();
#MockBean
private AccountService accountService;
#MockBean
private CustomerService customerService;
#Before
public void setUp() {
mockMvc=MockMvcBuilders.webAppContextSetup(context).build();
}
#Test
public void testCreateCustomer() throws Exception {
Account account=new Account();
account.setAccountNumber(456);
account.setAccountType("savings");
account.setBalance(2000.0);
Customer customer=new Customer();
customer.setCustomerId(1);
customer.setCustomerName("Manasa");
List<Account> acc=new ArrayList<>();
acc.add(account);
String inputInJson=objectMapper.writeValueAsString(customer);
String URI="/customer/createCust";
Mockito.when(customerService.customerCreate(Mockito.any(Customer.class))).thenReturn(customer);
RequestBuilder requestBuilder=MockMvcRequestBuilders
.post(URI)
.accept(MediaType.APPLICATION_JSON).content(inputInJson)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result=mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response=result.getResponse();
String outputInJson=response.getContentAsString();
assertThat(outputInJson).isEqualTo(outputInJson);
assertEquals(HttpStatus.OK.value(),response.getStatus()-1);
}
'''
My model are
'''
package com.bank.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Proxy;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#Entity
#Table(name="Customer")
#Proxy(lazy = false)
#JsonIgnoreProperties(ignoreUnknown = true)
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Integer customerId;
#Column(name="customerName")
String customerName;
#OneToMany( targetEntity=Customer.class,cascade = CascadeType.ALL)
#JoinColumn(name="ca_fk",referencedColumnName = "accountNumber")
private List<Account> account=new ArrayList<>();
public Customer() {
super();
}
public Customer(String customerName, List<Account> account) {
super();
this.customerName = customerName;
this.account = account;
}
public Integer getCustomerId() {
return customerId;
}
public void setCustomerId(Integer customerId) {
this.customerId = customerId;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public List<Account> getAccount() {
return account;
}
public void setAccount(List<Account> account) {
this.account = account;
}
#Override
public String toString() {
return "Customer [customerId=" + customerId + ", customerName=" + customerName + ", account=" + account + "]";
}
}
'''
'''
package com.bank.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Proxy;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#Entity
#Table(name="Account")
#Proxy(lazy = false)
#JsonIgnoreProperties(ignoreUnknown = true)
public class Account {
#Id
int accountNumber;
#Column(name="balance")
Double balance;
#Column(name="accountType")
String accountType;
//Customer customer;
public Account() {
super();
}
public Account(int accountNumber, Double balance, String accountType, Customer customer) {
super();
this.accountNumber = accountNumber;
this.balance = balance;
this.accountType = accountType;
}
public int getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(int accountNumber) {
this.accountNumber = accountNumber;
}
public Double getBalance() {
return balance;
}
public void setBalance(Double balance) {
this.balance = balance;
}
public String getAccountType() {
return accountType;
}
public void setAccountType(String accountType) {
this.accountType = accountType;
}
public Account(int accountNumber, Double balance, String accountType) {
super();
this.accountNumber = accountNumber;
this.balance = balance;
this.accountType = accountType;
}
}
'''
while running it works fine but issue is only with test cases.
My pom.xml file 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 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.6.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bank1</groupId>
<artifactId>bankProjectCapstone-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>bankProjectCapstone-1</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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
</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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
'''
so far I got this error
'''
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Unable to map collection com.bank.model.Customer.account
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804) ~[spring-beans-5.3.16.jar:5.3.16]
at
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132) ~[spring-test-5.3.16.jar:5.3.16]
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124) ~[spring-test-5.3.16.jar:5.3.16]
Caused by: org.hibernate.AnnotationException: Unable to map collection com.bank.model.Customer.account
at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1723) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
at org.hibernate.cfg.annotations.CollectionBinder.bindOneToManySecondPass(CollectionBinder.java:944) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
Caused by: org.hibernate.cfg.RecoverableException: Unable to find column with logical name: accountNumber in org.hibernate.mapping.Table(customer) and its related supertables and secondary tables
at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:844) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:126) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1713) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
... 102 common frames omitted
Caused by: org.hibernate.MappingException: Unable to find column with logical name: accountNumber in org.hibernate.mapping.Table(customer) and its related supertables and secondary tables
at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:839) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
... 104 common frames omitted
'''

#RefreshScope not working with external config files

I added the following dependencies in my pom so I could make use of Spring cloud
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Added spring-cloud.version as Finchley.RELEASE
This is the bean that I intend to refresh:
#Component
#ConfigurationProperties(ignoreUnknownFields = true,prefix="global")
#PropertySource(value = "${spring.config.location}")
#Getter
#Setter
#Validated
#RefreshScope
public class GeneralProperties {
private String mode;
}
Accessing the bean in my controller:
#RestController
#RequestMapping
#RefreshScope
public class AppController {
private static final AnalyticsLogger LOGGER = AnalyticsLoggerFactory
.getLogger(AppController.class);
#Autowired
SimulatorRequestProcessor simulatorRequestProcessor;
#Autowired
GeneralProperties generalProperties;
#ResponseBody
#PostMapping(value = "/api/mock-getdata", produces = "application/json")
public String fetchResponseBasedOnMode(#RequestHeader HttpHeaders headers,
#RequestBody String request) {
String response = null;
LOGGER.info("color: "+color);
switch (generalProperties.getMode()) {
//code
Properties set in application config:
spring.config.location=file:///var/lib/data/demo/config/generalConfig.properties
management.endpoints.web.exposure.include=refresh
Unable to refresh the value of mode. Can someone point out the error in this code. My property files are in a folder that is not committed in git, so I am not making use of spring-cloud-config.
Put this in src/main/resources/application.properties
management.endpoints.web.exposure.include=*
Run this program with this argument --spring.config.additional-location=/tmp/application.properties
package com.example.demorefreshscopeexternalfile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.style.ToStringCreator;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
#RestController
#EnableConfigurationProperties(DemorefreshscopeexternalfileApplication.MyProps.class)
public class DemorefreshscopeexternalfileApplication {
#Autowired
MyProps props;
#RequestMapping
public String message() {
return props.getMessage();
}
public static void main(String[] args) {
SpringApplication.run(DemorefreshscopeexternalfileApplication.class, args);
}
#ConfigurationProperties("my")
public static class MyProps {
private String message;
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public String toString() {
return new ToStringCreator(this)
.append("message", message)
.toString();
}
}
}
contents of /tmp/application.properties
my.message=message from /tmp
view http://localhost:8080
/tmp/application.properties can be updated, the post to /actuator/refresh and view 8080 again and you will see updated values.
Built with boot 2.2.4 and Hoxton.SR1
See https://docs.spring.io/spring-boot/docs/2.2.4.RELEASE/reference/html/appendix-application-properties.html#common-application-properties for spring.config.* and their meaning.

spring boot configuration properties not working

This is driving me up the wall trying to get spring boot #configurationproperties annotation working. So hoping someone can shed some light on this for me as to what I am doing wrong.
I have a spring boot application and it contains a application.properties on the classpath. It has a value in there of
server.contextPath=/test/v1
server.port=8080
spring.profiles.active=dev
vendors=me
I have a application.class which has the spring boot annotation and sits at the top of my package hierarchy
package com.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
#EnableConfigurationProperties
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I am trying to map the property vendors into a configurationproperties bean as below
package com.test.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
#Component
#PropertySource("classpath:application.properties")
#ConfigurationProperties
public class GlobalProperties {
private String vendors;
public String getVendors() {
return vendors;
}
public void setVendors(String vendors) {
this.vendors = vendors;
}
}
and then call this bean from my rest controller. I know it resolves the property as when i rename it the server fails to start. In the code below the props bean is not getting autowired and is null. //code ommitted for brevity
package com.test.controller;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.test.config.GlobalProperties;
#RestController
#Component
public class MController {
//TODO should be wired in from properties file
#Autowired
GlobalProperties props;
private boolean vendorUnknown(String vendor) {
if(props.getAllowedVendor().equalsIgnoreCase(vendor)) {
return true;
}
return false;
}
#RequestMapping(value = "/test/{id}", method = RequestMethod.GET, produces = { "application/json" })
public ResponseEntity<?> getStatus(
#PathVariable String id) {
//#RequestBody Bookmark input
if(vendorUnknown("me")) {
System.out.println("found");
};
return ResponseEntity.noContent().build();
}
}
Anybody point me to what i have done wrong please?
UPDATE:
changed the code above to be a more simplistic version with a test class to recreate the issue. See below for my pom.xml and test class
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>
<groupId>com.me.test</groupId>
<artifactId>test-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- tag::actuator[] -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- end::actuator[] -->
<!-- tag::tests[] -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- end::tests[] -->
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Test class:
package com.test.controller;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class MControllerTest {
#Autowired
private MockMvc mockMvc;
#InjectMocks
MController testController;
#Before
public void setup() {
// this must be called for the #Mock annotations above to be processed
// and for the mock service to be injected into the controller under
// test.
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(testController).build();
}
#Test
public void testPropertiesMsg() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/test/1").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
Remove #PropertySource. You can keep #Component, or if you don't, specify #EnableConfigurationProperties(GlobalProperties.class).
Don't need #Component on testController. But I think your issue is where you're calling vendorUnknown method from. It's not shown in your code. If calling from the constructor, then the bean initialization has not completed yet, and GlobalProperties props is indeed null.
Edit:
Based on OP's edit, here's a fully working solution.
DemoApplication.java:
#SpringBootApplication
#EnableConfigurationProperties
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
DemoController.java:
#RestController
public class DemoController {
#Autowired
private DemoProperties props;
#GetMapping(value = "/", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<?> getVendor() {
return ResponseEntity.ok(props.getVendors());
}
}
DemoProperties.java:
#ConfigurationProperties
#Component
public class DemoProperties {
private String vendors;
public String getVendors() {
return vendors;
}
public void setVendors(String vendors) {
this.vendors = vendors;
}
}
application.properties:
vendors=me
DemoControllerTest.java:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DemoControllerTest {
#Autowired
TestRestTemplate restTemplate;
#Test
public void testGenVendor() throws Exception {
String vendor = restTemplate.getForObject("/", String.class);
assertThat(vendor).isEqualTo("me");
}
}
Problems with OP's code:
MockMvc doesn't use the main class, so EnableConfigurationPropertiesis not processed. MockMvc or WebMvcTest is designed to test the web layer (duh!), not the whole app. Using either of those. the properties bean should be set by the test.
InjectMocks fails silently. See Why You Should Not Use InjectMocks Annotation to Autowire Fields.
Add #EnableConfigurationProperties to your Application class to enable scanning ConfigurationProperties beans.

Resources