My current dependency set-up for demo api:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-graphql:2.7.2-SNAPSHOT'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.7.2-SNAPSHOT'
testImplementation 'org.springframework:spring-webflux'
testImplementation 'org.springframework.graphql:spring-graphql-test:1.0.0'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
Test class:
import com.example.demo.dao.ProfileDao;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.graphql.test.tester.GraphQlTester;
import static org.springframework.test.util.AssertionErrors.assertNotNull;
#GraphQlTest
//#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class DemoApplicationTests {
#Autowired
GraphQlTester graphQlTester;
#MockBean
ProfileDao dao;
#Test
void contextLoads() {
assertNotNull("graphQlTester null", graphQlTester);
}
}
I've tried few approaches from varios advices from internet like using SpringBootTest instead of GraphQlTest but nothing worked.
Related
I'm trying to implement Bcrypt to hash passwords. But the issue I'm facing is that Spring Security enables authentication for all end points by default. But I don't want that I just want to signup a user and simply generate hash for the passwords. But I can't do that as when I make a Post request from Postman it shows 401 Unauthorized.4
I tried the following things in main class:
1-
#EnableWebSecurity
2-
#EnableAutoConfiguration
3-
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
4-
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors();
return http.build();
}
5-
I tried with org.mindrot:jbcrypt:0.4 but when I try to use BCrypt in my service function it does not import it from mindrot
I want to use spring security for Authentication and Authorization in future, But First I need to sign up a user and hash his password.
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.1'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '19'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
implementation 'org.mindrot:jbcrypt:0.4'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
tasks.named('test') {
useJUnitPlatform()
}
main class
package com.example.bcrypt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class BcryptApplication {
public static void main(String[] args) {
SpringApplication.run(BcryptApplication.class, args);
}
}
UserRepo
package com.example.bcrypt.repository.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.bcrypt.entity.User;
public interface UserRepository extends JpaRepository<User,Integer>{
}
UserService
package com.example.bcrypt.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.example.bcrypt.entity.User;
import com.example.bcrypt.repository.dao.UserRepository;
#Service
public class UserService {
#Autowired
private UserRepository userRepo;
public User create(User body){
BCryptPasswordEncoder bcrypt=new BCryptPasswordEncoder();
String hashedpassword=bcrypt.encode(body.getPassword());
body.setPassword(hashedpassword);
User res=userRepo.save(body);
System.out.println(res);
return res;
}
}
UserControlelr
package com.example.bcrypt.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.bcrypt.entity.User;
import com.example.bcrypt.service.UserService;
#RestController()
#RequestMapping("/users")
public class UserController {
#Autowired
private UserService userService;
#PostMapping("/register")
public User create(#RequestBody User body){
User res=userService.create(body);
System.out.println(res);
return res;
}
}
Your request fails because of spring security. You can add exceptions or disable it completely by providing a simple #Bean.
#Bean
public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) {
return http
.csrf()
.disable()
.authorizeExchange(authorizeExchangeSpec -> authorizeExchangeSpec.anyExchange().permitAll())
.build();
}
I count'tell from your code what endpoint you're calling so in the example above I've allowed any request. Note that you should not do that in production environments.
Edit:
I'm sorry, I gave you a bean for webflux.
You should be able to use this bean instead and have it all working.
I usually create a configuration class ex:
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.cors().disable()
.csrf().disable()
.authorizeHttpRequests().requestMatchers("/users/register").permitAll().and()
.build();
}
}
I have a class test which send me an error when I run the test.
I followed several threads and I have the right import "import org.junit.jupiter.api.Test"
So I don't understand why it sends me this error :
Cannot invoke "org.springframework.test.web.servlet.MockMvc.perform(org.springframework.test.web.servlet.RequestBuilder)" because "this.mockMvc" is null
My code :
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#WebMvcTest(TestController.class)
public class ControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private CreateMessageProvider createMessageProvider;
#Test
public void test() throws Exception {
this.mockMvc.perform(get("/test"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("OK"));
}
}
Gradle config :
mockitoCoreVersion = '4.6.1'
mockitoJunitJupiterVersion = '4.6.1'
springBootTestVersion = '2.7.2'
springTestVersion = '5.3.22'
testImplementation "org.springframework.boot:spring-boot-test:$springBootTestVersion"
testImplementation "org.springframework:spring-test:$springTestVersion"
testImplementation "org.mockito:mockito-junit-jupiter:$mockitoJunitJupiterVersion"
testImplementation "org.mockito:mockito-core:$mockitoCoreVersion"
EDIT : I found the solution. My gradle file didn't have this dependency :
testImplementation "org.springframework.boot:spring-boot-starter-test:2.7.2"
Try
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#AutoConfigureMockMvc
#SpringBootTest
public class ControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private CreateMessageProvider createMessageProvider;
#Test
public void test() throws Exception {
this.mockMvc.perform(get("/test"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("OK"));
}
}
Use these annotations :
#RunWith(SpringRunner.class)
#AutoConfigureMockMvc
#ExtendWith({RestDocumentationExtension.class, SpringExtension.class})
I am using the "RunWith(MockitoJUnitRunner.class)", the #Mock notationt to mock the service and the #InjectMocks notation to inject the mock service to the controller. I get a NullPointerException in the ChargingStationsControllerTest:40, in the "when". I debugged and realized that the mocks are null.
Here is my code:
package com.example.assignmentchargingstations.controllers;
import com.example.assignment.chargingStations.controllers.ChargingStationsController;
import com.example.assignment.chargingStations.models.AddressInfo;
import com.example.assignment.chargingStations.models.ChargingStation;
import com.example.assignment.chargingStations.models.StatusType;
import com.example.assignment.chargingStations.services.OpenChargeMapService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class ChargingStationsControllerTest {
#Mock
private OpenChargeMapService openChargeMapService;
#InjectMocks
private ChargingStationsController chargingStationsController;
#Test
public void testGetNearestChargingStations() throws Exception {
Double latitude = 90.0;
Double longitude = 90.0;
List<ChargingStation> chargingStationsListExpected = new ArrayList<>();
StatusType statusTypeExpected = StatusType.builder().IsOperational(true).build();
AddressInfo addressInfoExpected = AddressInfo.builder().Latitude(latitude).Longitude(longitude).Title("Test Charging Station").build();
chargingStationsListExpected.add(ChargingStation.builder().StatusType(statusTypeExpected).AddressInfo(addressInfoExpected).build());
when(openChargeMapService.getNearestChargingStations(anyDouble(), anyDouble())).thenReturn(chargingStationsListExpected);
ResponseEntity<List<ChargingStation>> responseExpected = chargingStationsController.getNearestChargingStations(latitude, longitude);
Assertions.assertEquals(responseExpected.getStatusCode(), HttpStatus.OK);
Assertions.assertEquals(responseExpected.getBody(), chargingStationsListExpected);
}
}
The controller that I'm testing:
package com.example.assignment.chargingStations.controllers;
import com.example.assignment.chargingStations.models.ChargingStation;
import com.example.assignment.chargingStations.services.OpenChargeMapService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
#Controller
public class ChargingStationsController {
private final OpenChargeMapService openChargeMapService;
public ChargingStationsController(OpenChargeMapService openChargeMapService) {
this.openChargeMapService = openChargeMapService;
}
#RequestMapping(path = "/nearest-charging-stations", method = RequestMethod.GET)
public ResponseEntity<List<ChargingStation>> getNearestChargingStations(#RequestParam Double latitude, #RequestParam Double longitude) {
List<ChargingStation> nearestChargingStations = openChargeMapService.getNearestChargingStations(latitude, longitude);
return new ResponseEntity<>(nearestChargingStations, HttpStatus.OK);
}
}
The service:
package com.example.assignment.chargingStations.services;
import com.example.assignment.chargingStations.clients.OpenChargeMapClient;
import com.example.assignment.chargingStations.models.ChargingStation;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.List;
#Service
public class OpenChargeMapService {
private static final Double MAX_LATITUDE = 90.0000000;
private static final Double MIN_LATITUDE = -90.0000000;
private static final Double MAX_LONGITUDE = 180.0000000;
private static final Double MIN_LONGITUDE = -180.0000000;
private final OpenChargeMapClient openChargeMapClient;
public OpenChargeMapService(OpenChargeMapClient openChargeMapClient) {
this.openChargeMapClient = openChargeMapClient;
}
public List<ChargingStation> getNearestChargingStations(Double latitude, Double longitude) {
validateLatitudeLongitude(latitude, longitude);
List<ChargingStation> chargingStationsList = openChargeMapClient.getNearestChargingStations(latitude, longitude);
return chargingStationsList;
}
private void validateLatitudeLongitude(Double latitude, Double longitude) {
if (isLatitudeOutOfRange(latitude) || isLongitudeOutOfRange(longitude)) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Values for latitude and longitude are out of range.");
}
}
private boolean isLatitudeOutOfRange(Double latitude) {
return (latitude.compareTo(MIN_LATITUDE) < 0) || (latitude.compareTo(MAX_LATITUDE) > 0);
}
private boolean isLongitudeOutOfRange(Double longitude) {
return (longitude.compareTo(MIN_LONGITUDE) < 0) || (longitude.compareTo(MAX_LONGITUDE) > 0);
}
}
The build.gradle:
plugins {
id 'org.springframework.boot' version '2.5.1'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.projectlombok:lombok:1.18.18'
implementation 'junit:junit:4.13.1'
annotationProcessor 'org.projectlombok:lombok:1.18.18'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
Since you are using Spring Boot. You have two options. You can either test the class in isolation or you can load in the spring context.
Both approaches have their benefits and limitations.
Supply mock directly into the class in test.
public class Test {
ClassToMock service = mock(ClassToMock.class)
ClassInTest testService = new ClassInTest(service);
#Test
public void doTest() {
....
}
}
This approach, you are supplying a mock directly into your service in test. This will result in speedier runtimes, but you will not be able to do more comprehensive integration tests.
Load mock service directly into spring context
#SpringBootTest
#RunWith(SpringJUnit4ClassRunner.class)
public class Test {
#MockBean
ClassToMock service;
#Autowired
ClassInTest testService;
#Test
public void doTest() {
....
}
}
This will generate the spring context and mock the service component you have created. Doing so would test the wiring of your beans and your service in test. You will also have more flexibility in case you want to mock an encapsulating service (i.e. repository layer/data layer). You should also be able to use #Mock & #InjectMock with the class annotation you are currently using.
I am creating a custom annotation NullCheck for method parameter to check value is null or not hello(#NullCheck String text), but I am not able to invoke Aspect around the Annotation.
Main Class
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#SpringBootApplication
#EnableAutoConfiguration
#EnableAspectJAutoProxy
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Controller class, just invoking an aspect for POC, not returning anything
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/")
class HelloController {
#GetMapping
public void hello() {
hello("hi");
}
private void hello(#NullCheck String text) {
System.out.println(text);
}
}
Annotation
package com.example.demo;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#Documented
#Retention(RUNTIME)
#Target(ElementType.PARAMETER)
public #interface NullCheck { }
Aspect
package com.example.demo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class NullCheckAspect {
this is working
#Before("#annotation(org.springframework.web.bind.annotation.GetMapping)")
but this is not
#Before("#annotation(com.example.demo.NullCheck)")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("Before method:" + joinPoint.getSignature());
}
}
build.gradle
buildscript {
ext {
springBootVersion = '2.1.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
idea {
module {
// if you hate browsing Javadoc
downloadJavadoc = true
// and love reading sources :)
downloadSources = true
}
}
bootJar {
launchScript()
}
repositories {
mavenCentral()
jcenter()
}
bootJar {
launchScript()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'org.springframework.boot:spring-boot-devtools'
}
what am I missing?
As per my understanding and after doing some search on google, you can get method parameter and its value with particular annotation with following code:
package com.example.demo;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
#Component
#Aspect
public class NullCheckAspect {
#Around("execution(* com.example.demo.HelloController.nullChecker(String))")
public Object around(ProceedingJoinPoint pJoinPoint) throws Throwable {
Object[] args = pJoinPoint.getArgs();
Method method = MethodSignature.class.cast(pJoinPoint.getSignature()).getMethod();
Annotation[][] parametersAnnotations = method.getParameterAnnotations();
Map<String, Object> annotatedParameters = new HashMap<>();
int i = 0;
for(Annotation[] parameters : parametersAnnotations) {
Object arg = args[i];
String name = method.getParameters()[i++].getDeclaringExecutable().getName();
for(Annotation parameter: parameters) {
if ((parameter instanceof NullCheck)) {
System.out.println("Found the null checker annotation with name: " + name);
System.out.println("Found the null checker annotation with arg: " + arg);
annotatedParameters.put(name, arg);
}
}
}
System.out.println(annotatedParameters);
return pJoinPoint.proceed(args);
}
}
And with the interface annotation:
package com.example.demo;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.stereotype.Component;
#Component
#Retention(RUNTIME)
#Target(ElementType.PARAMETER)
public #interface NullCheck {
}
More details about my code you can check it at my github repository, I have created spring boot demo version and pushed it for you at https://github.com/krishnaiitd/learningJava/blob/master/springBoot/gs-spring-boot/src/main/java/com/example/demo/HelloController.java
This also include other type of aspects like tracking the time of a particular methods.
Hope this will help you to get the basic understanding of #Aspect in Spring boot.
I don't know why it is as it is but I had the same issue. This is can be solved easily by using Pointcuts, for example:
#Before("nulllCheckAnnotation()")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("Before method:" + joinPoint.getSignature());
}
}
#Pointcut("#annotation(com.example.demo.NullCheck)")
private void nulllCheckAnnotation() { }
Read more about pointcuts here if you interested: https://www.baeldung.com/spring-aop-pointcut-tutorial
I am trying to use project lombok to generate a logger like the example here.
When I go to intelliJ, there is no code completion for the log I enter. I get the error below:
Code exerpt:
package com.example.clement.recipeproject.bootstrap;
import com.example.clement.recipeproject.domain.*;
import com.example.clement.recipeproject.repositories.CategoryRepository;
import com.example.clement.recipeproject.repositories.RecipeRepository;
import com.example.clement.recipeproject.repositories.UnitOfMeasureRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
#Slf4j
#Component
public class DevBootstrap implements ApplicationListener<ContextRefreshedEvent> {
private CategoryRepository categoryRepository;
private UnitOfMeasureRepository unitOfMeasureRepository;
private RecipeRepository recipeRepository;
public DevBootstrap(CategoryRepository categoryRepository, UnitOfMeasureRepository unitOfMeasureRepository, RecipeRepository recipeRepository) {
this.categoryRepository = categoryRepository;
this.unitOfMeasureRepository = unitOfMeasureRepository;
this.recipeRepository = recipeRepository;
}
// returns List<Recipe>
private List<Recipe> getRecipes() {
log.debug("I am a debug message");
*** Update:
Added some more photos to show that the slf4j log is coming up, but just no appropriate methods after it.
When I jump into #Slf4j I get this.
Annotation processors turned on, but unsure if the configuration is correct.
Do you add slf4j dependencies to the build.gradle like below
dependencies {
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25'
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
}
Are you sure that you imported the correct #Slf4 annotation from package lombok.extern.slf4j.Slf4j?
There is an annotation of the same name in package groovy.util.logging.Slf4j.