Using IDEA to connect database to generate entity class and customize Groovy script file

Keywords: Oracle Database Java MySQL

Introduction: Now 2019, there are many plug-ins or editors that support the automatic generation of data entity classes based on data tables, such as IDEA, MyBatis code generation tools, etc. This article describes how to use IDEA groovy script file to generate JPA annotated entity classes.

Reference link: Intellij IDEA Generates Annotated Entity Class Detailed Step through Database Tables - Sad Autumn Wind

First, use IDEA to connect to the database

  • Attention should be paid to:

    1. The official version of IDEA has this function, and the community version of IDEA has this function.
    2. The IDEA version of the demo image is 2018.3. There may be minor differences between different versions of the interface.
  1. Create a new data connection

    • If not, you can open the top menu bar: View-Tool Window-Database
    • New Oracle database is the same operation

  1. Configure Data Connection

    1. Fill in a connection name, whatever you like.
    2. No choices, just default.
    3. Fill in the IP address of the database connection, for example, the local database can fill in: localhost or 127.0.0.1
    4. Fill in the open port number of the database. If it is not set, the default is 3306.
    5. Fill in the name of the database you need to connect to
    6. Fill in the username of the database
    7. Fill in the database password
    8. Here's a driver that needs to be clicked to download. In the picture, it's already downloaded.
    9. Fill in your own database connection url, and then click on the button 9 to test the connection. If the local connection fails, check whether the mysql service is opened or not.

Two methods of creating entity classes in IDEA

(1) If you just create simple entity classes with attributes, getters, setters, and no JPA/Hibernate annotations for entity classes

  1. Click to open the data connection you just created
  2. Open schemas and find tables that you need to create entity classes (you can use ctrl or shift multiple selections)
  3. Right-click: Scripted Extensions - Generate POJOs.groovy
  4. Selecting the generation path is OK
  • Note

    • The generated package name may have problems. The default is package com.sample, which needs to be modified manually by itself.

(2) Hibernate/Jpa framework is used, annotated entity classes are needed, and Idea provides corresponding methods.

  • Add JPA module

    1. Open project structure
    2. Open the module and click + to add the module
    3. Select JPA
    4. Close the project structure by clicking on the lower right corner to confirm

  • Generating Annotated Entity Class-1 with Persistence Tool

    1. If the previous step is OK, the Persistence toolbar appears in the lower left sidebar of IDEA
    2. Open the Persistence toolbar, right-click the project: Generate Persistence Mapping - By Database Schema

  • Generating annotated entity class-2 using Persistence tool
  1. Select a database connection
  2. Select the package where the generated class resides
  3. Select the table to be generated
  4. Select the fields to be generated (fields are selected by default except foreign keys)
  5. Modify the property name to be generated
  6. Modify the attribute type to be generated
  7. Check it to generate annotated entity classes

The generated class instance is as follows

Third, further, use your own Groovy to generate annotated entity classes

Two methods of generating entity classes using IDEA are introduced, each with its advantages and disadvantages.
Generating non-annotated entity classes is simple and efficient, but the disadvantage is that using Jpa/Hibernate framework is not suitable.
Generating annotated entity classes can generate annotated entity classes, but the disadvantage is that the annotations of generated entity classes may not conform to our annotations and can only be generated under the current project package. Faced with some complex databases such as Oracle, many system tables will be displayed and table space switching is not convenient.
We know that Idea generates non-annotated entity classes through Groovy script files. We can also find this file. Can we modify this file to generate annotated entity classes?

(1) The benefits of using your own Groovy to generate annotated entity classes

  1. In the Database toolbar, the operation is simple and convenient.
  2. You can edit the script by yourself so that the generated entity class can meet your own customization requirements.
  3. When generating entity classes from databases such as Oracle, the influence of system tables can be avoided and table spaces can be selected for operation by themselves.
  4. It can be generated anywhere on the computer without restriction.

(2) Deficiencies of using Groovy to generate annotated entity classes

  1. @ author's name needs to be modified by himself
  2. @ Table(Schema=") table space name can not be read, you need to modify the script, set the table space name (mysql can directly delete the definition of this property) (IDEA's Persistence tool can read (Schema=""attribute and generate, but we do not know how to get it)
  3. @ Id's primary key generation method is unknown and needs to be determined after generation (mysql users can directly modify the script to set the primary key generation method, but Oracle users need to generate entity classes and then confirm one by one)

(3) Use your own Groovy to generate annotated entity classes where you can continue to improve

1. If you need hashcode() and equals() methods, modify the script to automatically generate it

(4) Create a new Groovy script file

  1. In the Database toolbar, right-click: Scripted Extensions - Go to Scripts Directory
  2. Create a new Generate MyPOJOs.groovy in the directory

  1. Add the contents

    1. // 1. Where idea is changed for its own name, the author's name can be changed for his own.
    2. // 2. schema ="Add your own table space name after it (mysql can be added without this schema attribute). You can modify it here as prompted.
import com.intellij.database.model.DasTable
import com.intellij.database.model.ObjectKind
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil

import java.text.SimpleDateFormat

/*
 * Available context bindings:
 *   SELECTION   Iterable<DasObject>
 *   PROJECT     project
 *   FILES       files helper
 */
packageName = ""
typeMapping = [
        (~/(?i)tinyint|smallint|mediumint/)      : "Integer",
        (~/(?i)int/)                             : "Long",
        (~/(?i)bool|bit/)                        : "Boolean",
        (~/(?i)float|double|decimal|real/)       : "Double",
        (~/(?i)datetime|timestamp|date|time/)    : "Date",
        (~/(?i)blob|binary|bfile|clob|raw|image/): "InputStream",
        (~/(?i)/)                                : "String"
]


FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
    SELECTION.filter { it instanceof DasTable && it.getKind() == ObjectKind.TABLE }.each { generate(it, dir) }
}

def generate(table, dir) {
    def className = javaName(table.getName(), true)
    def fields = calcFields(table)
    packageName = getPackageName(dir)
    PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(dir, className + ".java")), "UTF-8"))
    printWriter.withPrintWriter { out -> generate(out, className, fields, table) }

//    new File(dir, className + ".java").withPrintWriter { out -> generate(out, className, fields,table) }
}

// Get the folder path where the package is located
def getPackageName(dir) {
    return dir.toString().replaceAll("\\\\", ".").replaceAll("/", ".").replaceAll("^.*src(\\.main\\.java\\.)?", "") + ";"
}

def generate(out, className, fields, table) {
    out.println "package $packageName"
    out.println ""
    out.println "import javax.persistence.Column;"
    out.println "import javax.persistence.Entity;"
    out.println "import javax.persistence.Table;"
    out.println "import javax.persistence.Id;"
    out.println "import javax.persistence.GeneratedValue;"
    out.println "import java.io.Serializable;"
    Set types = new HashSet()

    fields.each() {
        types.add(it.type)
    }

    if (types.contains("Date")) {
        out.println "import java.util.Date;"
    }

    if (types.contains("InputStream")) {
        out.println "import java.io.InputStream;"
    }
    out.println ""
    out.println "/**\n" +
            " * @Description  \n" +
            " * @Author  idea\n" + //1. Modify idea to your name
            " * @Date " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + " \n" +
            " */"
    out.println ""
    out.println "@Entity"
    out.println "@Table ( name =\"" + table.getName() + "\" , schema = \"\")" //2. schema ="Add your own table space name after it (mysql can be added without this schema attribute)
    out.println "public class $className  implements Serializable {"
    out.println ""
    out.println genSerialID()
    fields.each() {
        out.println ""
        // Output annotations
        if (isNotEmpty(it.commoent)) {
            out.println "\t/**"
            out.println "\t * ${it.commoent.toString()}"
            out.println "\t */"
        }

        if ((it.annos+"").indexOf("[@Id]") >= 0) out.println "\t@Id"

        if (it.annos != "") out.println "   ${it.annos.replace("[@Id]", "")}"


        // Output member variables
        out.println "\tprivate ${it.type} ${it.name};"
    }

    // Output get/set method
    fields.each() {
        out.println ""
        out.println "\tpublic ${it.type} get${it.name.capitalize()}() {"
        out.println "\t\treturn this.${it.name};"
        out.println "\t}"
        out.println ""

        out.println "\tpublic void set${it.name.capitalize()}(${it.type} ${it.name}) {"
        out.println "\t\tthis.${it.name} = ${it.name};"
        out.println "\t}"
    }

    // Output toString method
    out.println ""
    out.println "\t@Override"
    out.println "\tpublic String toString() {"
    out.println "\t\treturn \"TpApiConfig{\" +"
    fields.each() {
        out.println "\t\t\t\t\"${it.name}='\" + ${it.name} + '\\'' +"
    }
    out.println "\t\t\t\t'}';"
    out.println "\t}"

    out.println ""
    out.println "}"
}

def calcFields(table) {
    DasUtil.getColumns(table).reduce([]) { fields, col ->
        def spec = Case.LOWER.apply(col.getDataType().getSpecification())

        def typeStr = typeMapping.find { p, t -> p.matcher(spec).find() }.value
        def comm = [
                colName : col.getName(),
                name    : javaName(col.getName(), false),
                type    : typeStr,
                commoent: col.getComment(),
                annos   : "\t@Column(name = \"" + col.getName() + "\" )"]
        if ("id".equals(Case.LOWER.apply(col.getName())))
            comm.annos += ["@Id"]
        fields += [comm]
    }
}

// It has been modified to use javaName, which can be changed to javaClassName in def className = javaName(table.getName(), true) if necessary
// Processing class names (here because my tables are all named t_, so I need to deal with removing the T at the beginning of generating class names.
// If you don't need it, look for a place where Java ClassName is used and change it to Java Name.
def javaClassName(str, capitalize) {
    def s = com.intellij.psi.codeStyle.NameUtil.splitNameIntoWords(str)
            .collect { Case.LOWER.apply(it).capitalize() }
            .join("")
            .replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, "_")
    // Remove the starting T http://developer.51cto.com/art/200906/129168.htm
    s = s[1..s.size() - 1]
    capitalize || s.length() == 1 ? s : Case.LOWER.apply(s[0]) + s[1..-1]
}

def javaName(str, capitalize) {
//    def s = str.split(/(?<=[^\p{IsLetter}])/).collect { Case.LOWER.apply(it).capitalize() }
//            .join("").replaceAll(/[^\p{javaJavaIdentifierPart}]/, "_")
//    capitalize || s.length() == 1? s : Case.LOWER.apply(s[0]) + s[1..-1]
    def s = com.intellij.psi.codeStyle.NameUtil.splitNameIntoWords(str)
            .collect { Case.LOWER.apply(it).capitalize() }
            .join("")
            .replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, "_")
    capitalize || s.length() == 1 ? s : Case.LOWER.apply(s[0]) + s[1..-1]
}

def isNotEmpty(content) {
    return content != null && content.toString().trim().length() > 0
}

static String changeStyle(String str, boolean toCamel) {
    if (!str || str.size() <= 1)
        return str

    if (toCamel) {
        String r = str.toLowerCase().split('_').collect { cc -> Case.LOWER.apply(cc).capitalize() }.join('')
        return r[0].toLowerCase() + r[1..-1]
    } else {
        str = str[0].toLowerCase() + str[1..-1]
        return str.collect { cc -> ((char) cc).isUpperCase() ? '_' + cc.toLowerCase() : cc }.join('')
    }
}

static String genSerialID() {
    return "\tprivate static final long serialVersionUID =  " + Math.abs(new Random().nextLong()) + "L;"
}

  1. Right-click on the table and select the script you write to generate the entity class

The results are as follows:

Posted by Vex on Mon, 26 Aug 2019 01:33:39 -0700