Spring Dependency Injection not working correctly - java

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
}

Related

NullPointerException when testing Singleton in Java EE

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();
}
// ...
}

#NotNull not running all the time with MethodValidationPostProcessor

I tried to use javax.validation.constraints.NotNull with org.springframework.validation.beanvalidation.MethodValidationPostProcessor.MethodValidationPostProcessor but does not run as expected inside the same class. Please, could you tell me why ?
MethodValidationConfig class:
#Configuration
#ComponentScan({ "com.mypackage" })
public class MethodValidationConfig {
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
ValidationUtils class:
#Component
#Validated
#Slf4j
public class ValidationUtils {
public void test1(#NotNull String[] test) {
if(test == null) {
log.error("Test is null!!!");
}
}
public void test2() {
test1(null);
}
}
TestApplication class:
#EnableAsync
#EnableTransactionManagement
#SpringBootApplication
#Slf4j
public class TestApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(TestApplication.class, args);
ValidationUtils validationUtils = context.getBean(ValidationUtils.class);
try {
validationUtils.test1(null);
} catch (Exception e) {
log.info("OK");
}
try {
validationUtils.test2();
} catch (Exception e) {
log.info("OK");
}
}
}
com.mypackage.TestApplication : OK
com.mypackage.validationUtils : Test is null!!
I assume the following happens: when you call test1(), the proxy intercepts, and does the validation. When you call test2(), it simply delegates the call to the real object, where there is no proxy involved. Similar problem: Spring AOP not working for method call inside another method

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.

Autowire not work in telegram app using Spring Boot

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);
}

how to auto-wire HibernateBundle with guice on dropwizard?

Im trying to configure hibernatebundle with guice/dropwizard and need help.
Im using hubspot / dropwizard-guice / 0.7.0 3rd party library in addition to dropwizard lib.
The code below obviously wont work and need help on figuring it out. How do I rewrite this so that hibernatebundle and ultimately, session factory, be auto injected to whatever bean that needs it.
MyApplication.java
public class MyApplication extends Application<MyAppConfiguration> {
private final HibernateBundle<MyAppConfiguration> hibernateBundle = new HibernateBundle<MyAppConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
#Override
public void initialize(Bootstrap<MyAppConfiguration> bootstrap) {
bootstrap.addBundle(hibernateBundle); // ???
bootstrap.addBundle(
GuiceBundle.<MyAppConfiguration>newBuilder()
.addModule(new MyAppModule())
.enableAutoConfig(getClass().getPackage().getName())
.setConfigClass(MyAppConfiguration.class)
.build()
);
}
}
MyAppModule.java
public class MyAppModule extends AbstractModule {
#Provides
public SessionFactory provideSessionFactory(MyAppConfiguration configuration) {
// really wrong as it creates new instance everytime.
return configuration.getHibernateBundle().getSessionFactory(); // ???
}
}
MyAppConfiguration.java
public class MyAppConfiguration extends Configuration {
#Valid
#NotNull
private DataSourceFactory database = new DataSourceFactory();
#JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
#JsonProperty("database")
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
this.database = dataSourceFactory;
}
// ???
public HibernateBundle<MyAppConfiguration> getHibernateBundle() {
return new HibernateBundle<MyAppConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return database;
}
};
}
}
Here is how I end up doing. I never got an answer from here or mailing list so I would consider this hackish and probably not the proper way to do it but it works for me.
In my module (that extends abstractmodule) :
private final HibernateBundle<MyConfiguration> hibernateBundle =
new HibernateBundle<MyConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
#Provides
public SessionFactory provideSessionFactory(MyConfiguration configuration,
Environment environment) {
SessionFactory sf = hibernateBundle.getSessionFactory();
if (sf == null) {
try {
hibernateBundle.run(configuration, environment);
} catch (Exception e) {
logger.error("Unable to run hibernatebundle");
}
}
return hibernateBundle.getSessionFactory();
}
revised:
public SessionFactory provideSessionFactory(MyConfiguration configuration,
Environment environment) {
SessionFactory sf = hibernateBundle.getSessionFactory();
if (sf == null) {
try {
hibernateBundle.run(configuration, environment);
return hibernateBundle.getSessionFactory();
} catch (Exception e) {
logger.error("Unable to run hibernatebundle");
}
} else {
return sf;
}
}
I thought the explicit run(configuration, environment) call (in the answer provided by #StephenNYC) was a bit weird so a digged a little deeper. I found out that AutoConfig in dropwizard-guice wasn't setting up ConfiguredBundle's correctly (HibernateBundle is such a type).
As of https://github.com/HubSpot/dropwizard-guice/pull/35 the code can now look like this instead:
#Singleton
public class MyHibernateBundle extends HibernateBundle<NoxboxConfiguration> implements ConfiguredBundle<MyConfiguration>
{
public MyHibernateBundle()
{
super(myDbEntities(), new SessionFactoryFactory());
}
private static ImmutableList<Class<?>> myDbEntities()
{
Reflections reflections = new Reflections("com.acme");
ImmutableList<Class<?>> entities = ImmutableList.copyOf(reflections.getTypesAnnotatedWith(Entity.class));
return entities;
}
#Override
public DataSourceFactory getDataSourceFactory(NoxboxConfiguration configuration)
{
return configuration.getMyDb();
}
}
#Provides
public SessionFactory sessionFactory(MyHibernateBundle hibernate)
{
return checkNotNull(hibernate.getSessionFactory());
}
The magic behind this is that MyHibernateBundle implements ConfiguredBundle which dropwizard-guice now automatically picks up and instantiates.
Here is the way I solved it :
Put the Hibernate bundle in the guice module and pass the bootstap object as argument of guice module constructor so the hibernate bundle can be added to it.
The configuration can remain exactly as you would use a hibernate-bundle without guice.
I got this working with dropwizard-hibernate v0.7.1 and dropwizard-guice v0.7.0.3
MyAppModule.java :
public class MyAppModule extends AbstractModule {
private final HibernateBundle<MyAppConfiguration> hibernateBundle = new HibernateBundle<MyAppConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
public MyAppModule(Bootstrap<MyAppConfiguration> bootstrap) {
bootstrap.addBundle(hibernateBundle);
}
#Override
protected void configure() {
}
#Provides
public SessionFactory provideSessionFactory() {
return hibernateBundle.getSessionFactory();
}
}
MyApplication.java :
public class MyApplication extends Application<MyAppConfiguration> {
#Override
public void initialize(Bootstrap<MyAppConfiguration> bootstrap) {
bootstrap.addBundle(
GuiceBundle.<MyAppConfiguration>newBuilder()
.addModule(new MyAppModule(bootstrap))
.enableAutoConfig(getClass().getPackage().getName())
.setConfigClass(MyAppConfiguration.class)
.build()
);
}
#Override
public void run(final MyAppConfiguration configuration, final Environment environment) throws Exception {
}
}
MyAppConfiguration.java :
public class MyAppConfiguration extends Configuration {
#Valid
#NotNull
#JsonProperty("database")
private DataSourceFactory database = new DataSourceFactory();
public DataSourceFactory getDataSourceFactory() {
return database;
}
}
I have not used hibernate in dropwizard, but I have used Guice and you really only need to worry about MyAppModule. That's where the magic will happen:
public class MyAppModule extends AbstractModule {
#Singleton
#Provides
public SessionFactory provideSessionFactory(MyAppConfiguration configuration) {
HibernateBundle<MyAppConfiguration> hibernate = new HibernateBundle<ExampleConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
}
return hibernate.getSessionFactory();
}
}
(see here for multiple Classes)
MyAppConfiguration.java and MyApplication.java should not have any of the hibernate bundle references in. You should then be able to #Inject a SessionFactory where ever you need it.

Categories

Resources