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.
Related
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.
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
I make my telegram bot using java library TelegramBots and also use SpringBoot in my application.
When in class TelegramBotPolling there is called method onUpdateReceived than the field busStationBtnsGenerator is null.
How corectly autowire field busStationBtnsGenerator in order it will be not null when onUpdateReceived method is called ?
This is brief example of my code:
#Component
public class TelegramBotPolling extends TelegramLongPollingBot {
#Autowired
BusStationBtnsGenerator busStationBtnsGenerator;
static {
ApiContextInitializer.init();
}
#PostConstruct
public void registerBot(){
TelegramBotsApi telegramBotsApi = new TelegramBotsApi();
try {
telegramBotsApi.registerBot(new TelegramBotPolling());
} catch (TelegramApiException e) {
logger.error(e);
}
}
#Override
public void onUpdateReceived(Update update) {
// When this method is called field "busStationBtnsGenerator" is null.
}
}
#Component
public class BusStationBtnsGeneratorImpl implements BusStationBtnsGenerator {
#Autowired
BusStationsParser stationsParser;
#Autowired
UrlHelper urlHelper;
#Override
public InlineKeyboardMarkup getKeyboardMarkupForBusStations()
throws Exception
{
......
}
private List<List<InlineKeyboardButton>> getBusStationButtons()
throws Exception
{
.....
}
}
Instance of class created with constructor new is not managed by Spring. For referring it you should you this keyword in this case.
#PostConstruct
public void registerBot(){
TelegramBotsApi telegramBotsApi = new TelegramBotsApi();
try {
telegramBotsApi.registerBot(this);
} catch (TelegramApiException e) {
logger.error(e);
}
I have the following classes:
public FooDAO extends AbstractDAO<Foo> { // Dropwizard DAO
#Inject FooDAO(SessionFactory sf) { super(sf); }
public void foo() { /* use SessionFactory */ }
}
public class FooService {
private final FooDAO fooDAO; // Constructor-injected dependency
#Inject FooService (FooDAO fooDAO) { this.fooDAO = fooDAO; }
#UnitOfWork
public void foo() {
this.fooDAO.foo();
System.out.println("I went through FooService.foo()");
}
}
Now, FooService is not a resource, so Dropwizard doesn't know about it and doesn't automagically proxy it. However the smart guys at Dropwizard made it so I can get a proxy through UnitOfWorkAwareProxyFactory.
I tried doing feeding these proxies to Guice with an interceptor, but I faced an issue because UnitOfWorkAwareProxyFactory only ever creates new instances and never lets me pass existing objects. The thing with new instances is that I don't know the parameters to give it since they're injected by Guice.
How do I create #UnitOfWork-aware proxies of existing objects?
Here's the interceptor I've made so far:
public class UnitOfWorkModule extends AbstractModule {
#Override protected void configure() {
UnitOfWorkInterceptor interceptor = new UnitOfWorkInterceptor();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(UnitOfWork.class), interceptor);
requestInjection(interceptor);
}
private static class UnitOfWorkInterceptor implements MethodInterceptor {
#Inject UnitOfWorkAwareProxyFactory proxyFactory;
Map<Object, Object> proxies = new IdentityHashMap<>();
#Override public Object invoke(MethodInvocation mi) throws Throwable {
Object target = proxies.computeIfAbsent(mi.getThis(), x -> createProxy(mi));
Method method = mi.getMethod();
Object[] arguments = mi.getArguments();
return method.invoke(target, arguments);
}
Object createProxy(MethodInvocation mi) {
// here, what to do? proxyFactory will only provide objects where I pass constructor arguments, but... I don't have those!
}
}
}
Of course, if Dropwizard (or Guice) offers me a simpler way to do so, which is it?
As from Dropwizard 1.1: (not yet released, as of August 10, 2016)
public class UnitOfWorkModule extends AbstractModule {
#Override
protected void configure() {
UnitOfWorkInterceptor interceptor = new UnitOfWorkInterceptor();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(UnitOfWork.class), interceptor);
requestInjection(interceptor);
}
#Provides
#Singleton
UnitOfWorkAwareProxyFactory provideUnitOfWorkAwareProxyFactory(HibernateBundle<AlexandriaConfiguration> hibernateBundle) {
return new UnitOfWorkAwareProxyFactory(hibernateBundle);
}
private static class UnitOfWorkInterceptor implements MethodInterceptor {
#Inject
UnitOfWorkAwareProxyFactory proxyFactory;
#Override
public Object invoke(MethodInvocation mi) throws Throwable {
UnitOfWorkAspect aspect = proxyFactory.newAspect();
try {
aspect.beforeStart(mi.getMethod().getAnnotation(UnitOfWork.class));
Object result = mi.proceed();
aspect.afterEnd();
return result;
} catch (InvocationTargetException e) {
aspect.onError();
throw e.getCause();
} catch (Exception e) {
aspect.onError();
throw e;
} finally {
aspect.onFinish();
}
}
}
}
public class ProjectIdInitializer {
public static void setProjectId(String projectId) {
//load spring context which i want to escape in my test
}
}
public class MyService {
public Response create(){
...
ProjectIdInitializer.setProjectId("Test");
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest({ProjectIdInitializer.class})
public class MyServiceTest{
#InjectMocks
private MyService myServiceMock ;
public void testCreate() {
PowerMockito.mockStatic(ProjectIdInitializer.class);
PowerMockito.doNothing().when(ProjectIdInitializer.class, "setProjectId", Mockito.any(String.class));
// Does not work,still tries to load spring context
Response response=myServiceMock .create();
}
How can i make sure that nothing happens if ProjectIdInitializer.setProjectId() is called from myservice?
As stated in comments, you should be aware that many things might break because of PowerMock.
You need to use PowerMock runner, something like that:
#RunWith(PowerMockRunner.class)
#PrepareForTest(ProjectIdInitializer.class)
public class MyServiceTest{
private MyService myService = new MyService();
public void testCreate()
{
PowerMockito.mockStatic(ProjectIdInitializer.class);
PowerMockito.doNothing().when(ProjectIdInitializer.class, "setProjectId", Mockito.any(String.class));
Response response=myService.create();
}
}
see also this doc.
This self contained sample:
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.ProjectIdInitializer.class)
public class A {
private MyService myService = new MyService();
#Test
public void testCreate() throws Exception {
PowerMockito.mockStatic(ProjectIdInitializer.class);
PowerMockito.doNothing().when(ProjectIdInitializer.class, "setProjectId", Mockito.any(String.class));
System.out.println("Before");
Response response = myService.create();
System.out.println("After");
}
public static class ProjectIdInitializer {
public static void setProjectId(String projectId) {
//load spring context which i want to escape in my test
System.out.println(">>>>>> Game over");
}
}
public static class Response {
}
public static class MyService {
public Response create() {
// ...
ProjectIdInitializer.setProjectId("Test");
return null;
}
}
}
outputs:
Before
After
As expected