yeaaaahhhh..hamf hamf
yeaaaahhhh..hamf hamf

Reputation: 788

Spring Data config and Postgres database integration (NO xml configuration)

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:

enter image description here

TECHNOLOGIES USED:

Initialization Configuration Files

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

Database Configuration Files

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

Entities and Repository

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

}

Questions

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".



UPDATE

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=true

datasource.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

Answers (2)

yeaaaahhhh..hamf hamf
yeaaaahhhh..hamf hamf

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

  1. add the scope as provided and then
  2. add the jar under the Tomcat's Library (..{tomcat7_home_path}/lib/postgres jar).

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

Tassos Bassoukos
Tassos Bassoukos

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

Related Questions