Cacheable annotation it's ignored - java

I'm trying to store a value in the cache, but it's going inside the method every time when it's not supposed to do.
This is my Main class:
#EnableCaching
public class Main {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.run(args);
}
}
I have a service, which contains the method that it's supposed to store the value in the cache:
#Service
public class MethodManagerImpl implements MethodManager{
#Override
#Cacheable("sampleValue")
public String getValue() {
System.out.println("Going inside method");
return some stuff;
}
}
This method it's being called from another class, which is my RestController:
#RestController
public class MyRestController {
#Autowired
private MethodManager methodManager;
#PostMapping("/sampleEndpoint")
public String sampleEndpointMethod(){
return methodManager.getValue();
}
}
Additionally, I have the next config class, which I'm not sure if it's necessary:
#Component
public class SimpleCacheCustomizer implements CacheManagerCustomizer<ConcurrentMapCacheManager> {
#Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setCacheNames(asList("sampleValue"));
}
}
The problem is that every time that I call the method, it's going inside the method, so seems that it's not caching anything.

Related

How to automatically inject implementation based on Generics

I have a Service class defined like this,
#RequiredArgsConstructor
class SomeService<T extends AbstractResponse> {
private final ValidationService<T> validationService;
....
}
And I have two kinds of AbstractResponse, ResponseA and ResponseB and have a validation service defined for both of them.
#Service("aValidationService");
class AValidationService<ResponseA> implements ValidationService<ResponseA> {
....
}
and
#Service("ValidationService");
class BValidationService<ResponseB> implements ValidationService<ResponseB> {
....
}
Right now spring is throwing an error because it's not able to deduce the implementation of ValidationService to use in SomeService as there are two implementations of it. How do I make spring deduce the correct implementation based on the type of AbstractResponse?
Hope that I understood your requirements.
You can not automatically inject, when you have (2) of the same kind. In this case ValidationService.
You could inject #ValidationServiceA, or #ValidationServiceB, or a List<ValidationServiceI> and then return the one you want based on a <T> type you care about:
The solution below highlights that.
The method getGenericParameter() is used to return the <T> parameter. This is to avoid the use of Reflection.
The method methodWhichDeterminesWhichServiceToUseBasedOnResponseType to used to determine which ValidationService to use based on the input that you require.
You can find the complete solution below, including a verification Test.
import org.springframework.stereotype.Service;
#Service
public class ValidationServiceA implements ValidationServiceI<ResponseA>{
#Override public Class<ResponseA> getGenericParameter() {
return ResponseA.class;
}
public void print(){
System.out.println("Service A");
}
}
#Service
public class ValidationServiceB implements ValidationServiceI<ResponseB>{
#Override public Class<ResponseB> getGenericParameter() {
return ResponseB.class;
}
public void print(){
System.out.println("Service B");
}
}
public interface ValidationServiceI<T>{
Class<T> getGenericParameter();
void print();
}
#Service
public class ServiceWhichCallsOthers {
#Autowired
private List<ValidationServiceI> validationServices;
public <T> ValidationServiceI<T> methodWhichDeterminesWhichServiceToUseBasedOnResponseType(T responseType){
Optional<ValidationServiceI> validationServiceSupportingResponse = validationServices.stream().filter(validationServiceI -> validationServiceI.getGenericParameter().equals(responseType)).findFirst();
return validationServiceSupportingResponse.get();
}
public void callValidationServiceA(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).print();
}
public void callValidationServiceB(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).print();
}
}
#SpringBootTest
public class ServiceWhichCallsOthersIT {
#Autowired
private ServiceWhichCallsOthers serviceWhichCallsOthers;
#Test
public void validateBasedOnResponseType(){
Assertions.assertEquals(ValidationServiceA.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).getClass());
Assertions.assertEquals(ValidationServiceB.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).getClass());
serviceWhichCallsOthers.callValidationServiceA();
serviceWhichCallsOthers.callValidationServiceB();
}
}

The service variable is not read in a method running in another thread

The Spring application In the service spins an endless cycle
#Service
public class MyService {
public boolean isStart = false;
#Async("threadPoolTaskExecutor")
public void sending() {
while (isStartService) {
...
}
}
}
#Service
public class OneService {
#Autowired
private final MyService myService;
public void start(boolean isStautus) {
myService.isStart = true;
myService.sending();
}
}
In another service, I set the value of the variable is Start Service = true. While there was no Async annotation on this method, everything worked. But as soon as it was added, and it began to run in a separate thread, the isStartService variable inside this method is now always = false. The loop is never executed. How do I correctly pass the value of this variable inside this stream. I.e. at first it should be true, and after some time its value is passed false and thus the method stops working.
I tried to make the isStart variable as volatile. It didn't help
The problem is that #Async triggers the creation of a proxy, so when you mutate the variable directly, the proxy doesn't intercept that call.
Create a setter for the isStart property and it'll work.
This application works as expected with the setter. You should make the field volatile so that it always fetches the updated value of the field.
#SpringBootApplication
#EnableAsync
public class SO72313483 {
public static void main(String[] args) {
SpringApplication.run(SO72313483.class, args);
}
private final static Logger logger = LoggerFactory.getLogger(SO72313483.class);
#Service
public static class MyService {
private volatile boolean isStartService = false;
#Async("taskExecutor")
public void sending() throws Exception {
while (isStartService) {
logger.info("Here");
Thread.sleep(5000);
}
}
public void setStartService(boolean startService) {
isStartService = startService;
}
}
#Service
public static class OneService {
#Autowired
private MyService myService;
public void start(boolean isStatus) throws Exception{
myService.setStartService(true);
myService.sending();
}
}
#Autowired
OneService oneService;
#Bean
ApplicationRunner runnerSO72313483() {
return args -> oneService.start(true);
}
}

Getting Bean instance as null using Strategy Design Pattern and #Autowired

Hi I am trying to use Strategy Design pattern. I am getting ReEncryptionOperation bean as null in my TestServiceImpl class.
this is my interface
public interface ReEncryptionOperation {
void performOperation (String name);
}
These are my implementation classes
public class Test1 implements ReEncryptionOperation {
#Override
public void performOperation(String name){
return ....;
}
}
public class Test2 implements ReEncryptionOperation {
#Override
public void performOperation(String name) {
return ....;
}
}
This is my configuration class where I am defining as a bean
#Configuration
#Slf4j
public class TestConfiguration
{
#Bean("reEncryptionOperation")
public ReEncryptionOperation getReEncryptionOperation () throws ReEncryptionException {
if (annotationSupport) {
return new Test1();
}
return new Test2();
}
}
this is my service class where i am trying to use ReEncryptionOperation using #Autowired. But I am getting null.
#Component
#Slf4j
public class TestServiceImpl
{
#Autowired
private ReEncryptionOperation reEncryptionOperation;
public ReEncryptionResponse submitJob (
final ReEncryptionRequest reEncryptionRequest) throws ReEncryptionException
{
reEncryptionOperation.performOperation(test);
}
}
Your configuration seems ok.
Check that TestConfiguration is located in a package scanned by spring.
To be sure your bean is created on runtime, place a breakpoint in the method getReEncryptionOperation

Spring bean scope for "one object per test method"

I have a test utility for with I need to have a fresh instance per test method (to prevent that state leaks between tests). So far, I was using the scope "prototype", but now I want to be able to wire the utility into another test utility, and the wired instances shall be the same per test.
This appears to be a standard problem, so I was wondering if there is a "test method" scope or something similar?
This is the structure of the test class and test utilities:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyTest {
#Autowired
private TestDriver driver;
#Autowired
private TestStateProvider state;
// ... state
// ... methods
}
#Component
#Scope("prototype") // not right because MyTest and TestStateProvider get separate instances
public class TestDriver {
// ...
}
#Component
public class TestStateProvider {
#Autowired
private TestDriver driver;
// ...
}
I'm aware that I could use #Scope("singleton") and #DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) but this refreshes more than I need – a new TestDriver instance for each test would be enough. Also, this approach is error-prone because all tests using the TestDriver would need to know that they also need the #DirtiesContext annotation. So I'm looking for a better solution.
It is actually pretty easy to implement a testMethod scope:
public class TestMethodScope implements Scope {
public static final String NAME = "testMethod";
private Map<String, Object> scopedObjects = new HashMap<>();
private Map<String, Runnable> destructionCallbacks = new HashMap<>();
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name)) {
scopedObjects.put(name, objectFactory.getObject());
}
return scopedObjects.get(name);
}
#Override
public void registerDestructionCallback(String name, Runnable callback) {
destructionCallbacks.put(name, callback);
}
#Override
public Object remove(String name) {
throw new UnsupportedOperationException();
}
#Override
public String getConversationId() {
return null;
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
public static class TestExecutionListener implements org.springframework.test.context.TestExecutionListener {
#Override
public void afterTestMethod(TestContext testContext) throws Exception {
ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) testContext
.getApplicationContext();
TestMethodScope scope = (TestMethodScope) applicationContext.getBeanFactory().getRegisteredScope(NAME);
scope.destructionCallbacks.values().forEach(callback -> callback.run());
scope.destructionCallbacks.clear();
scope.scopedObjects.clear();
}
}
#Component
public static class ScopeRegistration implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
factory.registerScope(NAME, new TestMethodScope());
}
}
}
Just register the test execution listener, and there will be one instance per test of all #Scope("testMethod") annotated types:
#RunWith(SpringRunner.class)
#SpringBootTest
#TestExecutionListeners(listeners = TestMethodScope.TestExecutionListener.class,
mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
public class MyTest {
#Autowired
// ... types annotated with #Scope("testMethod")
}
I ran into the same problem some time ago and came to this solution:
Use Mocks
I wrote some methods to create specific mockito settings to add behavior to each mock.
So create a TestConfiguration class with following methods and bean definition.
private MockSettings createResetAfterMockSettings() {
return MockReset.withSettings(MockReset.AFTER);
}
private <T> T mockClass(Class<T> classToMock) {
return mock(classToMock, createResetAfterMockSettings());
}
and your bean definition will look like:
#Bean
public TestDriver testDriver() {
return mockClass(TestDriver .class);
}
MockReset.AFTER is used to reset the mock after the test method is run.
And finally add a TestExecutionListeners to your Test class:
#TestExecutionListeners({ResetMocksTestExecutionListener.class})

Third party library method call not trigger calling respect AOP method

I make my telegram bot using java library TelegramBots, Spring Boot and AspectJ in my application.
I have next class that extend third party library class TelegramLongPollingBot with class TelegramBotPolling.
#Component
public class TelegramBotPolling extends TelegramLongPollingBot {
static {
ApiContextInitializer.init();
}
#PostConstruct
public void registerBot(){
TelegramBotsApi telegramBotsApi = new TelegramBotsApi();
try {
telegramBotsApi.registerBot(this);
} catch (TelegramApiException e) {
logger.error(e);
}
}
#Override
public void onUpdateReceived(Update update) {
...
}
}
This libraries class has abstract method onUpdateReceived that I implement in my class TelegramBotPolling.
I want to keep track when method onUpdateReceived is called and will log this method using Spring AOP:
#Aspect
#Component
public class TelegramBotPollingLogger {
#Around("execution(* ru.cheb.intercity.bus.telegrambot.TelegramBotPolling.onUpdateReceived(..))")
public Object onUpdateReceivedMethodLogger(ProceedingJoinPoint joinPoint)
{
Object returnVal = commonLogHandler.handle(joinPoint);
return returnVal;
}
}
But AOP method onUpdateReceivedMethodLogger doesn't called when onUpdateReceived is called. I think I have a problem because onUpdateReceived relate with third party library. Because my own class methods work well with AOP.
How can I call AOP method onUpdateReceivedMethodLogger when method onUpdateReceivedis called ?
============================================
Trying to inject TelegramBotPolling class in other class:
#Component
public class TelegramBotPolling extends TelegramLongPollingBot implements TelegramBotUpdater{
static {
ApiContextInitializer.init();
}
#Override
public String getBotToken() {...}
#Override
public String getBotUsername() {...}
#Override
public void onUpdateReceived(Update update) {
...
}
}
I define interface TelegramBotUpdater for TelegramBotPolling
public interface TelegramBotUpdater {
String getBotToken();
String getBotUsername();
void onUpdateReceived(Update update);
}
Other class that inject this interface TelegramBotUpdater:
#Component
public class BotRegistrator {
#Autowired
TelegramBotUpdater telegramBotUpdater;
public void register(){
TelegramBotsApi telegramBotsApi = new TelegramBotsApi();
try {
telegramBotsApi.registerBot((TelegramBotPolling)telegramBotUpdater);
} catch (TelegramApiException e) {
logger.error(e);
}
}
}
And Application class that start spring boot application inject other class:
#SpringBootApplication
public class Application {
#Autowired
BotRegistrator botRegistrator;
public static void main(String[] args) throws Throwable {
SpringApplication.run(Application.class, args);
botRegistrator.register();
}
}
When calling botRegistrator.register(); I get NPE exception.

Categories

Resources