feat: Initial commit of the ActionBean generator plugin
This commit includes the basic project structure, the initial implementation of the plugin, and fixes for duplicate API calls and deprecated code.
This commit is contained in:
163
src/main/java/com/sdk/actionbean/generator/GenerateAction.java
Normal file
163
src/main/java/com/sdk/actionbean/generator/GenerateAction.java
Normal file
@@ -0,0 +1,163 @@
|
||||
package com.sdk.actionbean.generator;
|
||||
|
||||
import com.intellij.database.model.*;
|
||||
import com.intellij.database.psi.*;
|
||||
import com.intellij.database.util.*;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.*;
|
||||
import com.intellij.openapi.fileChooser.*;
|
||||
import com.intellij.openapi.project.*;
|
||||
import com.intellij.openapi.ui.*;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.*;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.*;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class GenerateAction extends AnAction {
|
||||
|
||||
private static final LinkedHashMap<String, String> TYPE_MAPPING = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
TYPE_MAPPING.put("bigint", "Long");
|
||||
TYPE_MAPPING.put("bit", "Boolean");
|
||||
TYPE_MAPPING.put("boolean", "Boolean");
|
||||
TYPE_MAPPING.put("date", "java.util.Date");
|
||||
TYPE_MAPPING.put("decimal", "java.math.BigDecimal");
|
||||
TYPE_MAPPING.put("double", "Double");
|
||||
TYPE_MAPPING.put("float", "Float");
|
||||
TYPE_MAPPING.put("integer", "Integer");
|
||||
TYPE_MAPPING.put("numeric", "java.math.BigDecimal");
|
||||
TYPE_MAPPING.put("smallint", "Short");
|
||||
TYPE_MAPPING.put("timestamp", "java.util.Date");
|
||||
TYPE_MAPPING.put("text", "String");
|
||||
TYPE_MAPPING.put("time", "java.util.Date");
|
||||
TYPE_MAPPING.put("tinyint", "Byte");
|
||||
TYPE_MAPPING.put("varchar2", "String");
|
||||
TYPE_MAPPING.put("varchar", "String");
|
||||
TYPE_MAPPING.put("char", "String");
|
||||
}
|
||||
|
||||
private static final Map<String,String> userDefType = new HashMap<>();
|
||||
|
||||
private String getRawType(String columnDefinition ) {
|
||||
for (String rawType : TYPE_MAPPING.keySet()) {
|
||||
if (columnDefinition.contains(rawType)) {
|
||||
return rawType;
|
||||
}
|
||||
}
|
||||
return "varchar";
|
||||
}
|
||||
|
||||
private void createUserDefineType(DbTable table) {
|
||||
if (userDefType.isEmpty()) {
|
||||
String schemaName = table.getParent() != null ? table.getParent().getName() : "";
|
||||
DasUtil.getCatalogObject(table).getDasChildren(ObjectKind.SCHEMA).forEach(schema -> {
|
||||
if (schema.getName().equals("public") || schema.getName().equals(schemaName)) {
|
||||
schema.getDasChildren(ObjectKind.OBJECT_TYPE).forEach(domain -> {
|
||||
String domainName = domain.getName();
|
||||
String domainScript = ((DbObject) domain).getText();
|
||||
userDefType.put(domainName, getRawType(domainScript));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private String getFieldType(String columnType) {
|
||||
columnType = columnType.toLowerCase();
|
||||
String fieldType = TYPE_MAPPING.get(columnType );
|
||||
if (fieldType == null) {
|
||||
fieldType = TYPE_MAPPING.getOrDefault(userDefType.getOrDefault(fieldType,"varchar"),"Object" );
|
||||
}
|
||||
return fieldType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
PsiElement[] psiElements = e.getData(LangDataKeys.PSI_ELEMENT_ARRAY);
|
||||
if (project == null || psiElements == null || psiElements.length == 0) {
|
||||
return;
|
||||
}
|
||||
for (PsiElement psiElement : psiElements) {
|
||||
if (psiElement instanceof DbTable) {
|
||||
generate((DbTable) psiElement, project);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generate(DbTable table, Project project) {
|
||||
if (userDefType.isEmpty()) {
|
||||
createUserDefineType(table);
|
||||
}
|
||||
|
||||
String className = toCamelCase(table.getName(), true);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("public class ").append(className).append(" {\n\n");
|
||||
|
||||
JBIterable<? extends DasColumn> columns = DasUtil.getColumns(table);
|
||||
for (DasColumn column : columns) {
|
||||
String fieldName = toCamelCase(column.getName(), false);
|
||||
String fieldType = getFieldType(column.getDasType().toDataType().typeName);
|
||||
builder.append(" private ").append(fieldType).append(" ").append(fieldName).append(";\n");
|
||||
}
|
||||
builder.append("\n");
|
||||
|
||||
for (DasColumn column : columns) {
|
||||
String fieldName = toCamelCase(column.getName(), false);
|
||||
String fieldType = getFieldType(column.getDasType().toDataType().typeName);
|
||||
String capitalizedFieldName = capitalize(fieldName);
|
||||
|
||||
builder.append(" public ").append(fieldType).append(" get").append(capitalizedFieldName).append("() {\n");
|
||||
builder.append(" return ").append(fieldName).append(";\n");
|
||||
builder.append(" }\n\n");
|
||||
|
||||
builder.append(" public void set").append(capitalizedFieldName).append("(").append(fieldType).append(" ").append(fieldName).append(") {\n");
|
||||
builder.append(" this.").append(fieldName).append(" = ").append(fieldName).append(";\n");
|
||||
builder.append(" }\n\n");
|
||||
}
|
||||
|
||||
builder.append("}");
|
||||
|
||||
FileSaverDescriptor descriptor = new FileSaverDescriptor("Save JavaBean", "Save the generated JavaBean to a file", "java");
|
||||
FileSaverDialog saveFileDialog = FileChooserFactory.getInstance().createSaveFileDialog(descriptor, project);
|
||||
VirtualFileWrapper fileWrapper = saveFileDialog.save((VirtualFile) null, className + ".java");
|
||||
VirtualFile virtualFile = fileWrapper != null ? fileWrapper.getVirtualFile() : null;
|
||||
|
||||
if (virtualFile != null) {
|
||||
ApplicationManager.getApplication().runWriteAction(() -> {
|
||||
try (OutputStream outputStream = virtualFile.getOutputStream(this)) {
|
||||
outputStream.write(builder.toString().getBytes(StandardCharsets.UTF_8));
|
||||
} catch (IOException ex) {
|
||||
Messages.showErrorDialog(project, "Error saving file: " + ex.getMessage(), "Error");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private String toCamelCase(String s, boolean capitalizeFirst) {
|
||||
String[] parts = s.split("_");
|
||||
StringBuilder camelCaseString = new StringBuilder();
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
String part = parts[i];
|
||||
if (i == 0 && !capitalizeFirst) {
|
||||
camelCaseString.append(part.toLowerCase());
|
||||
} else {
|
||||
camelCaseString.append(capitalize(part));
|
||||
}
|
||||
}
|
||||
return camelCaseString.toString();
|
||||
}
|
||||
|
||||
private String capitalize(String s) {
|
||||
if (s == null || s.isEmpty()) {
|
||||
return s;
|
||||
}
|
||||
return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.sdk.actionbean.generator;
|
||||
|
||||
import com.intellij.database.psi.DbTable;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileChooserFactory;
|
||||
import com.intellij.openapi.fileChooser.PathChooserDialog;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.project.ProjectUtil;
|
||||
import com.intellij.openapi.roots.PackageIndex;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class GenerateBeanAction extends AnAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
PsiElement[] psiElements = e.getData(LangDataKeys.PSI_ELEMENT_ARRAY);
|
||||
if (project == null || psiElements == null || psiElements.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileChooserDescriptor descriptor = new FileChooserDescriptor(false,true,false,false,false,false);
|
||||
PathChooserDialog pathChooser = FileChooserFactory.getInstance().createPathChooser(descriptor, project, null);
|
||||
VirtualFile baseDir = ProjectUtil.guessProjectDir(project);
|
||||
pathChooser.choose(baseDir, virtualFiles -> {
|
||||
String packageName = getSelectedPackage(project, virtualFiles.getFirst());
|
||||
|
||||
ArrayList<DbTable> tables = new ArrayList<>();
|
||||
for (PsiElement psiElement : psiElements) {
|
||||
if (psiElement instanceof DbTable) {
|
||||
tables.add((DbTable) psiElement);
|
||||
}
|
||||
}
|
||||
runGenerator(project, tables, packageName);
|
||||
});
|
||||
}
|
||||
|
||||
private void runGenerator(Project project,ArrayList<DbTable> tables, String packageName) {
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Generate Database Action Models ...") {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
ApplicationManager.getApplication().invokeLater(() ->
|
||||
WriteCommandAction.runWriteCommandAction(project, () -> {
|
||||
try {
|
||||
new GeneratorServices(project,tables,packageName).execute(indicator);
|
||||
} catch (Exception ex) {
|
||||
showError(project, "An error occurred during code generation: " + ex.getMessage());
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showError(Project project, String message) {
|
||||
ApplicationManager.getApplication().invokeLater(() -> Messages.showErrorDialog(project, message, "Generation Failed"));
|
||||
}
|
||||
|
||||
private String getSelectedPackage(Project project, VirtualFile selectDirectory) {
|
||||
if (selectDirectory == null) return "";
|
||||
String packageName = PackageIndex.getInstance(project).getPackageNameByDirectory(selectDirectory);
|
||||
return packageName;
|
||||
}
|
||||
|
||||
private VirtualFile findSourceRoot(Project project, String packageName) {
|
||||
for (VirtualFile root : ProjectRootManager.getInstance(project).getContentSourceRoots()) {
|
||||
if (root.isDirectory() && !root.getName().equals("resources")) {
|
||||
return root;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.sdk.actionbean.generator;
|
||||
|
||||
import com.intellij.database.psi.DbTable;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GeneratorServices {
|
||||
|
||||
private final String packageName;
|
||||
private final Project project;
|
||||
private final ArrayList<DbTable> tables;
|
||||
|
||||
public GeneratorServices(Project project, ArrayList<DbTable> tables, String packageName) {
|
||||
this.tables = tables;
|
||||
this.project = project;
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
public void execute(@NotNull ProgressIndicator indicator) {
|
||||
// String packagePath = packageName.replace('.', '/');
|
||||
// VirtualFile packageDir = createPackageDirs(sourceRoot, packagePath);
|
||||
//
|
||||
// Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
|
||||
// cfg.setClassForTemplateLoading(this.getClass(), "/templates");
|
||||
// cfg.setDefaultEncoding("UTF-8");
|
||||
// cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||
// Template template = cfg.getTemplate("actionBean.ftl");
|
||||
//
|
||||
// DatabaseMetaData metaData = conn.getMetaData();
|
||||
// try (ResultSet tables = metaData.getTables(null, dbSchema.toUpperCase(), tablePattern, new String[]{"TABLE"})) {
|
||||
// while (tables.next()) {
|
||||
// String tableName = tables.getString("TABLE_NAME");
|
||||
// indicator.setText("Processing table: " + tableName);
|
||||
//
|
||||
// Map<String, Object> model = createModelForTable(metaData, tableName, dbSchema);
|
||||
//
|
||||
// VirtualFile outputFile = packageDir.findOrCreateChildData(this, model.get("className") + ".java");
|
||||
// try (Writer writer = new OutputStreamWriter(outputFile.getOutputStream(this))) {
|
||||
// template.process(model, writer);
|
||||
// }
|
||||
// indicator.setText2("Generated " + outputFile.getName());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private Map<String, Object> createModelForTable(DatabaseMetaData metaData, String tableName, String dbSchema) throws SQLException {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
model.put("packageName", packageName);
|
||||
model.put("tableName", tableName);
|
||||
model.put("className", tableName);
|
||||
model.put("dbSchema", dbSchema);
|
||||
|
||||
List<Map<String, Object>> columns = new ArrayList<>();
|
||||
Set<String> primaryKeys = new HashSet<>();
|
||||
try (ResultSet pks = metaData.getPrimaryKeys(null, dbSchema.toUpperCase(), tableName)) {
|
||||
while (pks.next()) {
|
||||
primaryKeys.add(pks.getString("COLUMN_NAME"));
|
||||
}
|
||||
}
|
||||
|
||||
try (ResultSet cols = metaData.getColumns(null, dbSchema.toUpperCase(), tableName, "%")) {
|
||||
while (cols.next()) {
|
||||
Map<String, Object> colModel = new HashMap<>();
|
||||
String colName = cols.getString("COLUMN_NAME");
|
||||
int dataType = cols.getInt("DATA_TYPE");
|
||||
|
||||
colModel.put("name", colName);
|
||||
colModel.put("isPk", primaryKeys.contains(colName));
|
||||
colModel.put("customType", mapJdbcType(dataType));
|
||||
columns.add(colModel);
|
||||
}
|
||||
}
|
||||
|
||||
model.put("columns", columns);
|
||||
model.put("fieldList", columns.stream().map(c -> (String) c.get("name")).collect(Collectors.joining(",")));
|
||||
model.put("keyList", String.join(",", primaryKeys));
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private VirtualFile createPackageDirs(VirtualFile sourceRoot, String path) throws java.io.IOException {
|
||||
VirtualFile current = sourceRoot;
|
||||
for (String part : path.split("/")) {
|
||||
VirtualFile child = current.findChild(part);
|
||||
if (child == null) {
|
||||
child = current.createChildDirectory(this, part);
|
||||
}
|
||||
current = child;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
private String mapJdbcType(int jdbcType) {
|
||||
return switch (jdbcType) {
|
||||
case Types.NUMERIC, Types.DECIMAL, Types.INTEGER, Types.BIGINT, Types.SMALLINT, Types.TINYINT, Types.FLOAT, Types.DOUBLE -> "NUMBER";
|
||||
case Types.DATE, Types.TIMESTAMP, Types.TIMESTAMP_WITH_TIMEZONE -> "DATE";
|
||||
default -> "STRING";
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user