Search posterous

Search all posts and users. Type a name, type a favorite song title, whatever! See what comes up.
  

More posterous blogs











More recommended blogs »

Here are posterous posts filed under hibernate...

krzychukula says...


Książkę kupiłem jakiś rok temum gdy postanowiłem poznać bibliotekę Hibernate, tak szeroko stosowaną w świecie Javy. Skończyło się jednak na przeczytaniu o ile dobrze pamiętam niecałych dwóch rozdziałów. Z racji upływu czasu zatarło się wspomnienie dlaczego właściwie jej nie przeczytałem, ale problem pozostał: trzeba się w końcu tego Hibernate nauczyć, bym bardziej że używam go w praktyce często "na czuja"
, niby jakoś ile ale porcja konkretnej wiedzy na pewno nie zaszkodzi.

No to zacząłem czytać:
1 rozdział: Wprowadzenie w ORM'y. Ok, standard.
2 rozdział: Hello World! Próba odpalenia Eclipse i testowania kodu. Moment iluminacji, już wiem czemu poprzednio jej nie przeczytałem!

Książka mimo iż wydana początkowo przez Manning i należy do serii "* in Action" to jednak ta strona książki jest bardzo niedopracowana! Z tego co przeglądałem Amazon i Manning dostępne jest już drugie wydanie "Java Persistence with Hibernate" która to jest prawie dwukrotnie grubsza od pierwszego wydania, domyślam się że przykłady są już lepiej wytłumaczone.
W każdym bądź razie książka zawiera tylko krótkie fragmenty kodu, poszatkowane i w żadnym razie nie nadające się do uruchomienia!
Jeśli ktoś poszukuje bardziej praktycznego podejścia do Hibernate polecam: http://vaannila.com/ gdzie można poczytać także o Spring oraz Struts.
Generalnie polecam tą stronę każdemu kto nie miał jeszcze do czynienia z Hibernate a chciał by się go nauczyć. Nie dość że omawiana jest konfiguracja to omawiane są Adnotacje których nie ma w Hibernate w Akcji. Nie jest to wina jakiegoś zaniedbania, po prostu książka była wydana dla wersji Hibernate 2.1. Adnotacje nie były wtedy wspierane.
Zdałem sobie sprawę że próby uruchamiania kodu nic nie dają poza irytacją i to pozwoliło mi docenić inne zalety książki.
Można się z niej nauczyć bardzo wiele nie tylko o ORM ale i o podstawach tworzenia aplikacji i kilku dobrych praktykach programistycznych.
Jeśli ktoś woli czytać po polsku albo po prostu kupił już tą książkę(jak ja) to polecam ją przeczytać. Jednak dla osób które mają wybór polecam raczej coś co zawiera już opis użycia Adnotacji: choćby druga edycja o której już pisałem a przez wielu jest uważana za "Biblię Hibernate".

Ocena: 6/10

Osobiście zamierzam przeczytać drugie wydanie: "Java Persistence with Hibernate" http://www.manning.com/bauer2/ wersja PDF to koszt ~$35 dolarów więc nie tak znów dużo jak na książkę o 880 stronach nawet w Polskich księgarniach.

Filed under: Hibernate

trapo says...

Sometime ago I was fighting with Hibernate Validator, trying to implement an unique constraint and I could not figure out how to create one that requires database access:

The problem is that your validators can't access sessionFactory or any other interface to the database. I know that I can break some rules and instantiate a sessionFactory/session/connection directly inside the Validator, but I dislike to do wrong things consciously. So, I looking for alternatives.

Then, while studying the new validation support offered by Spring, I just discovery that using Spring I can inject any bean inside my ConstraintValidators. From Spring documentation:

By default, the LocalValidatorFactoryBean configures a SpringConstraintValidatorFactory that uses Spring to create ConstraintValidator instances. This allows your custom ConstraintValidators to benefit from dependency injection like any other Spring bean.

And here is how you can use that Spring feature to implement unique constraint.

THE UNIQUE ANNOTATION

It is very simple and direct. You can see details about implementing your custom annotations in Hibernate Validator docs.

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=UniqueConstraintValidator.class)
@Documented
public @interface Unique {
    String message() default "{constraints.unique}";
    Class<?> entity();
    String field();
    Class<?>[] groups() default {};   
    Class<? extends Payload>[] payload() default {};
}

You can also see the code at GitHub, where trapo is hosted. If I decide to change something, you can get an updated version there. Once you have the @Unique annotation, you must implement the ConstraintValidator referenced by "validationBy" property in @Constraint annotation above. Here is the code using a bean injected by Spring:

public class UniqueConstraintValidator implements ConstraintValidator<Unique, String> {

    @Autowired private SessionFactory sessionFactory;
   
    private Class<?> entity;
    private String field;
   
    public void initialize(Unique annotation) {
        this.entity = annotation.entity();
        this.field = annotation.field();
    }

    public boolean isValid(String value, ConstraintValidatorContext context) {
        if(StringUtils.isEmpty(value)) {
            return false;
        }
        return query(value).intValue() == 0;
    }

    private Number query(String value) {
        HibernateTemplate template = new HibernateTemplate(sessionFactory);
        DetachedCriteria criteria = forClass(entity)
                                   .add(eq(field, value))
                                   .setProjection(count(field));
        return (Number)template.findByCriteria(criteria).iterator().next();
    }

}

Just like the @Unique annotation, you can find the code in GitHub. Now you just need a Validator bean that can be injected in the classes that need it.

<bean id="validator"
      class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

Voilá!

THE UGLY PART

Right now, Hibernate Validor don't offer any way to know from where your annotations are coming. If you take some time to think about the ConstraintValidator above, you will notice that I manually configure the entity class and field information that were annotated. I need that information to know what query I must execute in order to validate the uniqueness of the field. Bad to me. Really bad. Now I have to provide this information by myself annotating the field like the code highlighted below:

    @NotEmpty @Unique(entity = Forum.class, field = "name")
    private String name;

I can even hear the DRY concept crying! I can't also find a way to reflect this to my schema. Maybe Hibernate Validator can offer some interfaces that we can use to implement all this stuff.

Filed under: hibernate

trapo says...

I want to keep Trapo environment as simple as possible. I want that people just fire a command and all tests can run immediately: no setups, no database creation, no sql to run. Just one single command and trapo should do everything for you. Because of that, I start to isolate the test environment from the production one in order to use a different database instance (or even a different database vendor). To integrate the combo, I just call HSQLDB to the party. To avoid describe exactly what is HSQLDB, here is a quote from its homepage:

HSQLDB (HyperSQL DataBase) is the leading SQL relational database engine written in Java. It has a JDBC driver and supports a rich subset of ANSI-92 SQL (BNF tree format) plus many SQL:2008 enhancements. It offers a small, fast database engine which offers both in-memory and disk-based tables and supports embedded and server modes. Additionally, it includes tools such as a minimal web server, in-memory query and management tools (can be run as applets) and a number of demonstration examples.


FIRST, CONFIGURE MAVEN...

The simplest part: just add hsqldb as a maven dependency:

<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>1.8.0.10</version>
    <scope>test</scope>
</dependency>

I decide to scope it as test because I'm not intent to use it in production, but you can use a different scope.

SECOND, ADD TEST RESOURCES...

Then, I just create two files inside src/test/resources directory. You can create files here to replace src/main/resources while running tests. But I want to reduce the amount of work to maintain both test and production enviroment, so, I'm replacing just what need to be replace: the database configuration. The two files are:

src/test/resources/hibernate.tests.properties

hibernate.connection.driver_class = org.hsqldb.jdbcDriver
hibernate.connection.url = jdbc:hsqldb:mem:trapo
hibernate.connection.username = sa
hibernate.connection.password =
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50
hibernate.dialect = org.hibernate.dialect.HSQLDialect

hibernate.show_sql=true
hibernate.format_sql=true
hibernate.default_batch_fetch_size=5
hibernate.generate_statistics=true
hibernate.use_sql_comments=true
hibernate.jdbc.batch_size=10

hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
hibernate.cache.provider_class=net.sf.ehcache.hibernate.EhCacheProvider
hibernate.cache.use_structured_entries=true

hibernate.hbm2ddl.auto=create-drop

Note the url property, it is pointing to an in memory database. Moreover, this files contains cache and some other optional configurations to mimic the production configurations. The other file is the Spring context to configure the SessionFactory for tests:

src/test/resources/applicationContextTest.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/util
           http://www.springframework.org/schema/util/spring-util-2.5.xsd">
  <bean id="testSessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
        p:annotatedClasses-ref="annotatedClasses"
        p:annotatedPackages="com.google.code.trapo.domain"
        p:hibernateProperties-ref="hibernateProperties" />
  <util:list id="annotatedClasses">
    <value>com.google.code.trapo.domain.Forum</value>
    <value>com.google.code.trapo.domain.Topic</value>
  </util:list>
  <util:properties id="hibernateProperties" location="classpath:hibernate.test.properties" />
</beans>

I'm not fully confortable with that because I need to copy and past mapped classes here. But, this is a start, so I prefer to have sub-optimal solution over don't have any solution at all.

THIRD, REFACTOR YOUR TESTS...

Your tests should use SpringJUnit4Runner instead of the default one. So you have to put the following annotation in the test class:

@RunWith(SpringJUnit4ClassRunner.class)
public class MyRepositoryTests {
    ...
}

You also need to say to Spring where it should find the configuration files using @ContextConfiguration annotation:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath:/trapo-servlet.xml",
    "classpath:/applicationContextTest.xml"
})
public class MyRepositoryTests {
    ...
}

And, because your tests are using the database, is a good call configure them to be transactional. In order to do that, you need both @Transactional and @TransactionConfiguration annotations:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath:/trapo-servlet.xml",
    "classpath:/applicationContextTest.xml"
})
@Transactional
@TransactionConfiguration(transactionManager = "txManager")
public class MyRepositoryTests {
    ...
}

And then inject the testSessionFactory configure in applicationContextTests.xml in your tests:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath:/trapo-servlet.xml",
    "classpath:/applicationContextTest.xml"
})
@Transactional
@TransactionConfiguration(transactionManager = "txManager")
public class MyRepositoryTests {

    @Autowired private SessionFactory testSessionFactory;

}

FINALLY, JUST RUN YOUR TESTS...

And now the grand finale, just open a command prompt, go to trapo directory and type:

mvn clean test

If you want to see cobertura report, type:

mvn clean cobertura:cobertura

Hope that helps.

Filed under: hibernate

jetztgradnet says...

http://tech.puredanger.com/2009/07/10/hibernate-query-cache/

Filed under: hibernate

trapo says...

Because Trapo is at same time both a serious and pet project, I decide to give up about some tools and frameworks (Rails and PHP) that I know better and go through Java stuff - but not Grails because of its similarities with Rails. I'm not a Java guru and so, why not to try what is well accepted by community and take a safe path? Below I list my weapons.

FRAMEWORKS

SpringFramework as Dependency Inversion Container, MVC and as a glue between the other guys (version 3.0.0.M3)
Hibernate Core (3.3.2), Hibernate Annotations (3.4.0), Hibernate Search (3.1.1) as... you know!
JUnit (4.6) and Mockito (1.8.0) to do TDD (or at least try)

TOOLS

Eclipse Galileo (with some plugins)
Maven2 to manage all dependencies and build the project (I choose Maven also because it creates a common directory structure)

SO...

I'm expecting some fight with this tools, specially with Maven and Spring. Keep with me to know how a non-java guy solves these problems.

Filed under: hibernate