I have a following class:
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
import javax.inject.Inject;
import com.mysite.Config;
#Startup
#Singleton
public class Scheduler {
#Resource
private TimerService timerService;
#Inject #Config
private Logger log;
#Inject #Config
private Integer delay;
#Inject #Config
private Integer interval;
#Inject #Config
private Boolean enabled;
#PostConstruct
public void initTimer() {
if (enabled) {
TimerConfig tc = new TimerConfig();
tc.setPersistent(false);
timerService.createIntervalTimer(delay, interval, tc);
}
}
#Timeout
public void timeout(Timer timer) {
// do something
}
}
package structure:
java
dataloaders (here are the problematic classes)
other packages
resources
META-INF, config, etc
While deploying to JBoss 7.1.1 the initTimer method of this class is always called twice, which then results in the timeout being called twice every time.
I already know from here and here that it's a bug in JBoss (which supposedly is fixed for 7.1.1 but apparently it isn't). My question then is - does anybody know of any workaround that I could use to stop doubled execution of the #PostConstruct methods (I have more classes like that, all of them have the same problem)?
I've seen more questions like this, but they're all connected either with some REST library or Spring and CDI initializing the bean two times - it's not the case here.
Any help appreciated, thanks.
It turns out it was a problem with app packaging, the second app was underneath and its' xml config was picked up again causing objects to be constructed twice. My bad, thanks to #hwellmann for the hint.
Related
A web application I've been working on recently the past like 2 weeks maybe for whatever reason when I finally tested it - won't seem to even enter the method that I have to return a JSON list of objects. I have included the Jackson library and Spring Boot Web, Tomcat, Data-JPA, Hibernate, MySQL, and a library to allow me to access JSP files. The index.jsp comes up but I almost feel like Spring Boot is giving me that free of charge as it's not even entering that method. I have been having the issue for a few days but trying to resolve it on my own - I found another answer that suggested to put a breakpoint inside one of the Spring classes but when I "debugged" it through Eclipse, it didn't even stop at that class - something about pattern matching - One answer suggested adding a context to the application.properties file - didn't help. I've reduced it to as simple as I think I can get it. Can anyone tell me what I might be doing wrong? Before my code, the project is on Github at: https://github.com/sfulmer/Scheduler.git
Here's my controller:
package net.draconia.schedule.controllers;
import java.util.List;
import net.draconia.schedule.beans.Event;
import net.draconia.schedule.dao.EventDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class ScheduleController
{
private static final Logger logger = LoggerFactory.getLogger(ScheduleController.class);
#Autowired
private EventDAO mObjDAO;
protected EventDAO getDAO()
{
return(mObjDAO);
}
//#GetMapping("/events")
#RequestMapping(value = "events", method = RequestMethod.GET)
public #ResponseBody List<Event> getEvents()
{
logger.debug("I got here");
return(getDAO().getList());
}
#GetMapping("/")
public String index()
{
return("index");
}
}
Here is the DAO interface - I'll show the class if necessary but this is what the controller looks at:
package net.draconia.schedule.dao;
import java.util.List;
import javax.persistence.EntityNotFoundException;
import net.draconia.schedule.beans.Event;
public interface EventDAO
{
public Event getEventById(final long lId) throws EntityNotFoundException;
public List<Event> getList();
public void remove(final Event objEvent);
public void removeById(final long lId);
public Event save(final Event objEvent);
}
The Event class is so long but if I need to include it, I will. The application.properties file is here:
spring.datasource.url = jdbc:mysql://localhost:3306/schedule
spring.datasource.username = root
spring.datasource.password = R3g1n# M1lL$ 1$ My Qu3eN!
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
server.servlet.contextPath=/scheduler
and here is my Application class(with the SpringBootApplication annotation):
package net.draconia.schedule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#SpringBootApplication(scanBasePackages = {"net.draconia.schedule.controller"})
public class ScheduleApp implements WebMvcConfigurer
{
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder)
{
return(builder.sources(ScheduleApp.class));
}
public static void main(String[] args)
{
SpringApplication.run(ScheduleApp.class, args);
}
}
I'm relatively new to Spring Boot but haven't ever ran into this problem ever before as I work with it at work and it works fine but we use entirely REST services there and I am using JSP files as well as sorta end-points that respond with JSON but you can't respond from REST services with JSP views so unfortunately I can't copy work's project to get that working or I would sigh Any thoughts on how I can get this working or what I am omitting?
My guess is that you're mixing things from Spring and Spring boot, and that's getting problems on loading beans, as you're probably changing the annotations load order or loading other beans rather than spring boot defaults as expected. For example, you implements WebMvcConfigurer, but you aren't providing any WebMvc Configuration, like a ViewResolver bean
My advice is to follow this guide: https://spring.io/guides/gs/spring-boot/
and use only the annotations from spring boot if using spring boot, or spring if using spring (they're similar, but not exactly the same, configuration is different).
Anyways, you can check loaded beans in Spring application context (Inject it in Application class) with ctx.getBeanDefinitionNames() method and see if your controller is there (i guess not).
By looking into code, my first impression is that, you have some typo in here:
#SpringBootApplication(scanBasePackages = {"net.draconia.schedule.controller"})
Your controller class package name has net.draconia.schedule.controllers.
So can you please correct your scanBasePackages with proper package name.
If that is not the case, please update full stack trace along with GET request which you are submitting into application. Will take a look & update answer accordingly.
So I've been learning Spring for a few weeks. I am trying to make a simple project involving a Controller -> Service -> Repository -> Database pattern.
I started having this problem, but could not find the solution to it. I stumbled upon some similar problems online with the same error, but none of them gave my solution, everything seems normal in my project.
This is the error on output:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field repository in com.Library.services.LibraryService required a bean named 'entityManagerFactory' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean named 'entityManagerFactory' in your configuration.
This are the files of my project (file tree):
This is my code:
Main class:
package com.Library;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
#EntityScan("com.Library.services")
#EnableJpaRepositories("com.Library.repositories")
public class LibraryApplication {
public static void main(String[] args) {
SpringApplication.run(LibraryApplication.class, args);
}
}
Model:
package com.Library.models.dtos;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
#Getter
#Setter
#Entity
public class BookCategory {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Id;
private String Name;
}
Repository:
package com.Library.repositories;
import com.Library.models.dtos.BookCategory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface BookCategoryRepository extends JpaRepository<BookCategory,Long> {
List<BookCategory> findAll();
}
Service:
package com.Library.services;
import com.Library.models.dtos.BookCategory;
import com.Library.repositories.BookCategoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class LibraryService {
#Autowired
BookCategoryRepository repository;
public List<BookCategory> getAllCategories() {
return repository.findAll();
}
}
Controller:
package com.Library.controllers;
import com.Library.models.dtos.BookCategory;
import com.Library.services.LibraryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#CrossOrigin(origins = "*", allowedHeaders = "*")
#RestController
public class LibraryController{
#Autowired
LibraryService libraryService;
public List<BookCategory> getAllCategories() {
return libraryService.getAllCategories();
}
}
What could be the issue?
This bean definition is usually provided automatically by Spring Boot Auto-Configuration. The spring reference manual explains how to diagnose such issues:
The Spring Boot auto-configuration tries its best to “do the right thing”, but sometimes things fail, and it can be hard to tell why.
There is a really useful ConditionEvaluationReport available in any Spring Boot ApplicationContext. You can see it if you enable DEBUG logging output. If you use the spring-boot-actuator (see the Actuator chapter), there is also a conditions endpoint that renders the report in JSON. Use that endpoint to debug the application and see what features have been added (and which have not been added) by Spring Boot at runtime.
Many more questions can be answered by looking at the source code and the Javadoc. When reading the code, remember the following rules of thumb:
Look for classes called *AutoConfiguration and read their sources. Pay special attention to the #Conditional* annotations to find out what features they enable and when. Add --debug to the command line or a System property -Ddebug to get a log on the console of all the auto-configuration decisions that were made in your app. In a running application with actuator enabled, look at the conditions endpoint (/actuator/conditions or the JMX equivalent) for the same information.
In your case, a simple full text search finds that Hibernate is auto-configured by org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, which is declared as follows:
#AutoConfiguration(after = { DataSourceAutoConfiguration.class })
#ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class, SessionImplementor.class })
#EnableConfigurationProperties(JpaProperties.class)
#Import(HibernateJpaConfiguration.class)
public class HibernateJpaAutoConfiguration {
}
As you can tell from the ConditionalOnClass annotation, this configuration is only applied if your classpath contains the classes LocalContainerEntityManagerFactoryBean from spring-orm-jpa, EntityManager from the JPA spec, and SessionImplementor from the hibernate jar.
Most likely, you are missing one of these JAR files (maven dependencies), or have the wrong version of one. The ConditionEvaluationReport should tell you which, and the precise package names to check for.
I have some strange behavior in my Spring App, here is my Java Spring Boot application structure:
in package com.somethingsomething.packageA, I have 2 files
First is ParentA.java
package com.somethingsomething.packageA;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class ParentA {
#Autowired
private ChildA childA;
public ChildA getChildA() {
return childA;
}
#PostConstruct
public void ParentAPostConstruct() {
System.out.println("ParentA PostConstruct were called");
}
}
Second is ChildA.java
package com.somethingsomething.packageA;
import org.springframework.stereotype.Component;
#Component
public class ChildA {
public ChildA() {
System.out.println("ChildA were called");
}
}
and then under package com.somethingsomething.packageB, I also have two similar files.
First is ParentB.java
package com.somethingsomething.packageB;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class ParentB {
#Autowired
private ChildB childB;
public ChildB getChildB() {
return childB;
}
#PostConstruct
public void ParentBPostConstruct() {
System.out.println("ParentB PostConstruct were called");
}
}
Second is ChildB.java
package com.somethingsomething.packageB;
import org.springframework.stereotype.Component;
#Component
public class ChildB {
public ChildB() {
System.out.println("ChildB were called");
}
}
Both of packageA and packageB have similar structure. Then under com.somethingsomething I have two main function for both package:
ForPackageA.java
package com.somethingsomething;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.somethingsomething.packageA.ParentA;
#SpringBootApplication
public class ForPackageA {
public static void main(String[] args) {
ApplicationContext applicationContext =
SpringApplication.run(ForPackageA.class, args);
ParentA parentA =
applicationContext.getBean(ParentA.class);
System.out.println(parentA);
System.out.println(parentA.getChildA());
}
}
and ForPackageB.java
package com.somethingsomething;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.somethingsomething.packageB.ParentB;
#SpringBootApplication
public class ForPackageB {
public static void main(String[] args) {
ApplicationContext applicationContext =
SpringApplication.run(ForPackageB.class, args);
ParentB parentB =
applicationContext.getBean(ParentB.class);
System.out.println(parentB);
System.out.println(parentB.getChildB());
}
}
When i run ForPackageA.java, this will appear in log:
ChildA were called
ParentA PostConstruct were called
ChildB were called
ParentB PostConstruct were called
com.somethingsomething.packageA.ParentA#88d6f9b
com.somethingsomething.packageA.ChildA#47d93e0d
The ChildB were called and ParentB PostConstruct were called were not suppose to be there, since ForPackageA.java doesn't depend on those beans. Why is this happening?
The same thing also happening when i run ForPackageB.java, which will log following:
ChildA were called
ParentA PostConstruct were called
ChildB were called
ParentB PostConstruct were called
com.somethingsomething.packageB.ParentB#610db97e
com.somethingsomething.packageB.ChildB#6f0628de
But in this case ChildA were called and ParentA PostConstruct were called were not suppose to be logged.
So, why is this peculiar behavior is happening? Is this default behavior of Spring?
Edit:
If let say i add following line
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) to ParentB.java
(after #Component)
It will not make ParentB PostConstruct were called appear when i run
ForPackageA.java.
and also, if i add those line to ChildB.java it will also not
make ChildB were called appear when i run ForPackageA.java
Why are the beans act differently in prototype mode, i.e. they are not getting called like when they are in singleton mode?
Yes, this is default behaviour of Spring. At application start all Beans with a #Component annotation get created, no matter if you use them or not.
The call applicationContext.getBean(ParentB.class) then simply returns the already created Bean.
To answer your edit:
Spring Beans are by default Singletons, so theres always only one instance of the bean per applicationContext. This is Inversion of Control, meaning that Spring handles object instantiation, not you.
Beans with the Prototype scope can have multiple object instances and can, in a way, be instantiated by you. (By calling applicationContext.getBean(ParentA.class)). This is similar to doing something like ParentA a = new ParentA().
I suggest you read this to get a deeper understanding of scopes.
The bean object creation doesn't depends on which object you are trying to get. Whenever spring application gets launched, its all components object are created automatically and you are getting already created component object using applicationContext.getBean(componentClass) method. Hope this will help you to understand why you are getting logs for every object.
Why is this happening?
When you start your Spring app the ApplicationContext is initialised by component scanning your application and registering all Spring annotated beans in the context. This allows them to be injected as required.
Is this default behaviour of Spring?
Yes. You can change this behaviour by configuring the component scanning to only look at specified packages if you wish (although the use cases for this are few and far between).
I am studying for the Spring Core certification and I have the followind doubt with an exercice related to the beans configuration using the Java configuration way.
So I have the following RewardsConfig class that configure my beans (this class is into the application folder src/main/java):
package config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import rewards.RewardNetwork;
import rewards.internal.RewardNetworkImpl;
import rewards.internal.account.AccountRepository;
import rewards.internal.account.JdbcAccountRepository;
import rewards.internal.restaurant.JdbcRestaurantRepository;
import rewards.internal.restaurant.RestaurantRepository;
import rewards.internal.reward.JdbcRewardRepository;
import rewards.internal.reward.RewardRepository;
#Configuration
public class RewardsConfig {
#Autowired
DataSource dataSource;
#Bean
public RewardNetwork rewardNetwork(){
return new RewardNetworkImpl(accountRepository(), restaurantRepository(), rewardRepository());
}
#Bean
public AccountRepository accountRepository(){
JdbcAccountRepository repository = new JdbcAccountRepository();
repository.setDataSource(dataSource);
return repository;
}
#Bean
public RestaurantRepository restaurantRepository(){
JdbcRestaurantRepository repository = new JdbcRestaurantRepository();
repository.setDataSource(dataSource);
return repository;
}
#Bean
public RewardRepository rewardRepository(){
JdbcRewardRepository repository = new JdbcRewardRepository();
repository.setDataSource(dataSource);
return repository;
}
}
As you can see I declare 4 methods that are used to create 4 beans and that specify the dependency that occurs among these beans.
So I have a RewardNetwork bean that is implemented by RewardNetworkImpl class that depends from the following 3 beans: AccountRepository, RestaurantRepository and RewardRepository.
Is it the correct interpretation of the Java configuration is Spring?
Can I say for example that RewardNetwork is the declared bean and that RewardNetworkImpl its the current implementation of this bean?
All the 3beans (AccountRepository, RestaurantRepository and RewardRepository) depends by another bean dataSource that, as you can see in the previous code snippet, is declared as #Autowired:
#Autowired
DataSource dataSource;
This bean is not declared in this configuration class because it changes according to the environment (test, developt, production).
So, in my case it is declared into the unit test folder src/test/java:
package rewards;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
#Configuration
public class TestInfrastructureConfig {
/**
* Creates an in-memory "rewards" database populated
* with test data for fast testing
*/
#Bean
public DataSource dataSource(){
return
(new EmbeddedDatabaseBuilder())
.addScript("classpath:rewards/testdb/schema.sql")
.addScript("classpath:rewards/testdb/test-data.sql")
.build();
}
}
So the dataSource bean define a datasource that is valid only for the test environment (used when I perform a unit test).
Now my doubt is: I have 2 different configuration classes and the dataSource bean is not definied into the RewardsConfig configuration class that contains the 3 beans that use it. Why I can't not use the #Import annotation to use it into RewardsConfig?
Something like it:
#Import(TestInfrastructureConfig.class)
How it work exactly?
Tnx
You don't have to import beans to make them available for autowiring. #Import is used to add extra configuration classes.
You really don't want to hard-import a test configuration class, because then your production code is referring to test-only code (and, in this case, always activating it). Instead, think of your configuration class more like an abstract class: declare autowired beans, but don't worry about how they get there. The downstream (runtime) configuration will supply them, and you don't need to know how. Maybe you're supplying an in-memory H2 for testing and using Spring Cloud Connectors for actual runs, doesn't matter.
in the JSF-2 application I'm working on, I need to start a server side Timer when a user does an action.
This timer must be related to the application itself, so it must survive when the user session is closed.
To solve this problem, I thought to use java.util.Timer class instantiating the timer object in an Application scoped bean.
Could it be a good solution? Are there other better ways to achive this? Thanks
No ejb-container
If your container doesnt have ejb capabilities (tomcat, jetty etc..), you can go with quartz scheduler library: http://quartz-scheduler.org/
They also has some nice code samples: http://quartz-scheduler.org/documentation/quartz-2.1.x/examples/Example1
EJB 3.1
If your app-server have a EJB 3.1 (glassfish, Jboss), there is a java ee standard way of creating timers. Mainly look into the #Schedule and #Timeout annotations.
Something like this might cover your usecase (method annotated #Timeout will be invoked when timer runs out)
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
#Stateless
public class TimerBean {
#Resource
protected TimerService timerService;
#Timeout
public void timeoutHandler(Timer timer) {
String name = timer.getInfo().toString();
System.out.println("Timer name=" + name);
}
public void startTimer(long initialExpiration, long interval, String name){
TimerConfig config = new TimerConfig();
config.setInfo(name);
config.setPersistent(false);
timerService.createIntervalTimer(initialExpiration, interval, config);
}
}