leftovers...

about grails groovy

無意味にGrailsドメインクラスをHibernateの*.hbm.xmlファイルをスキャンしてザックリ生成してみる。

別に無意味というわけでないが、
4年ほど前にStruts+Hibernate+Springで開発したアプリケーションを作り直すために、
とりあえずドメインからと・・・・
意外とドメインが多い・・・そして各ドメインのフィールドも多い。。
Grailsでは、そのまま、*.hbm.xmlを使ってJavaのクラスを使用できるのだが、
拡張したり変更したりと、多分grailsドメインクラスで作業したほうが楽なのかな?
ということで、かなりグダグダなザックリスクリプトを書いてみたので(ほしい人がいるかも・・ってことで)さらしてみる。


仕組みは単純です。
指定したパスにある"*.hbm.xml"ファイルを全てを、XmlSlurperでぐねぐねして、
ガチでドメインクラスファイルを書き出しているだけです。
#自分の必要な物しか取ってきていない・・・。

手順です。
1. create-scriptで新規スクリプト作成。

grails create-script hbm

2. Grailsプロジェクト以下の"scripts"ディレクトリ以下に"Hbm.groovy"ファイルが生成されるので、
以下のソースに入れかえる。=>保存する。

3. 使用方法:"-path"オプションに*.hbm.xmlが置いてあるパスをあたえる。

grails hbm -path /your/file/path/to/hbm
grailsHome = Ant.project.properties."environment.GRAILS_HOME"

includeTargets << new File ( "${grailsHome}/scripts/Init.groovy" )  

target('default': "scan *.hbm.xml and export domain.groovy") {
  parseArguments()
  if(!argsMap?.path){
    println "[usage] grails hbm -path _PATH_TO_HBM_Files"
    System.exit(0)
  }
  
  def hbmDir = new File(argsMap.path)
  def pattern = ~/.*xml/
  hbmDir.eachFileMatch(pattern){f->
    def file = new File(""+f)
    
    def xml = new XmlSlurper().parse(file)
    def clsFullName = xml."class"."@name"
    def clsNameArr = "$clsFullName".split("\\.")
    //class name
    def clsName = clsNameArr[clsNameArr.length-1]
    //package
    def pkgArr = clsNameArr.getAt(new IntRange(0,clsNameArr.length-2) )

    def table = xml."class"."@table"
    def idElm = xml."class"."id"
    def idFieldName = idElm."@name"

    def idColumnName = idElm."@column"
    def idColumnType = idElm."@type"
    def idGenerator = idElm."generator"."@class"
    def idGeneratorSeqName = idElm."generator"."param".text()

    def fields=[:]
    def props = xml."class"."property"
    props.each{p->
      def columnName="${p.'@column'}"?"${p.'@column'}":p.'column'.'@name'
      def map=[
        "type":"${p.'@type'}",
        "column_name":"${columnName}",
        "column_type":"${p.'column'.'@sql-type'}",
        "len":"${p.'@length'}"
      ]
      fields[p."@name"]=map
    }

    def str=[]
    str<< "class ${clsName} {"
    str<< "\t"+"static mapping = {"
    str<< "\t\t"+"table '${table}'"
    str<< "\t\t"+"version false"
    str<< "\t\t"+"id column:'${idColumnName}' , type:'integer'"
    str<< "\t\t"+"id generator:'${idGenerator}', params:[sequence:'${idGeneratorSeqName}']"
    str<< ""
    def constrain=[:]
    fields.each{k,v->
      def type = ""
      if(v.column_type){
        type = ",type:'${v.column_type}'"
      }else if(v.type=="java.lang.Boolean"){
        type = ",type:'boolean'"
      }else if(v.type=="java.lang.Integer"){
        def len=v.len?:"4"
        def intype=len=="4"?"integer":"bigint"
        type = ",type:'${intype}'"
      }else if(v.type=="java.lang.String" && v.len!=''){
        constrain[k]="maxSize:${v.len}"
      }
      str<< "\t\t${k} column:'${v.column_name}' ${type}"
    }
    str<< "\t}"
    str<<"\tInteger id"
    fields.each{k,v->
      str<< "\t${v.type.replace('java.lang.','')} ${k}"
    }
    str<< ""
    str<< "\t"+"static constraints = {"
      fields.each{k,v->
        str<< "\t\t"+"${k}(nullable:true${constrain[k]?' ,'+constrain[k]:''})"
      }
    str<< "\t"+"}"
    str<< "}"
    def outFile = new File("grails-app/domain","${clsName}.groovy")
    new FileOutputStream(outFile).withWriter('UTF8'){w-> w << str.join("\n") }
  }
}

Grailsで"script"を活用すると、意外と開発時に便利!