poniedziałek, 5 stycznia 2015

Genymotion - problem finding VirtualBox

So I had this strange bug with Genymotion (nice Android emulator). It uses VirtualBox as emulator base and needs it installed in the system. I had VirtualBox installed but Genymotion was yelling all the time that it cannot find it....somehow I have found that it was looking in wrong directory. I couldn't find any config file (sic!) and almost gave up...but then..I found this small binary inside Genymotion directory! It's called reg.exe. If you start it you will get path to VirtualBox installation...dunno how it gets it but in my situation it was wroooong.So I created this nasty evil workaround:

#include <stdio.h>

int main() {
     // that was proper path for me
     printf("C:\\Program Files\\Oracle\\VirtualBox\\");     
}


I compiled it, created backup of the old reg.exe, copied new one...and enjoyed working emulator :)

poniedziałek, 29 grudnia 2014

Hibernate annotations: many-to-one with custom column

Sometimes you need to create many to one relation that doesn't use primary key. For example:


|Foo|            |Bar|            
 ---------        -----------
|id (PK)  |      |id (PK)    |
 ---------        -----------
|bar_id   |----->|bar_id (UQ)|
 ---------        -----------
                 |bar_name   |
here Foo references Bar by bar_id not id (id is more like a record's id not Bar's id)...What you need to do is annotate attribute like that (this is Foo class):

    @ManyToOne
    @JoinColumn(name="bar_id", referencedColumnName = "bar_id", nullable = false)
    private Bar bar;


If you want to have access to list of Foos from Bar you make something like this:

    @OneToMany
    @JoinColumn(name="bar_id", referencedColumnName = "bar_id")
    private Set<Foo> foos = new HashSet<>();


One more thing...if you have

<property name="hibernate.hbm2ddl.auto">create</property>


or "create-drop" you will probably get an error and there will be no foreign key added to table Foo. What you need to do is stop app change that prop:

<property name="hibernate.hbm2ddl.auto">update</property>


and start app again. This time there should be foreign key added to table. That's probably some sort of Hibernate bug.

TDD with Spring3 + Hibernate + Transactions

I found many people, including myself, struggling with creating test environment for web apps using Spring, Hibernate and Transactions. Sometimes there's a need to test your services in action without mock objects and so on. So how do you do that?

Here's main configuration class:

import java.util.Properties;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
 *
 * @author MarcinG
 */
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = {})
public class DataTestConfig {

    
    @Bean
    public SessionFactory sessionFactory() {
        LocalSessionFactoryBuilder builder
                = new LocalSessionFactoryBuilder(dataSource());

        builder.configure("hibernate-test.cfg.xml");

        return builder.buildSessionFactory();
    }

    private Properties getHibernateProperties() {
        Properties prop = new Properties();
        prop.put("hibernate.format_sql", "true");
        prop.put("hibernate.show_sql", "true");
        prop.put("hibernate.hbm2ddl.auto", "create-drop");
        prop.put("hibernate.dialect",
                "org.hibernate.dialect.HSQLDialect");
        return prop;
    }

    @Bean(name = "dataSource")
    public DriverManagerDataSource dataSource() {

        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("org.hsqldb.jdbcDriver");
        ds.setUrl("jdbc:hsqldb:mem:test_db");
        ds.setUsername("sa");
        return ds;
    }

    @Bean
    public HibernateTransactionManager transactionManager() {
        return new HibernateTransactionManager(sessionFactory());
    }
} 
In my case I'm using Gradle, so I have file "hibernate-test.cfg.xml" inside Resources dir. It looks like that:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory>
  <property name="hibernate.connection.pool_size">10</property>
  <property name="hibernate.connection.autocommit">true</property>
  <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
  <property name="hibernate.hbm2ddl.auto">create-drop</property><!-- creates the tables from the entites automatically -->
  <property name="show_sql">true</property>
  <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
  <mapping resource="pl/com/marcing/test/hibernate/Test.hbm.xml"/>
 </session-factory>
</hibernate-configuration>

Now you create tests like this one:

/**
 *
 * @author Gensiub
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {DataTestConfig.class})
public class TestFieldInRaportService {
    @Autowired
    TestService testService;

    /* service tests */ 
}
That service has @Transactional annotation. It uses DAO and so on. Test env will have in memory database which will work like a normal one. You can test whether you can retrieve previously saved objects and so on (no need for normal database).

Cheers!