Skip to content

Instantly share code, notes, and snippets.

@monzou
Created April 1, 2011 04:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monzou/897719 to your computer and use it in GitHub Desktop.
Save monzou/897719 to your computer and use it in GitHub Desktop.
package scripts;
import org.apache.poi.hssf.usermodel.HSSFCellStyle
import org.apache.poi.hssf.usermodel.HSSFFont
import org.apache.poi.hssf.usermodel.HSSFRichTextString
import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.ss.usermodel.CellStyle
import org.apache.poi.ss.usermodel.IndexedColors
/**
* usage: ReverseHbmToEntityExcel [target.dir] [dist.path]
*
* @author monzou
*/
class Utils {
static def prop(self, path, name) {
def p = path["@${name}"]
p == "" ? null : p
}
static def exp(self, path, name, prefix="") {
def p = prop(self, path, name)
p == null ? null : "${prefix}${name}: ${p}"
}
static def append(self, s1, s2, junction="") {
s2 == null ? s1 : (s1 + junction + s2)
}
}
@Mixin(Utils)
class IdentifierProperty {
private path
def type() {
prop(path, "type")
}
def name() {
prop(path, "name")
}
def remarks() {
def remarks = prop(path, "column").text()
append(remarks, exp(path.generator, "class", "\ngenerator."))
}
}
@Mixin(Utils)
class SimpleProperty {
private path
def type() {
prop(path, "type")
}
def name() {
prop(path, "name")
}
def remarks() {
prop(path, "column").text()
}
}
@Mixin(Utils)
class OneToOneProperty {
private path
def type() {
prop(path, "class")
}
def name() {
prop(path, "name")
}
def remarks() {
def remarks = "one-to-one"
remarks = append(remarks, exp(path, "cascade"), "\n")
remarks = append(remarks, exp(path, "outer-join"), "\n")
remarks = append(remarks, exp(path, "lazy"), "\n")
remarks = append(remarks, exp(path, "property-ref"), "\n")
remarks = append(remarks, exp(path, "constrained"), "\n")
remarks = append(remarks, exp(path.column, "name", "\njoinColumn."))
}
}
@Mixin(Utils)
class ManyToOneProperty {
private path
def type() {
prop(path, "class")
}
def name() {
prop(path, "name")
}
def remarks() {
def remarks = "many-to-one"
remarks = append(remarks, exp(path, "not-found"), "\n")
remarks = append(remarks, exp(path, "lazy"), "\n")
remarks = append(remarks, exp(path, "cascade"), "\n")
remarks = append(remarks, exp(path, "unique"), "\n")
remarks = append(remarks, exp(path, "property-ref"), "\n")
remarks = append(remarks, exp(path.column, "name", "\njoinColumn."))
}
}
@Mixin(Utils)
class OneToManyProperty {
private path
def type() {
"java.util.Set<${prop(path, 'class')}>"
}
def name() {
prop(path.parent(), "name")
}
def remarks() {
def remarks = "one-to-many"
remarks = append(remarks, exp(path.parent(), "table"), "\n")
remarks = append(remarks, exp(path.parent(), "cascade"), "\n")
remarks = append(remarks, exp(path.parent(), "outer-join"), "\n")
remarks = append(remarks, exp(path.parent(), "lazy"), "\n")
remarks = append(remarks, exp(path.parent(), "inverse"), "\n")
remarks = append(remarks, exp(path.parent(), "mutable"), "\n")
remarks = append(remarks, exp(path.parent(), "where"), "\n")
remarks = append(remarks, exp(path.parent().key.column, "name", "\njoinColumn."))
}
}
@Mixin(Utils)
class ManyToManyProperty {
private path
def type() {
"java.util.Set<${prop(path, 'class')}>"
}
def name() {
prop(path.parent(), "name")
}
def remarks() {
def remarks = "many-to-many"
remarks = append(remarks, exp(path.parent(), "table"), "\n")
remarks = append(remarks, exp(path.parent(), "cascade"), "\n")
remarks = append(remarks, exp(path.parent(), "outer-join"), "\n")
remarks = append(remarks, exp(path.parent(), "lazy"), "\n")
remarks = append(remarks, exp(path.parent(), "inverse"), "\n")
remarks = append(remarks, exp(path.parent(), "mutable"), "\n")
remarks = append(remarks, exp(path.parent(), "where"), "\n")
remarks = append(remarks, exp(path.parent().key.column, "name", "\njoinColumn."))
remarks = append(remarks, exp(path.column, "name", "\nassociationColumn."))
}
}
class Parser {
def delegate
Parser() {
delegate = new XmlSlurper()
delegate.setFeature "http://apache.org/xml/features/nonvalidating/load-external-dtd", false
}
def parse(target) {
delegate.parse(target).children()[0]
}
}
class BaseWriter {
def book
def sheet
def style
def headerStyle
def borderStyle
def bottomStyle
def boldBottomStyle
def BaseWriter() {
book = new HSSFWorkbook()
setupFont(book.getFontAt ((short) 0))
sheet = book.createSheet()
sheet.setZoom 85, 100
book.setSheetName 0, "entity"
style = style()
headerStyle = headerStyle()
borderStyle = borderStyle()
bottomStyle = bottomStyle()
boldBottomStyle = boldBottomStyle()
}
def flush(path) {
println "output ${path}"
new File(path).withOutputStream { book.write(it) }
}
private def borderStyle() {
def style = style()
style.setBorderTop HSSFCellStyle.BORDER_THIN
style.setBorderRight HSSFCellStyle.BORDER_THIN
style.setBorderBottom HSSFCellStyle.BORDER_THIN
style.setBorderLeft HSSFCellStyle.BORDER_THIN
style
}
private def headerStyle() {
def style = borderStyle()
def font = setupFont(book.createFont())
font.setColor IndexedColors.WHITE.getIndex()
style.setFillForegroundColor IndexedColors.GREY_80_PERCENT.getIndex()
style.setFillPattern CellStyle.SOLID_FOREGROUND
style.setFont font
style
}
private def boldBottomStyle() {
def style = bottomStyle()
def font = setupFont(book.createFont())
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD)
style.setFont font
style
}
private def bottomStyle() {
def style = style()
style.setVerticalAlignment HSSFCellStyle.VERTICAL_BOTTOM
style
}
def style() {
def style = book.createCellStyle()
style.setWrapText true
style.setVerticalAlignment HSSFCellStyle.VERTICAL_TOP
style.setAlignment HSSFCellStyle.ALIGN_LEFT
style
}
private def setupFont(font) {
font.setFontName "メイリオ"
font.setFontHeightInPoints((short) 11)
font
}
}
class Writer extends BaseWriter {
def propertyMapping = [
"description" : ["column": 1, "header": "属性"],
"type" : ["column": 2, "header" :"型"], "name": [ "column": 3, "header":"プロパティ"] , "remarks":["column":4, "header":"備考"]]
def Writer() {
super()
sheet.setColumnWidth 0, 256 * 5
sheet.setColumnWidth 1, 256 * 25
sheet.setColumnWidth 2, 256 * 70
sheet.setColumnWidth 3, 256 * 25
sheet.setColumnWidth 4, 256 * 70
}
def write(rowNumber, node) {
writeClassHeader(rowNumber++, node)
writePropertyHeader(rowNumber++)
writeProperties(rowNumber++, node)
}
private def writeClassHeader(rowNumber, node) {
def row = sheet.createRow(rowNumber)
use(Utils) {
writeCell(row, 1, truncatePackage(prop(node, "name")?.text()), boldBottomStyle)
writeCell(row, 2, exp(node, "extends"), bottomStyle)
writeCell(row, 3, node.name(), bottomStyle)
def info = exp(node, "table")
info = append(info, exp(node, "discriminator-value", "\n"))
writeCell(row, 4, info, bottomStyle)
}
rowNumber
}
private def writePropertyHeader(rowNumber) {
def row = sheet.createRow(rowNumber)
propertyMapping.keySet().each { key ->
def cell = row.createCell(propertyMapping[key]["column"])
cell.setCellStyle headerStyle
cell.setCellValue propertyMapping[key]["header"]
}
rowNumber
}
private def writeProperties(rowNumber, node) {
node.id.each { p ->
writeProperty(sheet.createRow(rowNumber++), node, new IdentifierProperty(path:p))
}
node.property.each { p ->
writeProperty(sheet.createRow(rowNumber++), node, new SimpleProperty(path:p))
}
node.version.each { p ->
writeProperty(sheet.createRow(rowNumber++), node, new SimpleProperty(path:p))
}
node.'**'.findAll {
it.name() == "one-to-one"
}.each { p ->
writeProperty(sheet.createRow(rowNumber++), node, new OneToOneProperty(path:p))
}
node.'**'.findAll {
it.name() == "many-to-one"
}.each { p ->
writeProperty(sheet.createRow(rowNumber++), node, new ManyToOneProperty(path:p))
}
node.'**'.findAll {
it.name() == "one-to-many"
}.each { p ->
writeProperty(sheet.createRow(rowNumber++), node, new OneToManyProperty(path:p))
}
node.'**'.findAll {
it.name() == "many-to-many"
}.each { p ->
writeProperty(sheet.createRow(rowNumber++), node, new ManyToManyProperty(path:p))
}
rowNumber
}
private def writeProperty(row, node, property) {
propertyMapping.keySet().each { key ->
def columnNumber = propertyMapping[key]["column"]
def text = null
try {
text = property.invokeMethod(key, null)?.toString()
} catch (MissingMethodException ignore) {
}
writeCell(row, columnNumber, text, borderStyle)
}
}
private def writeCell(row, columnNumber, text, style=this.style) {
def cell = row.createCell(columnNumber)
cell.setCellStyle style
cell.setCellValue new HSSFRichTextString(text)
}
private def truncatePackage(type) {
type?.replaceAll(/.*\./, '')
}
}
class ClassNode {
def fqn
def parentFqn
def path
def children = [:]
}
// クラスツリーを組み立てる
def parser = new Parser()
def nodes = [:]
def adjustParent(nodes, removeNodes, fqn) {
def node = nodes[fqn]
if (node != null) {
def parentFqn = node.parentFqn
if (parentFqn != null) {
removeNodes << fqn
def parentNode = nodes[parentFqn]
parentNode.children[fqn] = node
adjustParent(nodes, removeNodes, parentFqn)
}
}
}
if (args.length != 2) {
throw new IllegalArgumentException("usage: ReverseHbmToEntityExcel [target.dir] [dist.path]")
}
use(Utils) {
new File(args[0]).eachFileRecurse { file ->
if (file.name =~ /.*\.hbm\.xml$/) {
def path = parser.parse(file)
def parentFqn = prop(path, "extends")?.text()
def classFqn = prop(path, "name")?.text()
def node = new ClassNode(fqn:classFqn, parentFqn: parentFqn, path:path)
nodes[classFqn] = node
}
}
def removeNodes = []
nodes.each {
adjustParent(nodes, removeNodes, it.key)
}
removeNodes.each { nodes.remove(it) }
}
def writeNode(node, writer, rowNumber, prefix = "") {
println "${prefix}${node.fqn}"
def number = writer.write(++rowNumber, node.path)
node.children.each {
number = writeNode(it.value, writer, number, prefix << "\t")
}
number
}
def writer = new Writer()
def rowNumber = 0
nodes.sort { a, b ->
a.key <=> b.key
}.each {
rowNumber = writeNode(it.value, writer, rowNumber)
}
writer.flush(args[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment