I'm getting an NPE when I'm trying to auto wiring a Repository in my managed bean. This is my first project trying to use java configurations instead of xml configurations.
I'm not instantiating my self the repository and all the packages are in the spring context, even I can see in the log the instantiating of the repository.
Please, someone, give me a hand to figure out what's missing in my configuration
Using spring version 5.1.0.RELEASE and
<dependency>
<groupId>com.googlecode.genericdao</groupId>
<artifactId>dao-hibernate</artifactId>
<version>1.2.0</version>
</dependency>
1) WebMvcConfig
#Configuration
#EnableWebMvc
#ComponentScan({
"com.config","com.gedificios",
})
public class WebMvcConfig implements WebMvcConfigurer {
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new
InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
2) PersistenceJPAConfig
#Configuration
#EnableTransactionManagement
#PropertySource({"classpath:database.properties"})
#ComponentScan({"com.config","com.gedificios.core", "com.gedificios.persistence", "com.gedificios.view"})
#EntityScan("com.gedificios.persistence.entities")
#EnableJpaRepositories(basePackages = "com.gedificios.core.repository")
public class PersistenceJPAConfig {
#Autowired
private Environment env;
public PersistenceJPAConfig() {
super();
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setPersistenceXmlLocation("classpath*:WEB-INF/persistence.xml");
entityManagerFactoryBean.setPersistenceUnitName("persistenceUnit");
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setJpaProperties(additionalProperties());
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform(env.getProperty("hibernate.dialect"));
vendorAdapter.setShowSql(Boolean.getBoolean(env.getProperty("hibernate.show_sql")));
vendorAdapter.setGenerateDdl(Boolean.getBoolean(env.getProperty("hibernate.generateDdl")));
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
return entityManagerFactoryBean;
}
final Properties additionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
return hibernateProperties;
}
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("hibernate.connection.driver_class"));
dataSource.setUrl(env.getProperty("hibernate.connection.url"));
dataSource.setUsername(env.getProperty("hibernate.connection.username"));
dataSource.setPassword(env.getProperty("hibernate.connection.password"));
return dataSource;
}
#Bean
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
#Primary
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
#Bean
public JPAAnnotationMetadataUtil getMetadataUtil() {
return new JPAAnnotationMetadataUtil();
}
#Bean
public JPASearchProcessor getJPASearchProcessor(JPAAnnotationMetadataUtil jpaAnnotationMetadataUtil) {
return new JPASearchProcessor(jpaAnnotationMetadataUtil);
}
}
3) Persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source/>
<class>com.gedificios.persistence.entities.Contrato</class>
<class>com.gedificios.persistence.entities.Edificio</class>
<class>com.gedificios.persistence.entities.ubigeo.Pais</class>
<class>com.gedificios.persistence.entities.ubigeo.Departamento</class>
<class>com.gedificios.persistence.entities.ubigeo.Provincia</class>
<class>com.gedificios.persistence.entities.ubigeo.Distrito</class>
<properties>
<property name="hibernate.dialect" value="${hibernate.dialect}"/>
<property name="hibernate.connection.charSet" value="UTF-8"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="validate"/>
<property name="hibernate.use_jdbc_metadata_defaults" value="false"/>
</properties>
</persistence-unit>
</persistence>
4) PaisRepository
#Repository
public class PaisRepository extends BaseDAO<PaisDTO, String> {
#Autowired
DataSource dataSource;
private static final Logger LOG = LoggerFactory.getLogger(PaisRepository.class);
#PostConstruct
public void init() {
LOG.info("\n/***************** INICIALIZANDO REPOSITORY DE PAÍS /*****************\n");
}
public List<PaisDTO> getAllPaises() {
List< PaisDTO> items = null;
StringBuffer sql = new StringBuffer();
sql.append(" SELECT ");
sql.append(" P.id_pais \"idPais\" , ");
sql.append(" P.nombre_pais \"nombrePais\" ");
sql.append(" FROM ubigeo_pais as P order by p.nombre_pais");
System.out.println(sql);
org.hibernate.Query<PaisDTO> query = em().unwrap(Session.class).createSQLQuery(sql.toString()).setResultTransformer(new JpaHbmBeanResultTransformer(PaisDTO.class));
items = query.list();
return items;
}
}
4.1) Log evidence
06:24:50.197 [localhost-startStop-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'getJPASearchProcessor'
06:24:50.198 [localhost-startStop-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'getMetadataUtil'
06:24:50.198 [localhost-startStop-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'getJPASearchProcessor' via factory method to bean named 'getMetadataUtil'
06:24:50.199 [localhost-startStop-1] INFO com.gedificios.core.repository.PaisRepository -
/***************** INICIALIZANDO REPOSITORY DE PAÍS /*****************
06:24:50.201 [localhost-startStop-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'DTOMapperServiceDozerImpl'
06:24:50.201 [localhost-startStop-1] DEBUG org.dozer.DozerInitializer - Tried to perform initialization when Dozer was already started.
06:24:50.201 [localhost-startStop-1] INFO org.dozer.DozerBeanMapper - Initializing a new instance of dozer bean mapper.
5) ManagedBean
#ManagedBean
#Scope("view")
#Component
public class AdminEdificios extends FindCrudBeanBase {
#Autowired
ApplicationContext applicationContext;
#Autowired
PaisRepository paisRepository;
private static final Logger LOG = LoggerFactory.getLogger(AdminEdificios.class);
private List<PaisDTO> listaPaises;
private List<DepartamentoDTO> listaDepartamentos;
private List<ProvinciaDTO> listaDistritos;
private List<DistritoDTO> listaProvincias;
private String codigoPaisSeleccionado;
private String codigoDepartamentoSeleccionado;
private String codigoProvinciaSeleccionada;
private String codigoDistritoSeleccionado;
#PostConstruct
public void init() {
listaPaises = paisRepository.findAll();
listaDepartamentos = new ArrayList<DepartamentoDTO>();
listaDepartamentos.add(new DepartamentoDTO("001","001","Lima"));
}
...
getters & setters
}
The NPE is exactly here
listaPaises = paisRepository.findAll();
Related
We have set up JPA second-level cache but not working with the following configuration cache is configured properly as per logging but it not cache the database result and always fetching data from the database.
11:44:07.454 [main] [UserId: ] WARN net.sf.ehcache.Cache - Cache: com.Record has a maxElementsInMemory of 0. In Ehcache 2.0 this has been changed to mean a store with no capacity limit. Set it to 1 if you want no elements cached in memory.
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true">
<defaultCache eternal="false" timeToLiveSeconds="10000" memoryStoreEvictionPolicy="LFU" statistics="true" maxElementsInMemory="10000" overflowToDisk="false" />
<cache maxElementsInMemory="10000" name="Record" eternal="false" timeToIdleSeconds="10000" timeToLiveSeconds="10000" memoryStoreEvictionPolicy="LFU" statistics="true" />
</ehcache>
Enabled spring boot Caching in Application.java
#SpringBootApplication
#EnableScheduling
#EnableCaching
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
#PostConstruct
public void init(){
// Setting Spring Boot SetTimeZone
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Entity Record.java
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "t_record")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "c_discriminator", discriminatorType = DiscriminatorType.STRING)
#Cacheable
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE,region = "Record")
#NamedQueries({#NamedQuery(name = Record.QUERY_findAllByType, query = "SELECT r FROM Record r WHERE TYPE(r) = ?1 ORDER BY r.date DESC, r.id DESC")})
public abstract class Record implements Cloneable, XmlOutputEntity {
/**
* Class UID
*/
private static final long serialVersionUID = 7146308281386143748L;
public static final String QUERY_findAllByType = "findAllRecordByType";
}
Enabled second-level cache and query cache in the database configuration.
#Configuration
public class DatabaseConfig {
protected PropConfig propConfig;
#Autowired
public DatabaseConfig(PropConfig propConfig) {
this.propConfig = propConfig;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(propConfig.getDatabaseDriver());
dataSource.setUrl(propConfig.getDatabaseUrl());
dataSource.setUsername(propConfig.getDatabaseUsername());
dataSource.setPassword(propConfig.getDatabasePassword());
return dataSource;
}
#Bean
public LocalValidatorFactoryBean validator() {
final LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
return validator;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("com.test");
Properties props = new Properties();
props.put("logging.level.org.hibernate.SQL", "true");
props.put("logging.level.org.hibernate.type.descriptor.sql.BasicBinder", "TRACE");
props.put("show-sql", "true");
lef.setJpaProperties(props);
lef.getJpaPropertyMap().put("jadira.usertype.autoRegisterUserTypes", "true");
lef.getJpaPropertyMap().put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
lef.getJpaPropertyMap().put("hibernate.temp.use_jdbc_metadata_defaults", "false");
lef.getJpaPropertyMap().put("hibernate.cache.use_second_level_cache", "true");
lef.getJpaPropertyMap().put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");
lef.getJpaPropertyMap().put("hibernate.cache.use_query_cache", "true");
lef.setSharedCacheMode(SharedCacheMode.ALL);
return lef;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(propConfig.isShowSql());
hibernateJpaVendorAdapter.setGenerateDdl(propConfig.isGenerateDdl());
hibernateJpaVendorAdapter.setDatabase(propConfig.getVendor());
return hibernateJpaVendorAdapter;
}
#Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager();
}
}
Query caching has to be enabled on a case by case basis by setting the org.hibernate.cacheable hint to true. I think with Spring Data JPA you have to annotate the repository method with #QueryHint(name = "org.hibernate.cacheable", value = "true")
I get ORA-00942: table or view does not exist at runtime when the code reaches this line : session.merge(role);
So how to show the query text executed during this merge ?
update :
here is how I configured the app :
#Configuration
#ComponentScan("com.ambre.pta")
#EnableTransactionManagement
#PropertySources({
#PropertySource("classpath:jdbc.properties"),
#PropertySource("classpath:fr/global.properties"),
#PropertySource("classpath:fr/main.properties"),
#PropertySource("classpath:fr/admin.properties"),
#PropertySource("classpath:fr/referentiel.properties"),
#PropertySource("classpath:fr/departement.properties"),
#PropertySource("classpath:fr/exercice.properties"),
#PropertySource("classpath:fr/defi.properties")
})
public class ApplicationContextConfig {
#Autowired
private Environment env;
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean(name = "viewResolver")
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean(name = "dataSource")
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:#"+env.getProperty("jdbc.server")+":"+env.getProperty("jdbc.port")+":"+env.getProperty("jdbc.instance"));
dataSource.setUsername(env.getProperty("jdbc.login.default"));
dataSource.setPassword(env.getProperty("jdbc.pwd.default"));
return dataSource;
}
#Autowired
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(DataSource dataSource) {
LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
sessionBuilder.scanPackages("com.ambre.pta.model");
return sessionBuilder.buildSessionFactory();
}
#Autowired
#Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory);
return transactionManager;
}
#Autowired
#Bean(name = "utilisateurDao")
public UtilisateurDAO getUtilisateurDao(SessionFactory sessionFactory) {
return new UtilisateurDAOImpl(sessionFactory);
}
#Autowired
#Bean(name = "menuDao")
public MenuDAO getMenuDao(SessionFactory sessionFactory) {
return new MenuDAOImpl(sessionFactory);
}
...
}
Please add the below tag to your hibernate config
<property name="show_sql">true</property>
look into
hibernate config file
application.yml file, there might be hibernate configuration and show-sql: true option.
I have created configuration using below code :
#Configuration
#EnableTransactionManagement
#ComponentScan("Name of package")
#EnableJpaRepositories("Name of package")
public class Config {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "Name of package";
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("Driver Name");
dataSource.setUrl("Url");
dataSource.setUsername("UserName");
dataSource.setPassword("Password");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setPackagesToScan(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN);
entityManagerFactoryBean.setJpaProperties(hibProperties());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return entityManagerFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, "org.hibernate.dialect.DB2Dialect");
properties.put("hibernate.default_schema","Schema Name");
return properties;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
}
There is an custom repository interface that implements JPARepository.
I have autowired the custom repository in controller and tried to call findAll().But the method returns 0 although there are 3 records in DB.
I am using spring web for rest service calls.
Entity class is created with #Entity and #Table annotations.It has an embedded key which is annotated using #EmbeddedId annotation.
#Repository
public interface EntityRepository extends JpaRepository<EntityTable, Long> {
#SuppressWarnings("unchecked") EntityTable save(EntityTable entityTable);
}
Entity table is the name of my table mapped with db table.
I'm trying to update a project made with spring and hibernate with springboot.
Everything seems ok, but I can't figure how to get the entityManager.
I'm not using spring data, so no domain nor repository is used.
In this project, services are annotated with #service and entityManager is autowire with: #PersistenceContext,
here an example of my service
#Service
#Transactional
public class UserServiceImpl implements UserDetailsService, UserService {
#PersistenceContext
EntityManager entityManager;
/**
*
*/
private static final long serialVersionUID = 6384460058124202695L;
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
User user = entityManager.find(User.class, username);
return user;
}
The problem here is that the entityManager is null. So I read in doc that if we want to manage the entityManager we have to configure it, so I did this in configuration file:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "services" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
The application is launching, but still have the entityManager null.
Any clue?
Edit: adding my application class (Has it's a demo project, I put all the config in one file)
#Configuration
#EnableAutoConfiguration
#ComponentScan
#EnableWebMvcSecurity
public class Application extends WebSecurityConfigurerAdapter{
#Value("${sec.cas.server}")
private String casServer;
#Value("${sec.app.server}")
private String appServer;
#Value("${spring.datasource.driverClassName}")
private String databaseDriverClassName;
#Value("${spring.datasource.url}")
private String databaseUrl;
#Value("${spring.datasource.username}")
private String databaseUsername;
#Value("${spring.datasource.password}")
private String databasePassword;
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
#Bean
public ComboPooledDataSource dataSource() {
ComboPooledDataSource datasource = new ComboPooledDataSource();
try {
datasource.setDriverClass(databaseDriverClassName);
} catch (PropertyVetoException e) {
throw new IllegalArgumentException("Wrong driver class");
}
datasource.setJdbcUrl(databaseUrl);
datasource.setUser(databaseUsername);
datasource.setPassword(databasePassword);
datasource.setAcquireIncrement(1);
datasource.setIdleConnectionTestPeriod(600);
datasource.setMaxPoolSize(500);
datasource.setMinPoolSize(50);
datasource.setMaxStatements(0);
datasource.setMaxConnectionAge(600);
datasource.setMaxIdleTime(600);
return datasource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
DefaultPersistenceUnitManager unitManager = new DefaultPersistenceUnitManager ();
unitManager.setDefaultDataSource(dataSource());
unitManager.setPersistenceXmlLocations("classpath*:META-INF/persistence.xml"); //location of your persistence.xml file
unitManager.setPackagesToScan(new String[] { "services" });
unitManager.setDefaultPersistenceUnitName("entityManager");
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitManager(unitManager);
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.show_sql", "false");
properties.setProperty("hibernate.format_sql", "true");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle9iDialect");
return properties;
}
#Bean
public JdbcDaoImpl jdbcUserService() {
JdbcDaoImpl jdbcDaoImpl = new JdbcDaoImpl();
jdbcDaoImpl.setEnableGroups(true);
jdbcDaoImpl.setEnableAuthorities(true);
jdbcDaoImpl.setDataSource(dataSource());
return jdbcDaoImpl;
}
#Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService("http://"+appServer+"/j_spring_cas_security_check");
serviceProperties.setSendRenew(false);
return serviceProperties;
}
#Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(authenticationUserDetailsService());
casAuthenticationProvider.setUserDetailsService(new UserServiceImpl());
//casAuthenticationProvider.setAuthenticationUserDetailsService(userServiceImpl.class);
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey("an_id_for_this_auth_provider_only");
return casAuthenticationProvider;
}
#Bean
public UserDetailsByNameServiceWrapper authenticationUserDetailsService() {
UserDetailsByNameServiceWrapper userDetailsByName = new UserDetailsByNameServiceWrapper();
userDetailsByName.setUserDetailsService(jdbcUserService());
return userDetailsByName;
}
#Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
Cas20ServiceTicketValidator casServiceTicketValidator = new Cas20ServiceTicketValidator("https://"+casServer+"/cas");
casServiceTicketValidator.setProxyCallbackUrl("http://"+appServer+"/");
casServiceTicketValidator.setProxyGrantingTicketStorage(new ProxyGrantingTicketStorageImpl());
return casServiceTicketValidator;
}
#Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setAuthenticationSuccessHandler(new SavedRequestAwareAuthenticationSuccessHandler());
casAuthenticationFilter.setProxyGrantingTicketStorage(new ProxyGrantingTicketStorageImpl());
casAuthenticationFilter.setProxyReceptorUrl("/secure/receptor");
return casAuthenticationFilter;
}
#Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl("https://"+casServer+"/cas/login");
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(casAuthenticationFilter());
http
.exceptionHandling()
.authenticationEntryPoint(casAuthenticationEntryPoint());
http
.authorizeRequests()
.antMatchers("/", "/home").authenticated()
.anyRequest().authenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(casAuthenticationProvider());
}
Your EntityManager being null indicates that Spring isn't processing #PersistenceContext annotations in your UserServiceImpl instance.
You're creating an instance of UserServiceImpl manually as part of configuring your CasAuthenticationProvider bean. That means that Spring knows nothing about the instance and will not inject any of its dependencies. You need to use a Spring-created instance, for example by making it an argument of the casAuthenticationProvider() method.
Try:
DefaultPersistenceUnitManager unitManager = new DefaultPersistenceUnitManager();
unitManager.setPersistenceXmlLocations("classpath*:META-INF/persistence.xml"); //location of your persistence.xml file.
unitManager.setDefaultDataSource(dataSource);
In persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="entityManager" transaction-type="RESOURCE_LOCAL">
//classes, etc...
</persistence-unit>
</persistence>
and:
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitManager(unitManager);
em.setPersistenceUnitName("entityManager");
And then injet:
#PersistenceContext(unitName = "entityManager")
private EntityManager entityManager;
That should work.
Solution by OP.
Got it finally worked, no entityManager is needed to be redefined, just add the bean who get the #persistenceContext (before spring boot 1.2.0)
Here is my application context:
#Configuration
#ComponentScan(basePackages={"services","model"})
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
#Bean
public PersistenceAnnotationBeanPostProcessor persistenceBeanPostProcessor() {
return new PersistenceAnnotationBeanPostProcessor();
}
I am trying to create a Spring MVC application leveraging JPA for its persistence layer. Unfortunately, I was getting a NullPointerException when accessing the EntityManager as Spring does not appear to be injecting it. My configuration is all annotation-based with #EnableWebMvc. After some searching, I added #Transactional on my DAO and #EnableTransactionManagement on my #Configuration class. Then I got an error about not having a DataSource. Supposedly, a class with #EnableTransactionManagement needs to implement TransactionManagementConfigurer. However, I am having problems figuring out how to create the DataSource as well as why it cannot get it from my persistence.xml.
I would greatly appreciate any help in trying to get the EntityManager injected into my DAO.
My #Configuration class
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan("com.example.myapp")
public class MvcConfig extends WebMvcConfigurerAdapter
implements TransactionManagementConfigurer {
private static final boolean CACHE_ENABLED = true;
private static final String TEMPLATE_PATH = "/WEB-INF/freemarker";
private static final String TEMPLATE_SUFFIX = ".ftl";
private static final Logger LOG = Logger.getLogger( MvcConfig.class );
#Override
public void addResourceHandlers( ResourceHandlerRegistry registry ) {
registry.addResourceHandler( "/stylesheets/**" ).addResourceLocations( "/stylesheets/" );
}
#Bean
public FreeMarkerConfigurer configureFreeMarker() {
final FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath( TEMPLATE_PATH );
return configurer;
}
#Bean
public ViewResolver configureViewResolver() {
final FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setCache( CACHE_ENABLED );
resolver.setSuffix( TEMPLATE_SUFFIX );
return resolver;
}
#Bean
#Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager();
}
}
My DAO
#Component
#Transactional
public class MyDAO {
private static final Logger LOG = Logger.getLogger( MyDAO.class );
#PersistenceContext
private EntityManager entityManager;
public MyClass getMyClass() {
LOG.debug( "getMyClass()" );
final CriteriaQuery<MyClass> query = criteriaBuilder.createQuery( MyClass.class );
// more code here, but it breaks by this point
return myData;
}
}
My Updated Code
I have reached the point in which it almost all works. The EntityManager is being injected properly. However, transactions are not working. I get errors if I try to use a RESOURCE_LOCAL approach so I am looking at JTA managed transactions. When I add #Transactional on any of my DAO methods, I get a "Transaction marked for rollback" error with no further details in any log files to assist troubleshooting. If I remove the annotation from a basic read-only select, the select will work perfectly fine (not sure if I should even be putting the annotation on select-only methods). However, I obviously need this working on methods which perform db writes. If I debug through the code, it seems to retrieve the data perfectly fine. However, as it returns from the method, the javax.transaction.RollbackException gets thrown. From my understanding of everything, it seems as if the exception occurs in the AOP post-method processing.
My #Configuration class
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan("com.example.myapp")
public class MvcConfig extends WebMvcConfigurerAdapter {
private static final boolean CACHE_ENABLED = true;
private static final String TEMPLATE_PATH = "/WEB-INF/freemarker";
private static final String TEMPLATE_SUFFIX = ".ftl";
private static final Logger LOG = Logger.getLogger( MvcConfig.class );
#Override
public void addResourceHandlers( ResourceHandlerRegistry registry ) {
registry.addResourceHandler( "/stylesheets/**" ).addResourceLocations( "/stylesheets/" );
}
#Bean
public FreeMarkerConfigurer configureFreeMarker() {
final FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath( TEMPLATE_PATH );
return configurer;
}
#Bean
public ViewResolver configureViewResolver() {
final FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setCache( CACHE_ENABLED );
resolver.setSuffix( TEMPLATE_SUFFIX );
return resolver;
}
#Bean
public PlatformTransactionManager transactionManager() {
return new JtaTransactionManager();
}
#Bean
public AbstractEntityManagerFactoryBean entityManagerFactoryBean() {
LocalEntityManagerFactoryBean factory = new LocalEntityManagerFactoryBean();
factory.setPersistenceUnitName( "my_db" );
return factory;
}
}
In my application I didn't implement TransactionManagerConfigurer interface. I use next code to configure JPA (with Hibernate implementation). You can do the same in your configuration class.
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean factoryBean =
new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(new String[] {"com.dimasco.springjpa.domain"});
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
//vendorAdapter.setGenerateDdl(generateDdl)
factoryBean.setJpaVendorAdapter(vendorAdapter);
Properties additionalProperties = new Properties();
additionalProperties.put("hibernate.hbm2ddl.auto", "update");
factoryBean.setJpaProperties(additionalProperties);
return factoryBean;
}
#Bean
public DataSource dataSource() {
final ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass(driverClass);
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
dataSource.setJdbcUrl(jdbcUrl);
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setMinPoolSize(3);
dataSource.setMaxPoolSize(15);
dataSource.setDebugUnreturnedConnectionStackTraces(true);
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
Hope this will help you)
EDIT:
You can get datasource using JNDI lookup:
#Bean
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
More details you can find in this article. There is example with JndiDatasourceConfig class.
EDIT 2:
I ahve persistence.xml in my project, but it is empty:
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="JPA_And_Spring_Test">
</persistence-unit>
</persistence>
And I didn't specify any persistent unit name in my java configuration.
The following might help, even though it uses XML-based configuration:
https://github.com/springinpractice/sip13/blob/master/helpdesk/src/main/resources/spring/beans-repo.xml
It uses Spring Data JPA, but you don't have to do that. Use
#PersistenceContext private EntityManager entityManager;
(But consider Spring Data JPA as it provides very capable DAOs out of the box.)
Side note: For DAOs, favor #Repository over #Component. Both work for component scanning, but #Repository better describes the intended use.