Did Quarkus 2.7.1.Final remove support for annotations? Following code does not work, but worked in Quarkus 1.11. Code below.
Any suggestions/pointers are appreciated.
Thanks
GreetingResource.java:
#Path("/hello")
public class GreetingResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
if (isGramMessageHandlerFound()){
return "Hello - GramMessageHandler method found!";
} else {
return "Sorry - no GramMessageHandler method found!";
}
}
#GramMessageHandler(type="firstGramMessageHandler")
void firstGramMessageHandler()
{
}
#GramMessageHandler(type="secondGramMessageHandler")
void secondGramMessageHandler()
{
}
boolean isGramMessageHandlerFound()
{
final Method[] methods = getClass().getMethods();
for (final Method method : methods) {
final GramMessageHandler gramMessageHandler = method.getAnnotation(GramMessageHandler.class);
if (gramMessageHandler != null){
return true;
}
}
return false;
}
}
And the annotation:
GramMessageHandler.java:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface GramMessageHandler
{
String type() default "java.lang.String";
}
GreetingResourceTest.java
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
#QuarkusTest
public class GreetingResourceTest {
#Test
public void testHelloEndpoint() {
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("Hello - GramMessageHandler method found!"));
}
}
Running mvn clean test results in:
[ERROR] GreetingResourceTest.testHelloEndpoint:18 1 expectation failed.
Response body doesn't match expectation.
Expected: is "Hello - GramMessageHandler method found!"
Actual: Sorry - no GramMessageHandler method found!
Related
I am new to Junit and Mockito.
Trying to mock one of the object of the class, but it is not working.
The mock method is returning an empty list, due to which test case is getting failed.
This is the code which I have written.
Junit Test Class : Here I have mocked the object and method to return an Arraylist, but when the code is executed this mock method is returning an empty list due to which test case is getting failed.
package com.business;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import com.data.api.ToDoService;
public class TodoBusinessImplMockTest {
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void testRetrieveTodosRelatedToSpringUsingMock()
{
ToDoService todoServiceMock = mock(ToDoService.class);
List<String> todoList=Arrays.asList("Learn Spring MVC", "Learn Spring","Learn to Dance");
Mockito.when(todoServiceMock.retrieveTodos("Dummy")).thenReturn(todoList);
TodoBusinessImpl todoBusinessImpl = new TodoBusinessImpl(todoServiceMock);
List<String> todos = todoBusinessImpl.retrieveTodosRelatedToSpring("Ranga");
assertEquals(2, todos.size());
}
}
Interface : ToDoService.java
package com.data.api;
import java.util.List;
public interface ToDoService {
public List<String> retrieveTodos(String s);
}
TodoBusinessImpl.java
package com.business;
import java.util.ArrayList;
import java.util.List;
import com.data.api.ToDoService;
public class TodoBusinessImpl {
private ToDoService todoService;
TodoBusinessImpl(ToDoService todoService) {
this.todoService = todoService;
}
public List<String> retrieveTodosRelatedToSpring(String s) {
List<String> filteredTodos = new ArrayList<String>();
List<String> allTodos = todoService.retrieveTodos(s);
for (String todo : allTodos) {
if (todo.contains("Spring")) {
filteredTodos.add(todo);
}
}
return filteredTodos;
}
}
Your spec says:
Mockito.when(todoServiceMock.retrieveTodos("Dummy")).thenReturn(todoList);
but your call uses:
todoBusinessImpl.retrieveTodosRelatedToSpring("Ranga");
"Ranga" isn't "Dummy", therefore your spec isn't matched; therefore mockito returns the default result (which would be an empty list).
Try replacing the "Dummy" in Mockito.when(todoServiceMock.retrieveTodos("Dummy")).thenReturn(todoList); with anyString() (import static org.mockito.ArgumentMatchers.anyString;). This did the trick for me.
I'm using Java 8 Spring boot. I have below method.
public hello() {
try {
// send message
}
catch(HttpClientErrorException e) {
if (e.getRawStatusCode() == 401) {
// I need to retry the same hello() method for three times as in 10sec, 20sec and 25sec.
}
}
}
I need to call the same method three times for retrying whenever it hits the catch block.
How can I do this asynchronously?
I found below code but it didn't work.
#Retryable( value = {RestClientException.class}, maxAttempts = 3, backoff = #Backoff(3000))
Appreciate your help.
You can use #Async annotation from Spring to achieve that.
You have to create a config like this:
#Configuration
#EnableRetry
#EnableAsync
class RetryConfig {}
When you want to use Async with Retry you have to decorate the method with Async which is trying to call a Retryable method. Also, you have to make sure that you are returning Future<> or similar because you are sending that piece of code for a toss in the background
I have also implemented fallback mechanism otherwise the request will terminate with 500 exception.
If you run the code below you can see that the main request is executed on thread http-nio-8080-exec-1 while your Async code is executed on a different thread task-1.
I tried to explain this with a sample service method, but the concept will be same for local or remote service call.
A detailed exmaple is given below:
package com.example.silentsudo.springcloudssamples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
#SpringBootApplication
public class SpringCloudsSamplesApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudsSamplesApplication.class, args);
}
}
#RequestMapping(path = "sample")
#RestController
class SampleController {
private final GreetService greetService;
SampleController(GreetService greetService) {
this.greetService = greetService;
}
#GetMapping
public String hello() {
System.out.println(Thread.currentThread().getName());
return "Hello!";
}
#GetMapping(path = "greet")
public String greet(#RequestParam(value = "name", defaultValue = "John") String name) {
return greetService.greet(name);
}
#Async
#GetMapping(path = "greet-async")
public CompletableFuture<String> greetAsync(#RequestParam(value = "name", defaultValue = "John") String name) {
return CompletableFuture.completedFuture(greetService.greet(name));
}
}
#Configuration
#EnableRetry
#EnableAsync
class RetryConfig {
}
#Service
class GreetService {
private final UngaBungaService ungaBungaService;
GreetService(UngaBungaService ungaBungaService) {
this.ungaBungaService = ungaBungaService;
}
#Retryable(maxAttempts = 5, value = GreetException.class, backoff = #Backoff(value = 3000L))
public String greet(String name) {
return ungaBungaService.lol(name);
}
#Recover
public String recoverGreetException(GreetException greetException) {
return greetException.getMessage();
}
}
#Service
class UngaBungaService {
public String lol(String name) {
System.out.println(Thread.currentThread().getName());
throw new GreetException("Called greet for " + name);
}
}
class GreetException extends RuntimeException {
public GreetException(String message) {
super(message);
}
}
For retry mechanisms, you can to use the #Retryable(value = RestClientException.class)
For this to trigger, you need to actually throw this exception (or something that extends from RestClientException). Because of your catch statement, no exception is actually thrown, so the retry mechanism doesn't kick in.
#Retryable( value = {RestClientException.class}, maxAttempts = 3, backoff = #Backoff(3000))
public void hello() {
try {
// send message
}
catch(HttpClientErrorException e) {
if (e.getRawStatusCode() == 401) {
throw new RestClientException("meaningfull message");
}
}
}
If you want to run some catch code after the 3 retries failed, you can make use of the #Recover annotation on a recovery method.
If you want some more info on the retry mechanism, you could look here
Also don't forget to add #EnableRetry in your config so that the annotations are used.
Full code example with spring boot
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
context.getBean(TestService.class).hello();
context.close();
}
#Configuration
#EnableRetry
public class AppConfig {
}
#Service
public class TestService {
#Retryable(value = {IllegalArgumentException.class}, maxAttempts = 4, backoff = #Backoff(delay = 1000, multiplier = 4))
public void hello() {
try {
int a = Integer.parseInt(null);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Exception triggered");
}
}
}
I'am Ropi, i have an issue with my spring boot project test.
The issue is :
UnknownClassName.initializationError : NoClassDefFound UnknownClassName;
when i run the project it with skiped test proccess, it run well . and then i run the test it also run well..
but after i edit the test ( for example : i only add space on my test code), it give me an error.
and then when i edited my working code ( for example : i only add space on my coding work ), it give me illegal error.
My testing Code :
import com.emerio.rnd.otp.service.OtpService;
import org.hamcrest.core.IsNot;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.hamcrest.Matchers.*;
#RunWith(SpringRunner.class)
// #SpringBootTest
#WebFluxTest
public class OtpApplicationTests {
private Integer OTP1;
private Integer OTP2;
#Autowired
private WebTestClient webTestClient;
private OtpService otpService = new OtpService();
#Before
public void setup() throws Exception {
OTP1 = otpService.generateOTP("admin");
OTP2 = otpService.generateOTP("admin1");
}
// #WebFluxTest(OtpController.class)
#Test
public void generateOTPSuccess() throws Exception
{
webTestClient.get().uri("/generateotp/admin")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.data.otp").isNotEmpty();
}
#Test
public void generateOTPUsernameNotExist() throws Exception
{
webTestClient.get().uri("/generateotp/null")
.exchange()
.expectStatus().isBadRequest();
}
// #Test
// public void generateNewOTP() throws Exception
// {
// webTestClient.get().uri("/generateotp/admin1")
// .exchange()
// .expectStatus().isOk()
// .expectBody()
// .jsonPath("$.[otp != "+OTP2+"]");
// }
#Test
public void validateOTPSuccess() throws Exception
{
webTestClient.get().uri("/validateotp/admin/"+OTP1.toString())
.exchange()
.expectStatus().isOk();
}
#Test
public void validateOTPfailed() throws Exception
{
webTestClient.get().uri("/validateotp/admin/981981")
.exchange()
.expectStatus().isBadRequest();
}
#Test
public void validateOTPWithChar() throws Exception
{
webTestClient.get().uri("/validateotp/admin/AS1213")
.exchange()
.expectStatus().isBadRequest();
}
#Test
public void validateOTPTimeOut() throws Exception
{
// Thread.sleep(300010);
webTestClient.get().uri("/validateotp/admin/981981")
.exchange()
.expectStatus().isBadRequest();
}
My Controller Working code
My Controller :
import com.emerio.rnd.otp.response.Response;
import com.emerio.rnd.otp.service.OtpService;
import com.google.gson.Gson;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
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.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
#RestController
public class OtpController
{
private OtpService otpService = new OtpService();
private Response response = new Response();
#RequestMapping(method=RequestMethod.GET , value="/generateotp/{username}", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
public Mono<Object> generateOTP (#PathVariable String username)
{
try
{
if (username.equals("null"))
{
return Mono.just(new Throwable("error"));
} else
{
int otp = otpService.generateOTP(username);
JSONObject jObj = new JSONObject();
jObj.put("otp", otp);
return Mono.just(response.loaded(new Gson().fromJson(jObj.toString(), Object.class)));
}
} catch (Exception e)
{
return null;
}
}
#RequestMapping(method=RequestMethod.GET , value="/validateotp/{username}/{otp}", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
public Mono<Response> validateOTP (#PathVariable String username, #PathVariable String otp)
{
try
{
Integer otpCache = otpService.getOTP(username);
if (!otpCache.toString().equals(otp))
{
System.out.println("cache awal : " + otpCache);
System.out.println("cache : " + otp);
return Mono.just(response.loaded("otp not valid"));
} else
{
otpService.clearOTP(username);
return Mono.just(response.loaded("otp valid"));
}
} catch (Exception e)
{
return null;
}
}
My OTP Service :
package com.emerio.rnd.otp.service;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.springframework.stereotype.Service;
#Service
public class OtpService
{
private static final Integer EXPIRE_MINS = 5;
private LoadingCache<String, Integer> otpCache;
public OtpService()
{
super();
otpCache = CacheBuilder.newBuilder()
.expireAfterWrite(EXPIRE_MINS, TimeUnit.MINUTES).build(new CacheLoader<String,Integer>()
{
public Integer load (String key)
{
return 0;
}
});
}
public int generateOTP (String key)
{
Random random = new Random();
int otp = 100000 + random.nextInt(900000);
otpCache.put(key, otp);
return otp;
}
public int getOTP (String key)
{
try
{
return otpCache.get(key);
} catch (Exception e)
{
return 0;
}
}
public void clearOTP (String key)
{
otpCache.invalidate(key);
}
}
In Spring boot 1.3.6-RELEASE I had the below class registered to jersey. Every java.util.Date field would be read and returned as ISO8601 format. However, when updating to 1.4.1-RELEASE it now sometimes works and sometimes doesn't. What's the new proper way to enable this?
package com.mypackage;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Date;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.databind.util.ISO8601Utils;
#Provider
public class DateTimeParamConverterProvider implements ParamConverterProvider {
#SuppressWarnings("unchecked")
#Override
public <T> ParamConverter<T> getConverter(Class<T> clazz, Type type, Annotation[] annotations) {
if (type.equals(Date.class)) {
return (ParamConverter<T>) new DateTimeParamConverter();
} else {
return null;
}
}
static class DateTimeParamConverter implements ParamConverter<Date> {
#Override
public java.util.Date fromString(String value) {
if (value == null) {
return null;
}
try {
return ISO8601Utils.parse(value, new ParsePosition(0));
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
#Override
public String toString(Date value) {
return ISO8601Utils.format(value);
}
}
}
I register this provider like this:
#Component
#ApplicationPath("/")
public class JerseyConfiguration extends ResourceConfig {
private static final Logger log = Logger.getLogger(JerseyConfiguration.class.getName());
#Autowired
public JerseyConfiguration(LogRequestFilter lrf) {
register(new ObjectMapperContextResolverNonNull());
register(RestServiceImpl.class);
property(ServletProperties.FILTER_FORWARD_ON_404, true);
register(DateTimeParamConverterProvider.class, 6000);
...
Just define this in your application.properties:
spring.jackson.date-format=com.fasterxml.jackson.databind.util.ISO8601DateFormat
Here is my code for creating a custom Annotation for validating Name
ValidName.java
package custom.Annotation;
import java.lang.annotation.*;
import net.sf.oval.configuration.annotation.Constraint;
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.LOCAL_VARIABLE)
#Constraint(checkWith=NameValidator.class)
public #interface ValidName {
String message() default NameValidator.message;
}
here is my code for Constraint Class
package custom.Annotation;
import net.sf.oval.Validator;
import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
import net.sf.oval.context.OValContext;
import net.sf.oval.exception.OValException;
import play.Logger;
import java.util.regex.Pattern;
public class NameValidator extends AbstractAnnotationCheck<ValidName>
{
public final static String message="custom.message";
private static final String letter = "[a-zA-Z]";
public static final Pattern VALID_PATTERN = Pattern.compile(letter);
public static boolean isValidText(String userName) {
return VALID_PATTERN.matcher(userName).matches();
}
#Override
public void configure(ValidName annotation) {
setMessage(annotation.message());
}
#Override
public boolean isSatisfied(Object validatedObject, Object valueToValidate, OValContext context,
Validator validator) throws OValException {
try
{
if (valueToValidate == null) {
return false;
}
}catch (Exception e){
e.getMessage();
}
return` isValidText(valueToValidate.toString()`);
}
}
When I applied #ValidName to any local variable nothing happened
and I also am unable to debug the program. Any suggestions?
You need to use the oval validation by calling validate method of oval validation library.
#Autowired
#Qualifier("ovalValidator")
private Validator ovalValidator;
List<ConstraintViolation> violations = null;
violations = ovalValidator.validate(objectToValidate);