Spring Hibernate “annotatedPackages”

Sebenarnya ini trik lama sih, dapet dari mana juga dah lupa sumbernya…

Ok, ini tentang gimana caranya agar Spring Hibernate bisa ngenalin tag-tag annotation dengan mencantumkan nama packagenya aja di spring xml, jadi biar biar ga susah-susah tiap tambah class mapping baru, tambah baris baru di spring xml… tape deee…

Neh contohnya:

<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:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx"
        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/tx
                       http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

        <context:property-placeholder
                location="classpath:log4j.properties,
                file:${QANTREX_SERVER_HOME}/etc/*.properties" />

        <context:component-scan base-package="com.ecom.qantrex" />

        <tx:annotation-driven transaction-manager="txManager" />

        <bean id="dataSource"
                class="org.springframework.jdbc.datasource.DriverManagerDataSource"
                p:driverClassName="${com.ecom.qantrex.jdbc.driver}"
                p:url="${com.ecom.qantrex.jdbc.url}"
                p:username="${com.ecom.qantrex.jdbc.username}"
                p:password="${com.ecom.qantrex.jdbc.password}" />

        <bean id="sessionFactory"
                class="com.ecom.qantrex.common.AutomaticAnnotationSessionFactoryBean"
                p:dataSource-ref="dataSource">
                <property name="annotatedPackages">
                        <list>
                                <value>com.ecom.qantrex.softpin.entity
                                </value>
                                <value>com.ecom.qantrex.loyalty.entity
                                </value>
                        </list>
                </property>
                <property name="hibernateProperties">
                        <props>
                                <prop key="hibernate.dialect">
                                        ${com.ecom.qantrex.hibernate.dialect}
                                </prop>
                                <prop key="hibernate.show_sql">
                                        ${com.ecom.qantrex.hibernate.show_sql}
                                </prop>

                        </props>
                </property>
        </bean>

        <!-- transaction manager -->
        <bean id="txManager"
                class="org.springframework.orm.hibernate3.HibernateTransactionManager"
                p:sessionFactory-ref="sessionFactory" />

</beans>

Tuh noh, yang di warna tebal biru tuh…
Lho, kox bisa Cak… ya bisa Cik, kan binding class nya biken sendiri, ini neh namanya:

com.ecom.qantrex.common.AutomaticAnnotationSessionFactoryBean

biasanya berisi “annotatedClasses” dan list-value berisi daftar complete class-name, cara per-class gitu biken kerjaan tambahan, karna klo ngubah2 nama class, atao nambah class-mapping baru, ga praktis gitu loh…

Isinya class  AutomaticAnnotationSessionFactoryBean ini neh:

package com.ecom.qantrex.common;

import java.io.IOException;

import org.hibernate.HibernateException;
import org.hibernate.cfg.AnnotationConfiguration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;

public class AutomaticAnnotationSessionFactoryBean extends
        AnnotationSessionFactoryBean {

        private static String resourcePattern = "**/*.class";

        private String[] annotatedPackages;

        @Override
        public void setAnnotatedPackages(String[] annotatedPackages) {
                super.setAnnotatedPackages(annotatedPackages);
                this.annotatedPackages = annotatedPackages;
        }

        @Override
        @SuppressWarnings("unchecked")
        protected void postProcessAnnotationConfiguration(AnnotationConfiguration
                config) throws HibernateException {
                try {
                        ClassLoader classLoader =
                                Thread.currentThread().getContextClassLoader();
                        PathMatchingResourcePatternResolver patternResolver =
                                new PathMatchingResourcePatternResolver(classLoader);
                        SimpleMetadataReaderFactory metadataReaderFactory =
                                new SimpleMetadataReaderFactory(classLoader);

                        for (String basePackage : annotatedPackages) {
                                String resolvedPackage =
                                        ClassUtils.convertClassNameToResourcePath(
                                        SystemPropertyUtils
                                        .resolvePlaceholders(basePackage));
                                String packageSearchPath = ResourcePatternResolver.
                                        CLASSPATH_ALL_URL_PREFIX
                                        + resolvedPackage.trim()
                                        + "/" + resourcePattern;
                                Resource[] resources = patternResolver.
                                        getResources(packageSearchPath);

                                for (Resource resource : resources) {
                                        MetadataReader metadataReader =
                                                metadataReaderFactory.
                                                getMetadataReader(resource);
                                        AnnotationMetadata annotationMetadata =
                                                metadataReader.
                                                getAnnotationMetadata();
                                        boolean match = annotationMetadata.
                                                hasAnnotation(
                                                "javax.persistence.Entity");
                                        match = match || annotationMetadata.
                                                hasAnnotation(
                                                "org.hibernate.annotations.Entity");
                                        if (!match) continue;
                                        String className =
                                                metadataReader.
                                                getClassMetadata().getClassName();
                                        Class clazz = Class.forName(className);
                                        config.addAnnotatedClass(clazz);
                                }
                        }
                } catch (ClassNotFoundException e) {
                        throw new HibernateException(e);

                } catch (IOException e) {
                        throw new HibernateException(e);
                }
        }

}

Ga susah-suah amat kan?

Nah, ntar di dalem package:

com.ecom.qantrex.softpin.entity

dan:

com.ecom.qantrex.loyalty.entity

spring akan mencari annotation @Table dan semua annotation javax.persistance lainnya, kayak ini neh:

package com.ecom.qantrex.softpin.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "region")
public class Region {

        @Id
        private int id;

        private String name;

        @Column(name = "\"zone\"")
        private String zone;

        private String code;

        public String getCode() {
                return code;
        }

        public void setCode(String code) {
                this.code = code;
        }

        public int getId() {
                return id;
        }

        public void setId(int id) {
                this.id = id;
        }

        public String getName() {
                return name;
        }

        public void setName(String name) {
                this.name = name;
        }

        public String getZone() {
                return zone;
        }

        public void setZone(String zone) {
                this.zone = zone;
        }

}

OK, gitu dulu ya, tanya aja dah klo ga paham,
‘n gud lax… :)

~ by luxmile on April 12, 2009.

Leave a Reply