Reputation: 788
I have a project based on Spring Framework and it is initialized based only on Java configuration. This means that there is no need to use a web.xml file.
You can see the project's structure in the following image:
The "main" class is called AppInitializer and it resides under the initializer folder
AppInitializer
public class AppInitializer implements WebApplicationInitializer {
private static final String CONFIG_LOCATION = "com.project.app.config";
private static final String MAPPING_URL = "/";
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Create the 'root' Spring application context
WebApplicationContext context = getContext();
// Manage the lifecycle of the root application context
servletContext.addListener(new ContextLoaderListener(context));
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet",
new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping(MAPPING_URL);
}
private AnnotationConfigWebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation(CONFIG_LOCATION);
return context;
}
}
..while my configuration classes reside in the config folder
WebMvcConfig
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = { "com.project.app" })
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Autowired
private Environment env;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("hello");
}
@Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
}
At this point i want to add a postgres database in my project, therefore i created a folder named db in the CONFIG_LOCATION and in this way spring will "pick up" the @Configuration classes.( After creating a new db using PGAdmin ).. i created the following configuration class.
DataSources
@Component
@PropertySource("classpath:application.properties")
public class DataSources {
@Autowired
private Environment env;
@Bean
@Primary
public DataSource dataSource() {
org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource();
String url = env.getProperty(SystemSettings.DS_URL);
String user = env.getProperty(SystemSettings.DS_USERNAME);
String pass = env.getProperty(SystemSettings.DS_PASSWORD);
ds.setDriverClassName("org.postgresql.Driver");
ds.setUrl(url);
ds.setUsername(user);
ds.setPassword(pass);
return ds;
}
}
whereas SystemSettings holds the username,password and url of the Database
@Service
@Configuration
public class SystemSettings implements Settings {
public static final String DS_URL = "datasource.app.url";
public static final String DS_USERNAME = "datasource.app.username";
public static final String DS_PASSWORD = "datasource.app.password";
@Autowired
private Environment env;
@Override
public String get(String key) {
return env.getProperty(key);
}
}
The values are picked up from an application.properties file as its denoted in the DataSources class.
spring.jpa.database=POSTGRESQL
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
datasource.app.type=POSTGRESQL
datasource.app.url=jdbc:postgresql://localhost:5432/app
datasource.app.username=user datasource.app.password=pass
I proceed on adding an entity class that will represent a simple table in the project. It is located inside the services/entities folder
StopJPA
@Entity
@Table(name = "stop")
public class StopJPA {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "description")
private String stopDescription;
@Column(name = "idStop")
private String idStop;
public StopJPA() {
}
public StopJPA(String stopDescription, String idStop) {
this.stopDescription = stopDescription;
this.idStop = idStop;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getStopDescription() {
return stopDescription;
}
public void setStopDescription(String stopDescription) {
this.stopDescription = stopDescription;
}
public String getIdStop() {
return idStop;
}
public void setIdStop(String idStop) {
this.idStop = idStop;
}
}
Then i created a repository interface for this table that extends a CrudRepository.
StopRepository
/**
* Repository interface for StopJPA entities.
*/
@Repository
@RepositoryRestResource(collectionResourceRel = "stop", path = "stop")
public interface StopRepository extends CrudRepository<StopJPA, Long> {
StopJPA findById(@Param("id") Long id);
}
After all this setup and configuration i managed to get the project running but the table is not created in the database.
My MAIN INTENTION is to configure Spring (by using Spring Data JPA) and Hibernate in order to make them work together without the use of xml configuration files and without Spring BOOT dependencies. The latter means that the environment has to be configured "manually".
I added some more configuration in the DataSources class and renamed it in
PersistenceContext
@Component
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class PersistenceContext {
@Autowired
private Environment env;
@Bean
@Primary
public DataSource dataSource() throws ClassNotFoundException {
org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource();
String url = env.getProperty(SystemSettings.DS_URL);
String user = env.getProperty(SystemSettings.USERNAME);
String pass = env.getProperty(SystemSettings.DS_PASSWORD);
ds.setDriverClassName("org.postgresql.Driver");
ds.setUrl(url);
ds.setUsername(user);
ds.setPassword(pass);
return ds;
}
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan("com.project.app.services.entities");
Properties jpaProperties = new Properties();
// Configures the used database dialect. This allows Hibernate to create SQL
// that is optimized for the used database.
jpaProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
// Specifies the action that is invoked to the database when the Hibernate
// SessionFactory is created or closed.
jpaProperties.put("hibernate.hbm2ddl.auto",
env.getRequiredProperty("hibernate.hbm2ddl.auto"));
// If the value of this property is true, Hibernate writes all SQL
// statements to the console.
jpaProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
// If the value of this property is true, Hibernate will format the SQL
// that is written to the console.
jpaProperties.put("hibernate.format_sql", env.getRequiredProperty("hibernate.format_sql"));
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
/**
* Because we are using JPA, we have to create a transaction manager bean that integrates the
* JPA provider with the Spring transaction mechanism. We can do this by using the
* JpaTransactionManager class as the transaction manager of our application.
*
* We can configure the transaction manager bean by following these steps:
*
* -> Create a new JpaTransactionManager object. -> Configure the entity manager factory whose
* transactions are managed by the created JpaTransactionManager object.
**/
@Bean
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
Ans ALSO updated the properties file
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.hbm2ddl.auto=create-drop hibernate.show_sql=false
hibernate.format_sql=truedatasource.app.type=POSTGRESQL
datasource.app.driverClassName=org.postgresql.Driver
datasource.app.url=jdbc:postgresql://localhost:5432/app
datasource.app.username=user datasource.app.password=pass
Unfortunately now i get this error
SEVERE: Unable to create initial connections of pool. java.sql.SQLException: org.postgresql.Driver at ...... Caused by: java.lang.ClassNotFoundException: org.postgresql.Driver at......
I dont know why it gives me this exception. The maven dependency is there, the driver is also in classpath. . Any help?
Upvotes: 0
Views: 3445
Reputation: 788
Well, it was all about the Classpath.. I already had the dependency in my pom.xml but what i needed to do was to
Pom
<!-- Postgres -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1205-jdbc42</version>
<scope>provided</scope>
</dependency>
Why must the JDBC driver be put in TOMCAT_HOME/lib folder?
Upvotes: 0
Reputation: 16142
JPA does not specify DDL generation / migration. Hibernate by default does not do DDL generation / migration, but it's possible to do so if you configure your persistence.xml properly.
Upvotes: 1