Hibernate Tools源码的使用

Eclipse 中Hibernate tools 的安装和使用 http://zhoualine.iteye.com/blog/1190141

源码里面有一个很好的格式化类:org.hibernate.tool.hbm2x. XMLPrettyPrinter
调用
	public void formatFiles() {
		
		formatXml( "xml" );
		formatXml( "hbm.xml" );
		formatXml( "cfg.xml" );
				
	}

	private void formatXml(String type) throws ExporterException {
		List list = (List) files.get(type);
		if(list!=null && !list.isEmpty()) {
			for (Iterator iter = list.iterator(); iter.hasNext();) {
				File xmlFile = (File) iter.next();
				try {					
					XMLPrettyPrinter.prettyPrintFile(XMLPrettyPrinter.getDefaultTidy(), xmlFile, xmlFile, true);
				}
				catch (IOException e) {
					throw new ExporterException("Could not format XML file: " + xmlFile,e);
				}
			}
		}
	}


获得源码的方法:
https://github.com/hibernate/hibernate-tools, 然后建立maven工程
得到源码后需要处理的问题:
1.修改pom.xml的name等信息,来适合自己建立的工程。
2.注释掉pom.xml一些没必要的数据库信息。
3.注释几个地方
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.5.8</version>
			<!--<scope>test</scope>-->
		</dependency>

4.加入sql server driver,先执行mavn
mvn install:install-file -Dfile=/mnt/D/work_documents/jar2mvn/sqljdbc-4.0.jar -DgroupId=sqljdbc -DartifactId=sqljdbc -Dversion=4.0 -Dpackaging=jar
再加入依赖:
        <dependency>
            <groupId>sqljdbc</groupId>
            <artifactId>sqljdbc</artifactId>
            <version>4.0</version>
        </dependency>

5. 加入
/mnt/D/work_documents/workspace_ide/HibernateTools/src/java/config/hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 连接数据库信息 -->
        <property name="hibernate.bytecode.use_reflection_optimizer">false</property>
        <property name="hibernate.connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
        <property name="hibernate.connection.password">sa</property>
        <property name="hibernate.connection.url">jdbc:sqlserver://192.168.0.196:1433;databaseName=dev_cpm</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
        <property name="hibernate.search.autoregister_listeners">false</property>
        <!-- 代码生成信息  info -->
        <!--<property name="hibernatetool.metadatadialect">org.hibernate.cfg.reveng.dialect.SQLServer2008MetaDataDialect</property>-->
        <property name="hibernatetool.metadatadialect">org.hibernate.cfg.reveng.dialect.SQLServerMetaDataDialect</property>

        <!-- 自定义信息 -->
        <property name="custom.package">com</property>
        <property name="custom.one2many">false</property>
        <property name="custom.many2one">true</property>
        <property name="custom.many2many">true</property>
        <property name="custom.detectOptimisticLock">true</property>
        <!-- 要遍历的数据库,这个是必需写正确,否在找不到表 -->
        <property name="custom.catlog">dev_cpm</property>
        <property name="custom.schema">dbo</property>
        <property name="custom.isAnnotation">true</property>
        <property name="custom.genPojo">true</property>
        <property name="custom.genDao">true</property>
        <property name="custom.outputDir">/mnt/D/work_documents/workspace_ide/HibernateTools/codes</property>
    </session-factory>
</hibernate-configuration>


/mnt/D/work_documents/workspace_ide/HibernateTools/src/java/com/pandy/RunHibernateTools.java
package com.pandy;

import java.io.File;
import java.util.Properties;

import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.JDBCMetaDataConfiguration;
import org.hibernate.cfg.reveng.DefaultReverseEngineeringStrategy;
import org.hibernate.cfg.reveng.ReverseEngineeringSettings;
import org.hibernate.tool.hbm2x.DAOExporter;
import org.hibernate.tool.hbm2x.DAONewExporter;
import org.hibernate.tool.hbm2x.POJOExporter;

public class RunHibernateTools {

    public void run() {

        String path = getClass().getResource("/").toString();
        if (path.startsWith("file:"))
            path = path.substring("file:".length() + 1);

        //String fileName = path + "config/hibernate.cfg.xml";
        String fileName = "/mnt/D/work_documents/workspace_ide/HibernateTools/src/java/config/hibernate.cfg.xml";
        File file = new File(fileName);
        if (!file.exists()) {
            throw new RuntimeException("找不到配置文件");
        }
        // 直接给绝对路径会出问题
        Configuration xmlcfg = new Configuration().configure(file);

        JDBCMetaDataConfiguration cfg = new JDBCMetaDataConfiguration();
        Properties properties = xmlcfg.getProperties();
        cfg.setProperties(properties);

        DefaultReverseEngineeringStrategy configurableNamingStrategy = new DefaultReverseEngineeringStrategy();
        configurableNamingStrategy.setSettings(new ReverseEngineeringSettings(configurableNamingStrategy)
                .setDefaultPackageName(getString(properties, "custom.package", "com"))// 要生成的包名
                .setCreateCollectionForForeignKey(getBoolean(properties, "custom.one2many", false))// 是否生成many-to-one的在one端的集合类,
                        // 就是一对多的关系
                .setCreateManyToOneForForeignKey(getBoolean(properties, "custom.many2one", true))// 是否生成many-to-one
                .setDetectManyToMany(getBoolean(properties, "custom.many2many", true))// 是否生成many-to-many
                .setDetectOptimisticLock(getBoolean(properties, "custom.detectOptimisticLock", true)) // 乐观锁对象?
        );
        cfg.setReverseEngineeringStrategy(configurableNamingStrategy);
        //cfg.readFromJDBC();// 不区分schema和catlog的话,容易碰到错误.
        cfg.readFromJDBC(getString(properties, "custom.catlog", "Test"), getString(properties, "custom.schema", "dbo"));// 只从数据的这些信息生成
        cfg.buildMappings();

        if (getBoolean(properties, "custom.genPojo", true)) {
            POJOExporter exporter = new POJOExporter(cfg, getOutputDir(properties));
            if (getBoolean(properties, "custom.isAnnotation", true)) {
                exporter.getProperties().setProperty("ejb3", "true");// ejb3注解
                exporter.getProperties().setProperty("jdk5", "true");// jdk5语法(主要是集合类的泛型处理)
            }
            exporter.start();
        }

        if (getBoolean(properties, "custom.genDao", false)) {
            DAOExporter daoExporter = new DAOExporter(cfg, getOutputDir(properties));
            daoExporter.start();
        }
    }

    private File getOutputDir(Properties properties) {
        File file = new File(getString(properties, "custom.outputDir", "/"));// 生成项目的物理位置(跟目录,tools会自动根据pacakge建立相应路径)
        return file;
    }

    private static boolean getBoolean(Properties properties, String key, boolean defaultValue) {
        String val = properties.getProperty(key);
        if (isBlank(val)) {
            return defaultValue;
        }
        return Boolean.valueOf(val);
    }

    private static String getString(Properties properties, String key, String defaultValue) {
        String val = properties.getProperty(key);
        if (isBlank(val)) {
            return defaultValue;
        }
        return val;
    }

    private static Integer getInteger(Properties properties, String key, Integer defaultValue) {
        String val = properties.getProperty(key);
        if (isBlank(val)) {
            return defaultValue;
        }
        return Integer.parseInt(val);
    }

    private static boolean isBlank(String val) {
        if (val == null || val.trim().length() == 0)
            return true;
        return false;
    }

    public static void main(String[] args) {
        System.out.println("----------------代码生成开始-----------------------");
        RunHibernateTools tools = new RunHibernateTools();
        tools.run();
        System.out.println("----------------代码生成完成-----------------------");

    }

}

可能要适当修改
6.增加一个存放代码的文件夹
/mnt/D/work_documents/workspace_ide/HibernateTools/codes
7. /mnt/D/work_documents/workspace_ide/HibernateTools/src/java/org/hibernate/cfg/JDBCMetaDataConfiguration.java 增加一个方法:
public void readFromJDBC(String catalog, String schema) {

        JDBCBinder binder = new JDBCBinder(this, buildSettings(), createMappings(), revEngStrategy);

        binder.readFromDatabase(catalog, schema, buildMapping(this));

    }

mian方法修改:
//cfg.readFromJDBC();// 不区分schema和catlog的话,容易碰到错误.
cfg.readFromJDBC(getString(properties, "custom.catlog", "Test"), getString(properties, "custom.schema", "dbo"));// 只从数据的这些信息生成

8.生成的DAO后缀是Home,要是改成XxxxDAO,以DAO为后缀。
/mnt/D/work_documents/workspace_ide/HibernateTools/src/java/org/hibernate/tool/hbm2x/DAOExporter.java, 修改以下方法为:
protected void init() {
    	super.init();
    	setTemplateName(DAO_DAOHOME_FTL);
    	setFilePattern("{package-name}/{class-name}DAO.java");    	    	
    }

9.模板文件,如果生成的代码需要修改,可以修改模板,路径为
/mnt/D/work_documents/workspace_ide/HibernateTools/src/templates
10. 配置需要生成代码的表
A: 跟踪代码
/mnt/D/work_documents/workspace_ide/HibernateTools/src/java/org/hibernate/tool/hbm2x/GenericExporter.java
前面有一段static代码,里面有 ge.getConfiguration().getClassMappings(),ge.getConfiguration()里面有一个tables属性,映射了table=>java file.
B:到/mnt/D/work_documents/workspace_ide/HibernateTools/src/java/org/hibernate/tool/hbm2x/AbstractExporter.java  去查看这个configuration到底怎么初始化?
可以看到它的初始化是GenericExporter构造函数里面传入。那么就要找到什么时候创建GenericExporter?
C:
它是在POJOExporter构造函数里面,那么就在main函数的POJOExporter exporter = new POJOExporter(cfg, getOutputDir(properties));创建。
D:到main函数更在cfg的创建,并监视里面的tables什么时候有值?cfg.readFromJDBC()这里被赋值,继续跟踪。
D: 跟踪到/mnt/D/work_documents/workspace_ide/HibernateTools/src/java/org/hibernate/cfg/JDBCBinder.java,readFromDatabase()方法DatabaseCollector collector = readDatabaseSchema(catalog, schema),被赋值。
E: 让它继续找,我们只是在生成的时候过滤掉就可以了。 那么回到A,在这里做手脚
-----------
I: /mnt/D/work_documents/workspace_ide/HibernateTools/src/java/config/hibernate.cfg.xml增加一个
<!--  需要都好隔开表名  -->
<property name="custom.filter.include">app_user,rh_log_exception_info,rh_log_exception_param</property>

II:/mnt/D/work_documents/workspace_ide/HibernateTools/src/java/org/hibernate/cfg/JDBCMetaDataConfiguration.java最后面增加
public String[] filterIncludeTables = null;
    public void setFilterIncludeTables(String[] filters) {
        this.filterIncludeTables = filters;
        for (int i = 0; i < filters.length; i++) {
            this.filterIncludeTables[i] = filters[i].replace("_", "");
        }
    }

    public boolean isInclude(String shortName) {
        if(filterIncludeTables==null) return true;

        for (int i = 0; i < filterIncludeTables.length; i++) {
            if(shortName.equalsIgnoreCase(filterIncludeTables[i])) return true;
        }
        return false;
    }

III: /mnt/D/work_documents/workspace_ide/HibernateTools/src/java/org/hibernate/tool/hbm2x/GenericExporter.java修改static段的代码:
	static {
		modelIterators.put( "configuration", new ModelIterator() {

			void process(GenericExporter ge) {
				TemplateProducer producer = new TemplateProducer(ge.getTemplateHelper(),ge.getArtifactCollector());
				producer.produce(new HashMap(), ge.getTemplateName(), new File(ge.getOutputDirectory(),ge.filePattern), ge.templateName, "Configuration");
				
			}
			
		});
		modelIterators.put("entity", new ModelIterator() {
		
			void process(GenericExporter ge) {
				Iterator iterator = ge.getCfg2JavaTool().getPOJOIterator(ge.getConfiguration().getClassMappings());
				Map additionalContext = new HashMap();
				while ( iterator.hasNext() ) {					
					POJOClass element = (POJOClass) iterator.next();
                    JDBCMetaDataConfiguration cfg = (JDBCMetaDataConfiguration)ge.getConfiguration();
                    if(cfg.isInclude(element.getShortName())){
                        ge.exportPersistentClass( additionalContext, element );
                    }
				}
			}
		});
		modelIterators.put("component", new ModelIterator() {
			
			void process(GenericExporter ge) {
				Map components = new HashMap();
				
				Iterator iterator = ge.getCfg2JavaTool().getPOJOIterator(ge.getConfiguration().getClassMappings());
				Map additionalContext = new HashMap();
				while ( iterator.hasNext() ) {					
					POJOClass element = (POJOClass) iterator.next();
					ConfigurationNavigator.collectComponents(components, element);											
				}
						
				iterator = components.values().iterator();
				while ( iterator.hasNext() ) {					
					Component component = (Component) iterator.next();
					ComponentPOJOClass element = new ComponentPOJOClass(component,ge.getCfg2JavaTool());
                    JDBCMetaDataConfiguration cfg = (JDBCMetaDataConfiguration)ge.getConfiguration();
                    if(cfg.isInclude(element.getShortName())){
                        ge.exportComponent( additionalContext, element );
                    }
				}
			}
		});
	}

这样就搞定了。可以模仿做排除功能。
11.打包成jar, 参考: http://panyongzheng.iteye.com/blog/1759912http://sundful.iteye.com/blog/1850070,修改pom.xml使用maven-compiler-plugin插件的java版本为1.7。 并修改插件的版本号 http://qiang106.iteye.com/blog/1388645
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
					<includes>
						<include>**/*.java</include>
					</includes>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
			......
			......
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-assembly-plugin</artifactId>
				<configuration>
					<descriptors>
						<descriptor>./src/assembly/dist.xml</descriptor>
					</descriptors>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
				</configuration>
			</plugin>

命令为:
测试并打包: mvn -e clean package
不需要测试打包: mvn -e clean package -DskipTests
复制源码,不测试打包: mvn clean assembly:assembly -DskipTests
12.执行jar:
复制得到依赖jar: mvn dependency:copy-dependencies -DoutputDirectory=target/lib
执行不含源码jar: java -jar /mnt/D/work_documents/workspace_ide/HibernateTools/target/hibernate-tools-Pandy.4.0.0-CR1.jar
执行含源码的jar: java -jar /mnt/D/work_documents/workspace_ide/HibernateTools/target/hibernate-tools-Pandy.4.0.0-CR1-jar-with-dependencies.jar
最后的 打包并执行的两个命令:
mvn -e clean package dependency:copy-dependencies -DskipTests -DoutputDirectory=target/lib
java -jar /mnt/D/work_documents/workspace_ide/HibernateTools/target/hibernate-tools-Pandy.4.0.0-CR1.jar

13.执行是输入hibernate.cfg.xml文件路径
A:修改run方法,增加一个hibernate.cfg.xml的绝对路径参数,并注释掉原本硬编码路径:

B:修改mian方法:
public static boolean validate(String[] args){
        if(args==null||args.length==0) {
            System.out.println("ERROR: 一定要输入一个参数,这个参数是hibernate.cfg.xml的绝对路径.");
            return false;
        }
        String filePath = args[0];

        File file = new File(filePath);
        if(!file.exists()){
            System.out.println("ERROR: hibernate.cfg.xml文件不存在.");
            return false;
        }
        return true;
    }

    public static void main(String[] args) {
        System.out.println("验证参数:");
        if(!validate(args)){
            System.exit(0);
        }

        System.out.println("----------------代码生成开始-----------------------");
        RunHibernateTools tools = new RunHibernateTools();
        tools.run(args[0]);
        System.out.println("----------------代码生成完成-----------------------");

    }

最终执行命令: java -jar /mnt/D/work_documents/workspace_ide/HibernateTools/target/hibernate-tools-Pandy.4.0.0-CR1.jar /mnt/D/work_documents/workspace_ide/HibernateTools/hibernate.cfg.xml
14.POJO的源码主键生成
org.hibernate.tool.hbm2x.pojo.EntityPOJOClass, generateAnnIdGenerator()方法。因为不知道怎么传入主键的配置,所以尝试在这里修改。我改成了:要么是uuid,要么是auto类型,这个是自己的需求。
			if ( !"native".equals( strategy ) ) {
                    if ( "guid".equals( strategy )||"uuid".equals( strategy ) ) {
                        //增加uuid的注解
                        builder.resetAnnotation( importType("javax.persistence.GeneratedValue") );
                        builder.addQuotedAttribute( "generator", "system-uuid" );
                        idResult.append(builder.getResult());
                        //增加一个注解
                        AnnotationBuilder builder1=AnnotationBuilder.createAnnotation( importType("org.hibernate.annotations.GenericGenerator") )
                                .addQuotedAttribute( "name", "system-uuid" )
                                .addQuotedAttribute( "strategy", "org.hibernate.id.UUIDGenerator");
                        idResult.append(builder1.getResult());
                    }
                    else {
						/*builder.resetAnnotation( importType("javax.persistence.GeneratedValue") );
						builder.addAttribute( "strategy", staticImport("javax.persistence.GenerationType", "IDENTITY" ) );
						idResult.append(builder.getResult());*/
                        builder.resetAnnotation( importType("javax.persistence.GeneratedValue") );
                        //使用自动主键生成器
                        builder.addAttribute( "strategy", staticImport("javax.persistence.GenerationType", "GenerationType.AUTO" ) );
                        idResult.append(builder.getResult());
                    }
                }else {
					builder.resetAnnotation( importType("javax.persistence.GeneratedValue") );
					idResult.append(builder.getResult());
				}



修改源码默认产生equal,toString,hashCode方法:
/mnt/D/work_documents/workspace_ide_linux/HibernateTools/src/java/org/hibernate/tool/hbm2x/pojo/BasicPOJOClass.java
toString:
private boolean needsToString(Iterator iter) {
		/*while ( iter.hasNext() ) {
			Property element = (Property) iter.next();
			if ( c2j.getMetaAsBool( element, "use-in-tostring" ) ) {
				return true;
			}
		}
		return false;*/
        return true;
	}

private Iterator getToStringPropertiesIterator(Iterator iter) {
		List properties = new ArrayList();

		while ( iter.hasNext() ) {
			Property element = (Property) iter.next();
			//if ( c2j.getMetaAsBool( element, "use-in-tostring" ) ) {
				properties.add( element );
			//}
		}

		return properties.iterator();
	}

equal & hashCode:
private boolean needsEqualsHashCode(Iterator iter) {
		while ( iter.hasNext() ) {
			Property element = (Property) iter.next();
			//if ( usePropertyInEquals( element ) ) {
				return true;
			//}
		}
		return false;
	}

public String generateHashCode(Property property, String result, String thisName, boolean jdk5) {
		StringBuffer buf = new StringBuffer();
		//if ( c2j.getMetaAsBool( property, "use-in-equals" ) ) {
			...... 里面的不用注释
		//}
		return buf.toString();
	}



修改版本号信息:
/mnt/D/work_documents/workspace_ide_linux/HibernateTools/src/java/org/hibernate/tool/Version.java











自己的修改hibernate-tools的模板和修复Comment乱码问题: http://kennylee26.iteye.com/blog/1229993
Hibernate Tools生成注释: http://www.blogjava.net/pauliz/archive/2009/11/13/302162.html
修改源码的地方:
输出中文乱码:
1.
TemplateProducer.produce(), 应该使用UTF-8输出到文件.
Writer fileWriter = null;
....
fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destination), "UTF-8"));
2.src/org/hibernate/tool/hbm2x/jtidy.properties
input-encoding=utf-8
output-encoding=utf-8
3.反转表名等类,都存放在:org.hibernate.cfg.reveng.dialect, 并针对相应类重载getTables方法.
DAO:
src/org/hibernate/tool/hbm2x/DAOExporter.java, 这里修改输出类的文件名,extends,implements等.
dao/daohome.ftl, 这里可以修改默认的方法,和类名字等.
POJO:
src/org/hibernate/tool/hbm2x/POJOExporter.java, 这里修改输出类的extends,implements等.
pojo/Pojo.ftl

去掉注解的schema,catlog, Ejb3TypeDeclaration.ftl,Line8,7

POJO的头部注释信息:生成表的注释:
A:修改或者重载JDBCMetaDataDialect的继续类的getTables()方法,确保这里的rs.getString("remarks")能得到数据库的注释,否则自己查找数据库得到注释.
B:src/pojo/PojoTypeDeclaration.ftl,增加表注释
${pojo.getClassJavaDoc(pojo.getDeclarationName() + " By Pandy.", 0)}
改为
<#if clazz.table.comment?exists>
/**
* Entity: ${clazz.table.comment}
*/
</#if>

extends:
BasicPOJOClass.getExtendsDeclaration(), Line190
EntityPOJOClass.getExtends(), 写入extends, 或者直接Line84固定返回extends

implements:
BasicPOJOClass.getImplementsDeclaration(), Line200
EntityPOJOClass.getImplements(), Line87
给POJO增加一些默认的函数:
src/pojo/Pojo.ftl, Line11,
增加serialVersionUID:
src/pojo/Pojo.ftl, Line7
private static final long serialVersionUID = 1L;


修改数据库语言:Dialect, 这里影响到pojo.id的注解
MetaDataDialectFactory.createMetaDataDialect();
这里没有正确从文件hibernate.properties获得dialect, 所以直接修改property=默认的dialect,
比如:String property ="org.hibernate.cfg.reveng.dialect.SQLServerMetaDataDialect"; 
SQLServerMetaDataDialect这个是在Hibernate-Tools.jar里面的.




http://tonydark01.iteye.com/blog/1721834
直接用junit或mian函数运行,而非依赖于jboss的插件,省的更新eclipse或者迁移的时候各种麻烦 ,副项目包备份.
1.增加slf4j-simple-1.5.2.jar,
2.增加驱动程序包,
3.给JDBCMetaDataConfiguration.java增加一个方法
public void readFromJDBC(String catalog, String schema) {
		JDBCBinder binder = new JDBCBinder(this, buildSettings(), createMappings(), revEngStrategy);
		binder.readFromDatabase(catalog, schema, buildMapping(this));
	}

4.给hibernate.cfg.xml增加一个属性
<property name="hibernatetool.metadatadialect">org.hibernate.cfg.reveng.dialect.SQLServer2008MetaDataDialect</property>
,
注意,貌似许多属性都是在这里增加的.

猜你喜欢

转载自panyongzheng.iteye.com/blog/1829520
今日推荐