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);
}
Related
I need to test if a lambda function is called n-times from a service instance.
I have a Service class, that interact with the repository, when an error occur on retriving data from repository the service should retry until a max number of retries is reached so I have implemented as follow:
interface Repository {
Collection<String> getData();
}
public class RetryHelper<T> {
private Integer retries;
public RetryHelper(Integer retries) {
this.retries = retries;
}
public interface Operation<T> {
T doIt() throws Exception;
}
public T doWithRetry(Operation<T> operation) throws Exception {
int remainRetries = retries;
do {
try {
return operation.doIt();
} catch (Exception e) {
if (remainRetries == 0) {
throw e;
}
//TODO: wait before retry
remainRetries--;
}
} while (true);
}
}
class Service {
#Inject
Repository repo;
private final RetryHelper<Collection<String>> retryHelper;
public Collection<String> callService() {
try {
Collection<String> res = retryHelper.doWithRetry(() ->
repo.getData());
return res;
} catch (Exception e) {
throw (CustomException) e;
}
}
}
I need to test using Mockito that repo.getData() is called n-times when error occurs. I can change the Service code and the RetryHelper, so I am open to suggestions.
I have try to implment the test following tutorials and documentations:
public class ServiceTest {
#Inject
Service service;
#InjectMock
Repository repository;
#InjectMock
RetryHelper<Collection<String>> retryHelper;
#Captor
ArgumentCaptor<RetryHelper.Operation<Collection<String>>> operation;
#BeforeEach
void init_mocks() {
MockitoAnnotations.openMocks(this);
}
#Test
void shouldRetryIfDataQueryFailsForNonFatalError() throws Exception {
when(repository.getData())
.thenThrow(new RuntimeException("Runtime Exception"));
service.callService();
verify(retryHelper).doWithRetry(operation.capture());
verify(repository, times(2)).getData();
}
}
The test fail with message that getData() is never called.
I have finally found the solution without using Captor
public class ServiceTest {
#Inject
Service service;
#InjectMock
Repository repository;
#Inject
RetryHelper<Collection<String>> retryHelper;
#Test
void shouldRetryIfDataQueryFailsForNonFatalError() throws Exception {
when(repository.getData())
.thenThrow(new RuntimeException("Runtime Exception"));
try {
service.callService();
} catch(Exception e) {
verify(repository, times(2)).getData();
}
}
}
I want to test the getCitation() method using jUnit:
#Singleton
public class QuotesLoaderBean {
Properties quotes;
Properties names;
#PostConstruct
public void init() {
InputStream quotesInput = this.getClass().getClassLoader().getResourceAsStream("quotes.properties");
InputStream namesInput = this.getClass().getClassLoader().getResourceAsStream("names.properties");
quotes = new Properties();
names = new Properties();
try {
quotes.load(quotesInput);
names.load(namesInput);
} catch (IOException ex) {
Logger.getLogger(QuotesLoaderBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
public Citation createCitation(String quote) {
Citation citation = new Citation();
citation.setQuote(quote);
citation.setWho(getName());
return citation;
}
public Citation getCitation() {
Citation citation = new Citation();
citation.setQuote(getQuote());
citation.setWho(getName());
return citation;
}
In the Test File I want to Inject the Singleton and use it in the test method. But then I get the NullPointerException:
public class QuoteServiceTest {
#Inject
QuotesLoaderBean quotesLoaderBean;
public QuoteServiceTest() {
}
#BeforeClass
public static void setUpClass() {
}
#AfterClass
public static void tearDownClass() {
}
#Before
public void setUp() {
}
#After
public void tearDown() {
}
#Test
public void whenGetQuote_thenQuoteShouldBeReturned() {
quotesLoaderBean.getQuote();
}
}
The test method is not finished, nut I just want to show the exception that occurs when I call a method from the Singleton. In another service class i can easily inject the class and call the methods.
Injection is handled by a DI-enabled container in execution time.
When you deploy your entire application, a container is set and injection works fine.
When executing unit tests, none of the services are launched, and any #Inject will end up with the variable set to null, because no container will be launched either.
So, in order to test your code, you may want to build the service inside setUp method:
public class QuotesServiceTest {
QuotesLoaderBean quotesLoaderBean;
// ...
#Before
public void setUp() {
quotesLoaderBean = new QuotesLoaderBean();
// call init method after construction
quotesLoaderBean.init();
}
// ...
}
I have a Spring/Swing application in which I'm experimenting DI but whatever I've done so far, I couldn't make it work properly. Here are some example classes I work on;
public class Launcher {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
ApplicationContext context = null;
try {
context = new AnnotationConfigApplicationContext(AppConfig.class);
MainFrame mainFrame = (MainFrame) context.getBean("mainFrame");
mainFrame.init();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (context != null)
((ConfigurableApplicationContext) context).close();
}
}
});
}
}
#Configuration
#ComponentScan("tr.com.example.*")
public class AppConfig {
#Bean(name = "mainFrame")
public MainFrame createMainFrame() {
return new MainFrame();
}
}
public class MyPanel{
#Autowired
MyManager manager;
...do stuff
}
#Service
public class MyManager{
...do stuff
}
So, when I try to inject MyManager to MyPanel, I'm getting NullPointerException. But if I try to inject it to MainFrame it works.
Can someone please explain me what's wrong here and how should I make it correctly?
Thanks in advance.
Your MyPanel is not a #Component, therefore it's invisible to Spring and any #Autowired or other annotations won't be processed.
The key to Spring is to use it fully. Unless you know that something shouldn't be a bean (i.e. a domain class, entity or so on) it probably should be a bean.
It is not working beacuse you have not use #Component over MyPanel
public class Launcher {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
ApplicationContext context = null;
try {
context = new AnnotationConfigApplicationContext(AppConfig.class);
MainFrame mainFrame = (MainFrame) context.getBean("mainFrame");
mainFrame.init();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (context != null)
((ConfigurableApplicationContext) context).close();
}
}
});
}
}
#Configuration
#ComponentScan("tr.com.example.*")
public class AppConfig {
#Bean(name = "mainFrame")
public MainFrame createMainFrame() {
return new MainFrame();
}
}
#Component
public class MyPanel{
#Autowired
MyManager manager;
...do stuff
}
#Service
public class MyManager{
...do stuff
}
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.
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();
}
}
}
}