From 633690d191f4670d1e5acbdf337d4b7b079d486b Mon Sep 17 00:00:00 2001
From: lorne <1991wangliang@gmail.com>
Date: Thu, 11 Dec 2025 19:50:50 +0800
Subject: [PATCH 1/3] add #167
---
.../example-app-cmd-domain/pom.xml | 2 +-
.../example-app/example-app-cmd-meta/pom.xml | 2 +-
example/example-app/example-app-query/pom.xml | 2 +-
example/example-app/pom.xml | 2 +-
.../example-domain-leave/pom.xml | 2 +-
.../example-domain-user/pom.xml | 2 +-
example/example-domain/pom.xml | 2 +-
.../example-infra/example-infra-flow/pom.xml | 2 +-
.../example-infra/example-infra-jpa/pom.xml | 2 +-
.../example-infra-security/pom.xml | 2 +-
example/example-infra/pom.xml | 2 +-
example/example-interface/pom.xml | 2 +-
example/example-server/pom.xml | 2 +-
example/pom.xml | 2 +-
pom.xml | 2 +-
springboot-starter-data-authorization/pom.xml | 2 +-
springboot-starter-data-fast/pom.xml | 7 +-
.../DynamicEntityClassBuilder.java | 302 ++++++++++++++++++
.../classloader/DynamicEntityClassLoader.java | 60 ++++
.../DynamicEntityClassLoaderContext.java | 27 ++
.../fast/dynamic/DynamicEntityBuilder.java | 187 +++++++++++
.../springboot/fast/metadata/EntityMeta.java | 134 ++++++++
.../dynamic/DynamicEntityBuilderTest.java | 63 ++++
springboot-starter-flow/pom.xml | 2 +-
springboot-starter-security/pom.xml | 2 +-
springboot-starter/pom.xml | 2 +-
26 files changed, 798 insertions(+), 20 deletions(-)
create mode 100644 springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassBuilder.java
create mode 100644 springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassLoader.java
create mode 100644 springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassLoaderContext.java
create mode 100644 springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilder.java
create mode 100644 springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/EntityMeta.java
create mode 100644 springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java
diff --git a/example/example-app/example-app-cmd-domain/pom.xml b/example/example-app/example-app-cmd-domain/pom.xml
index b8e909ae..86a1c254 100644
--- a/example/example-app/example-app-cmd-domain/pom.xml
+++ b/example/example-app/example-app-cmd-domain/pom.xml
@@ -6,7 +6,7 @@
com.codingapi.springboot
example-app
- 3.4.23
+ 3.4.24
../pom.xml
diff --git a/example/example-app/example-app-cmd-meta/pom.xml b/example/example-app/example-app-cmd-meta/pom.xml
index 3a87683c..c0ed3c91 100644
--- a/example/example-app/example-app-cmd-meta/pom.xml
+++ b/example/example-app/example-app-cmd-meta/pom.xml
@@ -6,7 +6,7 @@
com.codingapi.springboot
example-app
- 3.4.23
+ 3.4.24
../pom.xml
diff --git a/example/example-app/example-app-query/pom.xml b/example/example-app/example-app-query/pom.xml
index 8b1d030e..f9d5cd14 100644
--- a/example/example-app/example-app-query/pom.xml
+++ b/example/example-app/example-app-query/pom.xml
@@ -6,7 +6,7 @@
com.codingapi.springboot
example-app
- 3.4.23
+ 3.4.24
../pom.xml
diff --git a/example/example-app/pom.xml b/example/example-app/pom.xml
index 3c72466b..735483bf 100644
--- a/example/example-app/pom.xml
+++ b/example/example-app/pom.xml
@@ -6,7 +6,7 @@
com.codingapi.springboot
springboot-example
- 3.4.23
+ 3.4.24
../pom.xml
pom
diff --git a/example/example-domain/example-domain-leave/pom.xml b/example/example-domain/example-domain-leave/pom.xml
index 29de615f..d369d840 100644
--- a/example/example-domain/example-domain-leave/pom.xml
+++ b/example/example-domain/example-domain-leave/pom.xml
@@ -6,7 +6,7 @@
com.codingapi.springboot
example-domain
- 3.4.23
+ 3.4.24
../pom.xml
diff --git a/example/example-domain/example-domain-user/pom.xml b/example/example-domain/example-domain-user/pom.xml
index d89473f8..010e9712 100644
--- a/example/example-domain/example-domain-user/pom.xml
+++ b/example/example-domain/example-domain-user/pom.xml
@@ -6,7 +6,7 @@
com.codingapi.springboot
example-domain
- 3.4.23
+ 3.4.24
../pom.xml
diff --git a/example/example-domain/pom.xml b/example/example-domain/pom.xml
index 8bde6ca9..d0b4bf53 100644
--- a/example/example-domain/pom.xml
+++ b/example/example-domain/pom.xml
@@ -5,7 +5,7 @@
com.codingapi.springboot
springboot-example
- 3.4.23
+ 3.4.24
../pom.xml
4.0.0
diff --git a/example/example-infra/example-infra-flow/pom.xml b/example/example-infra/example-infra-flow/pom.xml
index 2b5e82f3..12e565f6 100644
--- a/example/example-infra/example-infra-flow/pom.xml
+++ b/example/example-infra/example-infra-flow/pom.xml
@@ -5,7 +5,7 @@
com.codingapi.springboot
example-infra
- 3.4.23
+ 3.4.24
../pom.xml
diff --git a/example/example-infra/example-infra-jpa/pom.xml b/example/example-infra/example-infra-jpa/pom.xml
index cc1d6e0a..07fa83dc 100644
--- a/example/example-infra/example-infra-jpa/pom.xml
+++ b/example/example-infra/example-infra-jpa/pom.xml
@@ -5,7 +5,7 @@
com.codingapi.springboot
example-infra
- 3.4.23
+ 3.4.24
../pom.xml
diff --git a/example/example-infra/example-infra-security/pom.xml b/example/example-infra/example-infra-security/pom.xml
index 1a05b954..d905d92a 100644
--- a/example/example-infra/example-infra-security/pom.xml
+++ b/example/example-infra/example-infra-security/pom.xml
@@ -6,7 +6,7 @@
com.codingapi.springboot
example-infra
- 3.4.23
+ 3.4.24
../pom.xml
diff --git a/example/example-infra/pom.xml b/example/example-infra/pom.xml
index bc3d7b13..a1d0acfc 100644
--- a/example/example-infra/pom.xml
+++ b/example/example-infra/pom.xml
@@ -6,7 +6,7 @@
com.codingapi.springboot
springboot-example
- 3.4.23
+ 3.4.24
../pom.xml
pom
diff --git a/example/example-interface/pom.xml b/example/example-interface/pom.xml
index 6c508ee9..f6d78dd0 100644
--- a/example/example-interface/pom.xml
+++ b/example/example-interface/pom.xml
@@ -6,7 +6,7 @@
com.codingapi.springboot
springboot-example
- 3.4.23
+ 3.4.24
example-interface
diff --git a/example/example-server/pom.xml b/example/example-server/pom.xml
index 073c8ee2..be3ef03c 100644
--- a/example/example-server/pom.xml
+++ b/example/example-server/pom.xml
@@ -5,7 +5,7 @@
springboot-example
com.codingapi.springboot
- 3.4.23
+ 3.4.24
4.0.0
diff --git a/example/pom.xml b/example/pom.xml
index 05807946..24b4ebfb 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -19,7 +19,7 @@
springboot-example
- 3.4.23
+ 3.4.24
springboot-example
springboot-example project for Spring Boot
diff --git a/pom.xml b/pom.xml
index 776f897e..861192da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
com.codingapi.springboot
springboot-parent
- 3.4.23
+ 3.4.24
https://github.com/codingapi/springboot-framewrok
springboot-parent
diff --git a/springboot-starter-data-authorization/pom.xml b/springboot-starter-data-authorization/pom.xml
index a5282ee4..e6116bf4 100644
--- a/springboot-starter-data-authorization/pom.xml
+++ b/springboot-starter-data-authorization/pom.xml
@@ -6,7 +6,7 @@
com.codingapi.springboot
springboot-parent
- 3.4.23
+ 3.4.24
springboot-starter-data-authorization
diff --git a/springboot-starter-data-fast/pom.xml b/springboot-starter-data-fast/pom.xml
index 69b340a6..82e10ab5 100644
--- a/springboot-starter-data-fast/pom.xml
+++ b/springboot-starter-data-fast/pom.xml
@@ -5,7 +5,7 @@
springboot-parent
com.codingapi.springboot
- 3.4.23
+ 3.4.24
4.0.0
@@ -20,6 +20,11 @@
+
+ net.bytebuddy
+ byte-buddy
+
+
org.springframework.boot
spring-boot-starter-web
diff --git a/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassBuilder.java b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassBuilder.java
new file mode 100644
index 00000000..05c2dcd1
--- /dev/null
+++ b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassBuilder.java
@@ -0,0 +1,302 @@
+package com.codingapi.springboot.fast.classloader;
+
+import com.codingapi.springboot.fast.metadata.EntityMeta;
+import jakarta.persistence.*;
+import net.bytebuddy.ByteBuddy;
+import net.bytebuddy.description.annotation.AnnotationDescription;
+import net.bytebuddy.description.modifier.Visibility;
+import net.bytebuddy.dynamic.DynamicType;
+import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
+import net.bytebuddy.implementation.FieldAccessor;
+import org.hibernate.annotations.Comment;
+import org.springframework.util.StringUtils;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 动态实体构建器 - 基于 EntityClass 元数据
+ */
+public class DynamicEntityClassBuilder {
+
+ /**
+ * 根据 EntityClass 构建动态实体
+ */
+ public static Class> buildDynamicEntity(EntityMeta entityMeta) {
+ if (entityMeta == null || entityMeta.getClassName() == null) {
+ throw new IllegalArgumentException("Entity metadata cannot be null");
+ }
+
+ try {
+ DynamicType.Builder> builder = new ByteBuddy()
+ .subclass(Object.class)
+ .name(entityMeta.getClassName())
+ .implement(Serializable.class)
+ .annotateType(buildEntityAnnotations(entityMeta));
+
+ // 添加字段
+ boolean hasPrimaryKey = false;
+ for (EntityMeta.ColumnMeta column : entityMeta.getColumns()) {
+ builder = addColumnField(builder, column);
+ if (column.isPrimaryKey()) {
+ hasPrimaryKey = true;
+ }
+ }
+
+ // 如果没有主键,添加默认ID字段
+ if (!hasPrimaryKey) {
+ builder = addDefaultIdField(builder);
+ }
+
+
+ Class> clazz = builder.make()
+ .load(DynamicEntityClassBuilder.class.getClassLoader(),
+ ClassLoadingStrategy.Default.WRAPPER)
+ .getLoaded();
+
+ DynamicEntityClassLoaderContext.getInstance().registerClass(clazz);
+
+ return clazz;
+
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to build dynamic entity: " +
+ entityMeta.getClassName(), e);
+ }
+ }
+
+ /**
+ * 构建实体类注解
+ */
+ private static AnnotationDescription[] buildEntityAnnotations(EntityMeta entityMeta) {
+ List annotations = new ArrayList<>();
+
+ // @Entity 注解
+ annotations.add(AnnotationDescription.Builder.ofType(Entity.class).build());
+
+ // @Table 注解
+ if (entityMeta.getTable() != null) {
+ AnnotationDescription.Builder tableBuilder =
+ AnnotationDescription.Builder.ofType(Table.class);
+
+ EntityMeta.TableMeta tableMeta = entityMeta.getTable();
+ if (tableMeta.getName() != null && !tableMeta.getName().isEmpty()) {
+ tableBuilder = tableBuilder.define("name", tableMeta.getName());
+ }
+ if (tableMeta.getCatalog() != null && !tableMeta.getCatalog().isEmpty()) {
+ tableBuilder = tableBuilder.define("catalog", tableMeta.getCatalog());
+ }
+ if (tableMeta.getSchema() != null && !tableMeta.getSchema().isEmpty()) {
+ tableBuilder = tableBuilder.define("schema", tableMeta.getSchema());
+ }
+
+ annotations.add(tableBuilder.build());
+ }
+
+ // @Comment 注解 - 注释应该放在类上,而不是表注解上
+ if (entityMeta.getTable() != null && StringUtils.hasText(entityMeta.getTable().getComment())) {
+ AnnotationDescription.Builder commentBuilder =
+ AnnotationDescription.Builder.ofType(Comment.class);
+
+ EntityMeta.TableMeta tableMeta = entityMeta.getTable();
+ commentBuilder = commentBuilder.define("value", tableMeta.getComment());
+ annotations.add(commentBuilder.build());
+ }
+
+ return annotations.toArray(new AnnotationDescription[0]);
+ }
+
+ /**
+ * 添加字段
+ */
+ private static DynamicType.Builder> addColumnField(DynamicType.Builder> builder,
+ EntityMeta.ColumnMeta columnMeta) {
+ // 确定字段类型
+ Class> fieldType = columnMeta.getType();
+
+ // 构建字段名(转换驼峰命名)
+ String fieldName = convertToCamelCase(columnMeta.getName());
+
+
+
+ // 构建字段注解
+ List fieldAnnotations =
+ buildFieldAnnotations(columnMeta, fieldName);
+
+ // 开始定义字段
+ DynamicType.Builder> fieldBuilder = builder;
+
+
+ if (fieldAnnotations.isEmpty()) {
+ fieldBuilder = fieldBuilder.defineField(fieldName, fieldType, Visibility.PRIVATE);
+ }else {
+ fieldBuilder = fieldBuilder.defineField(fieldName, fieldType, Visibility.PRIVATE)
+ .annotateField(fieldAnnotations.toArray(new AnnotationDescription[0]));
+ }
+
+ // 添加 getter 和 setter
+ String capitalizedFieldName = capitalize(fieldName);
+ String getterName = "get" + capitalizedFieldName;
+ String setterName = "set" + capitalizedFieldName;
+
+ // 布尔类型特殊处理
+ if (fieldType == Boolean.class || fieldType == Boolean.TYPE) {
+ getterName = "is" + capitalizedFieldName;
+ }
+
+ fieldBuilder = fieldBuilder
+ .defineMethod(getterName, fieldType, Visibility.PUBLIC)
+ .intercept(FieldAccessor.ofField(fieldName));
+
+ fieldBuilder = fieldBuilder
+ .defineMethod(setterName, void.class, Visibility.PUBLIC)
+ .withParameter(fieldType)
+ .intercept(FieldAccessor.ofField(fieldName));
+
+ return fieldBuilder;
+ }
+
+ /**
+ * 构建字段注解
+ */
+ private static List buildFieldAnnotations(
+ EntityMeta.ColumnMeta columnMeta, String fieldName) {
+
+ List annotations = new ArrayList<>();
+
+ // @Id 注解
+ if (columnMeta.isPrimaryKey()) {
+ annotations.add(AnnotationDescription.Builder.ofType(Id.class).build());
+
+ // @GeneratedValue 注解
+ if (columnMeta.getGeneratedValue() != null) {
+ EntityMeta.GeneratedValueMeta genMeta = columnMeta.getGeneratedValue();
+ AnnotationDescription.Builder genBuilder =
+ AnnotationDescription.Builder.ofType(GeneratedValue.class);
+
+ if (genMeta.getStrategy() != null) {
+ genBuilder = genBuilder.define("strategy", genMeta.getStrategy());
+ }
+
+ if (genMeta.getGenerator() != null && !genMeta.getGenerator().isEmpty()) {
+ genBuilder = genBuilder.define("generator", genMeta.getGenerator());
+ }
+
+ annotations.add(genBuilder.build());
+ }
+ }
+
+ // @Column 注解
+ AnnotationDescription.Builder columnBuilder =
+ AnnotationDescription.Builder.ofType(Column.class);
+
+ columnBuilder = columnBuilder
+ .define("name", columnMeta.getName())
+ .define("nullable", columnMeta.isNullable())
+ .define("unique", columnMeta.isUnique())
+ .define("insertable", columnMeta.isInsertable())
+ .define("updatable", columnMeta.isUpdatable());
+
+ if (columnMeta.getLength() > 0) {
+ columnBuilder = columnBuilder.define("length", columnMeta.getLength());
+ }
+ if (columnMeta.getPrecision() > 0) {
+ columnBuilder = columnBuilder.define("precision", columnMeta.getPrecision());
+ }
+ if (columnMeta.getScale() > 0) {
+ columnBuilder = columnBuilder.define("scale", columnMeta.getScale());
+ }
+ if (columnMeta.getColumnDefinition() != null &&
+ !columnMeta.getColumnDefinition().isEmpty()) {
+ columnBuilder = columnBuilder.define("columnDefinition",
+ columnMeta.getColumnDefinition());
+ }
+
+ annotations.add(columnBuilder.build());
+
+ // @Comment 注解
+ if (StringUtils.hasText(columnMeta.getComment())) {
+ annotations.add(AnnotationDescription.Builder.ofType(Comment.class)
+ .define("value", columnMeta.getComment())
+ .build());
+ }
+
+ return annotations;
+ }
+
+ /**
+ * 添加默认ID字段 - 修正版本
+ */
+ private static DynamicType.Builder> addDefaultIdField(DynamicType.Builder> builder) {
+
+
+ // 创建字段注解
+ List fieldAnnotations = new ArrayList<>();
+ fieldAnnotations.add(AnnotationDescription.Builder.ofType(Id.class).build());
+
+ // @GeneratedValue 注解
+ AnnotationDescription.Builder genBuilder =
+ AnnotationDescription.Builder.ofType(GeneratedValue.class);
+ genBuilder = genBuilder.define("strategy", GenerationType.IDENTITY);
+ fieldAnnotations.add(genBuilder.build());
+
+ // @Column 注解
+ AnnotationDescription.Builder columnBuilder =
+ AnnotationDescription.Builder.ofType(Column.class);
+ columnBuilder = columnBuilder
+ .define("name", "id")
+ .define("nullable", false);
+ fieldAnnotations.add(columnBuilder.build());
+
+ // 应用字段注解
+ builder = builder.defineField("id", Long.class, Visibility.PRIVATE).annotateField(fieldAnnotations.toArray(new AnnotationDescription[0]));
+
+ // 添加 getter 和 setter
+ builder = builder
+ .defineMethod("getId", Long.class, Visibility.PUBLIC)
+ .intercept(FieldAccessor.ofField("id"))
+ .defineMethod("setId", void.class, Visibility.PUBLIC)
+ .withParameter(Long.class)
+ .intercept(FieldAccessor.ofField("id"));
+
+ return builder;
+ }
+
+ /**
+ * 转换为驼峰命名
+ */
+ private static String convertToCamelCase(String name) {
+ if (name == null || name.isEmpty()) {
+ return name;
+ }
+
+ // 处理下划线命名
+ if (name.contains("_")) {
+ StringBuilder result = new StringBuilder();
+ String[] parts = name.split("_");
+ if (parts.length > 0) {
+ result.append(parts[0].toLowerCase());
+
+ for (int i = 1; i < parts.length; i++) {
+ if (!parts[i].isEmpty()) {
+ result.append(Character.toUpperCase(parts[i].charAt(0)));
+ if (parts[i].length() > 1) {
+ result.append(parts[i].substring(1).toLowerCase());
+ }
+ }
+ }
+ }
+ return result.toString();
+ }
+
+ // 已经是驼峰命名,首字母小写
+ return Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ }
+
+ private static String capitalize(String str) {
+ if (str == null || str.isEmpty()) {
+ return str;
+ }
+ return Character.toUpperCase(str.charAt(0)) + str.substring(1);
+ }
+}
\ No newline at end of file
diff --git a/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassLoader.java b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassLoader.java
new file mode 100644
index 00000000..202a80dc
--- /dev/null
+++ b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassLoader.java
@@ -0,0 +1,60 @@
+package com.codingapi.springboot.fast.classloader;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+class DynamicEntityClassLoader extends ClassLoader {
+
+ private final Map> dynamicClasses = new ConcurrentHashMap<>();
+
+ public DynamicEntityClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ public void registerClass(String className, Class> clazz) {
+ dynamicClasses.put(className, clazz);
+ }
+
+ public void registerClass(Class> clazz) {
+ this.registerClass(clazz.getName(), clazz);
+ }
+
+
+ @Override
+ protected Class> findClass(String name) throws ClassNotFoundException {
+ // 首先检查已加载的动态类
+ if (dynamicClasses.containsKey(name)) {
+ return dynamicClasses.get(name);
+ }
+ // 委托给父类
+ return super.findClass(name);
+ }
+
+ @Override
+ public Class> loadClass(String name) throws ClassNotFoundException {
+ return loadClass(name, false);
+ }
+
+ @Override
+ protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ synchronized (getClassLoadingLock(name)) {
+ // 首先检查是否已经加载
+ Class> c = findLoadedClass(name);
+ if (c == null) {
+ // 检查是否是动态类
+ if (dynamicClasses.containsKey(name)) {
+ c = dynamicClasses.get(name);
+ } else {
+ // 委托给父类
+ c = super.loadClass(name, resolve);
+ }
+ }
+
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+ }
+
+}
diff --git a/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassLoaderContext.java b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassLoaderContext.java
new file mode 100644
index 00000000..555e4917
--- /dev/null
+++ b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassLoaderContext.java
@@ -0,0 +1,27 @@
+package com.codingapi.springboot.fast.classloader;
+
+import lombok.Getter;
+
+public class DynamicEntityClassLoaderContext {
+
+ @Getter
+ private final static DynamicEntityClassLoaderContext instance = new DynamicEntityClassLoaderContext();
+
+ private final DynamicEntityClassLoader dynamicEntityClassLoader;
+
+ private DynamicEntityClassLoaderContext(){
+ dynamicEntityClassLoader = new DynamicEntityClassLoader(Thread.currentThread().getContextClassLoader() != null
+ ? Thread.currentThread().getContextClassLoader()
+ : getClass().getClassLoader());
+ Thread.currentThread().setContextClassLoader(dynamicEntityClassLoader);
+ }
+
+ public void registerClass(String className, Class> clazz) {
+ dynamicEntityClassLoader.registerClass(className, clazz);
+ }
+
+ public void registerClass(Class> clazz) {
+ dynamicEntityClassLoader.registerClass(clazz);
+ }
+
+}
diff --git a/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilder.java b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilder.java
new file mode 100644
index 00000000..5a153b80
--- /dev/null
+++ b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilder.java
@@ -0,0 +1,187 @@
+package com.codingapi.springboot.fast.dynamic;
+
+import org.hibernate.boot.Metadata;
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.model.relational.ContributableDatabaseObject;
+import org.hibernate.boot.registry.StandardServiceRegistry;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.tool.schema.SourceType;
+import org.hibernate.tool.schema.TargetType;
+import org.hibernate.tool.schema.internal.ExceptionHandlerCollectingImpl;
+import org.hibernate.tool.schema.spi.*;
+import org.springframework.util.StringUtils;
+
+import java.util.*;
+
+public class DynamicEntityBuilder {
+
+ private final Dialect dialect;
+ private final StandardServiceRegistry serviceRegistry;
+ private final SchemaManagementTool managementTool;
+
+ public DynamicEntityBuilder(Class> dialectClass, String jdbcUrl) {
+ this(dialectClass,jdbcUrl,null,null);
+ }
+
+ public DynamicEntityBuilder(Class> dialectClass, String jdbcUrl, String username, String password) {
+ try {
+ this.dialect = (Dialect) dialectClass.getDeclaredConstructor().newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to instantiate dialect", e);
+ }
+
+ StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
+ .applySetting(AvailableSettings.DIALECT, dialect.getClass().getName())
+ .applySetting("hibernate.connection.url", jdbcUrl);
+ if (StringUtils.hasText(username)) {
+ builder.applySetting("hibernate.connection.username", username);
+ }
+ if (StringUtils.hasText(password)) {
+ builder.applySetting("hibernate.connection.password", password);
+ }
+ this.serviceRegistry = builder.build();
+ this.managementTool = serviceRegistry.getService(SchemaManagementTool.class);
+ }
+
+ private class ExecutionOptionsImpl implements ExecutionOptions {
+
+ @Override
+ public Map getConfigurationValues() {
+ Map config = new HashMap<>();
+ config.put(AvailableSettings.DIALECT, dialect.getClass().getName());
+ return config;
+ }
+
+ @Override
+ public boolean shouldManageNamespaces() {
+ return false;
+ }
+
+ @Override
+ public ExceptionHandler getExceptionHandler() {
+ return new ExceptionHandlerCollectingImpl();
+ }
+ }
+
+ private static class ContributableMatcherImpl implements ContributableMatcher {
+ @Override
+ public boolean matches(ContributableDatabaseObject contributed) {
+ return true;
+ }
+ }
+
+ private static class SourceDescriptorImpl implements SourceDescriptor {
+
+ @Override
+ public SourceType getSourceType() {
+ return SourceType.METADATA;
+ }
+
+ @Override
+ public ScriptSourceInput getScriptSourceInput() {
+ return extractor -> List.of();
+ }
+ }
+
+ private static class TargetDescriptorImpl implements TargetDescriptor {
+ private final List sqlCommands = new ArrayList<>();
+
+ @Override
+ public EnumSet getTargetTypes() {
+ return EnumSet.of(TargetType.SCRIPT);
+ }
+
+ @Override
+ public ScriptTargetOutput getScriptTargetOutput() {
+ return new ScriptTargetOutput() {
+ @Override
+ public void prepare() {
+
+ }
+
+ @Override
+ public void accept(String command) {
+ sqlCommands.add(command);
+ }
+
+ @Override
+ public void release() {
+
+ }
+ };
+ }
+
+ public String getDDL() {
+ return String.join("\n", sqlCommands);
+ }
+ }
+
+ public String generateDropTableDDL(Class> entityClass) {
+ MetadataSources metadataSources = new MetadataSources(serviceRegistry);
+ metadataSources.addAnnotatedClass(entityClass);
+ Metadata metadata = metadataSources.buildMetadata();
+ TargetDescriptorImpl targetDescriptor = new TargetDescriptorImpl();
+
+ managementTool.getSchemaDropper(Collections.emptyMap()).doDrop(metadata,
+ new ExecutionOptionsImpl(),
+ new ContributableMatcherImpl(),
+ new SourceDescriptorImpl(),
+ targetDescriptor);
+
+ return targetDescriptor.getDDL();
+ }
+
+ public String generateCreateTableDDL(Class> entityClass) {
+ MetadataSources metadataSources = new MetadataSources(serviceRegistry);
+ metadataSources.addAnnotatedClass(entityClass);
+ Metadata metadata = metadataSources.buildMetadata();
+
+ TargetDescriptorImpl targetDescriptor = new TargetDescriptorImpl();
+
+ managementTool.getSchemaCreator(Collections.emptyMap()).doCreation(metadata,
+ new ExecutionOptionsImpl(),
+ new ContributableMatcherImpl(),
+ new SourceDescriptorImpl(),
+ targetDescriptor);
+ return targetDescriptor.getDDL();
+ }
+
+ public String generateMigratorTableDDL(Class> entityClass) {
+ MetadataSources metadataSources = new MetadataSources(serviceRegistry);
+ metadataSources.addAnnotatedClass(entityClass);
+ Metadata metadata = metadataSources.buildMetadata();
+
+ TargetDescriptorImpl targetDescriptor = new TargetDescriptorImpl();
+
+ managementTool.getSchemaMigrator(Collections.emptyMap()).doMigration(metadata,
+ new ExecutionOptionsImpl(),
+ new ContributableMatcherImpl(),
+ targetDescriptor);
+ return targetDescriptor.getDDL();
+ }
+
+ public List validatorTable(Class> entityClass) {
+ ExceptionHandlerCollectingImpl exceptionHandler = new ExceptionHandlerCollectingImpl();
+ MetadataSources metadataSources = new MetadataSources(serviceRegistry);
+ metadataSources.addAnnotatedClass(entityClass);
+ Metadata metadata = metadataSources.buildMetadata();
+ List exceptionList = new ArrayList<>();
+ try {
+ managementTool.getSchemaValidator(Collections.emptyMap()).doValidation(metadata,
+ new ExecutionOptionsImpl() {
+ @Override
+ public ExceptionHandler getExceptionHandler() {
+ return exceptionHandler;
+ }
+ },
+ new ContributableMatcherImpl());
+ } catch (Exception e) {
+ exceptionList.add(e);
+ }
+ exceptionList.addAll(exceptionHandler.getExceptions());
+ return exceptionList;
+ }
+
+}
diff --git a/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/EntityMeta.java b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/EntityMeta.java
new file mode 100644
index 00000000..1ef9b4e0
--- /dev/null
+++ b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/EntityMeta.java
@@ -0,0 +1,134 @@
+package com.codingapi.springboot.fast.metadata;
+
+import com.codingapi.springboot.fast.classloader.DynamicEntityClassBuilder;
+import com.codingapi.springboot.fast.dynamic.DynamicEntityBuilder;
+import jakarta.persistence.GenerationType;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+public class EntityMeta {
+
+ private final String className;
+ private final TableMeta table;
+ private final List columns;
+
+ public EntityMeta(String className) {
+ this.className = className;
+ this.table = new TableMeta();
+ this.columns = new ArrayList<>();
+ }
+
+ public void setTable(String name,String catalog,String schema,String comment){
+ this.table.setName(name);
+ this.table.setCatalog(catalog);
+ this.table.setSchema(schema);
+ this.table.setComment(comment);
+ }
+
+ public void setTable(String name,String comment){
+ this.setTable(name,null,null,comment);
+ }
+
+ public void setTable(String name){
+ this.setTable(name,null,null,null);
+ }
+
+ public void addPrimaryKeyColumn(Class> type,String name,GenerationType strategy,String generator,String comment,boolean unique,boolean nullable, boolean insertable,
+ boolean updatable,String columnDefinition, int length,int precision,int scale){
+ ColumnMeta column = new ColumnMeta();
+ column.setType(type);
+ column.setName(name);
+ column.setPrimaryKey(true);
+ GeneratedValueMeta generatedValueMeta = new GeneratedValueMeta();
+ generatedValueMeta.setGenerator(generator);
+ generatedValueMeta.setStrategy(strategy);
+ column.setGeneratedValue(generatedValueMeta);
+ column.setComment(comment);
+ column.setUnique(unique);
+ column.setNullable(nullable);
+ column.setInsertable(insertable);
+ column.setUpdatable(updatable);
+ column.setColumnDefinition(columnDefinition);
+ column.setLength(length);
+ column.setPrecision(precision);
+ column.setScale(scale);
+ this.columns.add(column);
+ }
+
+ public void addColumn(Class> type,String name,String comment,boolean unique,boolean nullable, boolean insertable,
+ boolean updatable,String columnDefinition, int length,int precision,int scale){
+ ColumnMeta column = new ColumnMeta();
+ column.setPrimaryKey(false);
+ column.setType(type);
+ column.setName(name);
+ column.setComment(comment);
+ column.setUnique(unique);
+ column.setNullable(nullable);
+ column.setInsertable(insertable);
+ column.setUpdatable(updatable);
+ column.setColumnDefinition(columnDefinition);
+ column.setLength(length);
+ column.setPrecision(precision);
+ column.setScale(scale);
+ this.columns.add(column);
+ }
+
+ public void addColumn(Class> type,String name,String comment){
+ this.addColumn(type,name,comment,false,false,false,false,null,255,0,0);
+ }
+
+ public void addColumn(Class> type,String name){
+ this.addColumn(type,name,null,false,false,false,false,null,255,0,0);
+ }
+
+ public void addPrimaryKeyColumn(Class> type,String name,GenerationType strategy){
+ this.addPrimaryKeyColumn(type,name,strategy,null,null,false,false,false,false,null,255,0,0);
+ }
+
+ public void addPrimaryKeyColumn(Class> type,String name,GenerationType strategy,String comment){
+ this.addPrimaryKeyColumn(type,name,strategy,null,comment,false,false,false,false,null,255,0,0);
+ }
+
+ public Class> buildClass(){
+ return DynamicEntityClassBuilder.buildDynamicEntity(this);
+ }
+
+ @Setter
+ @Getter
+ public static class TableMeta{
+ private String name;
+ private String catalog;
+ private String schema;
+ private String comment;
+ }
+
+ @Setter
+ @Getter
+ public static class ColumnMeta{
+ private Class> type;
+ private String name;
+ private boolean isPrimaryKey;
+ private GeneratedValueMeta generatedValue;
+ private String comment;
+ private boolean unique;
+ private boolean nullable;
+ private boolean insertable;
+ private boolean updatable;
+ private String columnDefinition;
+ private int length;
+ private int precision;
+ private int scale;
+ }
+
+ @Setter
+ @Getter
+ public static class GeneratedValueMeta{
+ private GenerationType strategy;
+ private String generator;
+ }
+
+}
diff --git a/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java b/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java
new file mode 100644
index 00000000..ca7fd49b
--- /dev/null
+++ b/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java
@@ -0,0 +1,63 @@
+package com.codingapi.springboot.fast.dynamic;
+
+import com.codingapi.springboot.fast.entity.Demo;
+import com.codingapi.springboot.fast.metadata.EntityMeta;
+import jakarta.persistence.GenerationType;
+import org.hibernate.dialect.H2Dialect;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class DynamicEntityBuilderTest {
+
+ @Test
+ void generateTableDDL() {
+ DynamicEntityBuilder dynamicEntityBuilder = new DynamicEntityBuilder(H2Dialect.class,"jdbc:h2:file:./test.db");
+ List exceptions = dynamicEntityBuilder.validatorTable(Demo.class);
+ System.out.println(exceptions);
+ assertTrue(exceptions.isEmpty());
+
+ String createDDL = dynamicEntityBuilder.generateCreateTableDDL(Demo.class);
+ System.out.println("createDDL:\n" + createDDL);
+ assertNotNull(createDDL);
+
+ String dropDDL = dynamicEntityBuilder.generateDropTableDDL(Demo.class);
+ System.out.println("dropDDL:\n" + dropDDL);
+ assertNotNull(dropDDL);
+
+ String migrateDDL = dynamicEntityBuilder.generateMigratorTableDDL(Demo.class);
+ System.out.println("migrateDDL:\n" + migrateDDL);
+ assertNotNull(migrateDDL);
+ }
+
+ @Test
+ void dynamicGenerateTableDDL() {
+ DynamicEntityBuilder dynamicEntityBuilder = new DynamicEntityBuilder(H2Dialect.class,"jdbc:h2:file:./test.db");
+
+ EntityMeta entityMeta = new EntityMeta("com.codingapi.entity.Test");
+ entityMeta.setTable("test");
+ entityMeta.addPrimaryKeyColumn(Long.class,"id", GenerationType.IDENTITY,"主键");
+ entityMeta.addColumn(String.class,"name","姓名");
+
+ Class> entityClass = entityMeta.buildClass();
+
+ List exceptions = dynamicEntityBuilder.validatorTable(entityClass);
+ System.out.println(exceptions);
+ assertFalse(exceptions.isEmpty());
+
+ String createDDL = dynamicEntityBuilder.generateCreateTableDDL(entityClass);
+ System.out.println("createDDL:\n" + createDDL);
+ assertNotNull(createDDL);
+
+ String dropDDL = dynamicEntityBuilder.generateDropTableDDL(entityClass);
+ System.out.println("dropDDL:\n" + dropDDL);
+ assertNotNull(dropDDL);
+
+ String migrateDDL = dynamicEntityBuilder.generateMigratorTableDDL(entityClass);
+ System.out.println("migrateDDL:\n" + migrateDDL);
+ assertNotNull(migrateDDL);
+
+ }
+}
\ No newline at end of file
diff --git a/springboot-starter-flow/pom.xml b/springboot-starter-flow/pom.xml
index 63c74096..4d13e158 100644
--- a/springboot-starter-flow/pom.xml
+++ b/springboot-starter-flow/pom.xml
@@ -6,7 +6,7 @@
springboot-parent
com.codingapi.springboot
- 3.4.23
+ 3.4.24
springboot-starter-flow
diff --git a/springboot-starter-security/pom.xml b/springboot-starter-security/pom.xml
index d4598136..6dd3c797 100644
--- a/springboot-starter-security/pom.xml
+++ b/springboot-starter-security/pom.xml
@@ -6,7 +6,7 @@
springboot-parent
com.codingapi.springboot
- 3.4.23
+ 3.4.24
springboot-starter-security
diff --git a/springboot-starter/pom.xml b/springboot-starter/pom.xml
index 78d0381d..d6b970d1 100644
--- a/springboot-starter/pom.xml
+++ b/springboot-starter/pom.xml
@@ -5,7 +5,7 @@
com.codingapi.springboot
springboot-parent
- 3.4.23
+ 3.4.24
springboot-starter
From f4611d04d5613da0c37a03463e65a793890ccef0 Mon Sep 17 00:00:00 2001
From: lorne <1991wangliang@gmail.com>
Date: Thu, 11 Dec 2025 19:52:15 +0800
Subject: [PATCH 2/3] add #167
---
.../DynamicEntityClassBuilder.java | 30 +++++++++----------
.../{EntityMeta.java => EntityMetaData.java} | 5 ++--
.../dynamic/DynamicEntityBuilderTest.java | 12 ++++----
3 files changed, 23 insertions(+), 24 deletions(-)
rename springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/{EntityMeta.java => EntityMetaData.java} (97%)
diff --git a/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassBuilder.java b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassBuilder.java
index 05c2dcd1..94ed83f2 100644
--- a/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassBuilder.java
+++ b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/classloader/DynamicEntityClassBuilder.java
@@ -1,6 +1,6 @@
package com.codingapi.springboot.fast.classloader;
-import com.codingapi.springboot.fast.metadata.EntityMeta;
+import com.codingapi.springboot.fast.metadata.EntityMetaData;
import jakarta.persistence.*;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.annotation.AnnotationDescription;
@@ -23,21 +23,21 @@ public class DynamicEntityClassBuilder {
/**
* 根据 EntityClass 构建动态实体
*/
- public static Class> buildDynamicEntity(EntityMeta entityMeta) {
- if (entityMeta == null || entityMeta.getClassName() == null) {
+ public static Class> buildDynamicEntity(EntityMetaData entityMetaData) {
+ if (entityMetaData == null || entityMetaData.getClassName() == null) {
throw new IllegalArgumentException("Entity metadata cannot be null");
}
try {
DynamicType.Builder> builder = new ByteBuddy()
.subclass(Object.class)
- .name(entityMeta.getClassName())
+ .name(entityMetaData.getClassName())
.implement(Serializable.class)
- .annotateType(buildEntityAnnotations(entityMeta));
+ .annotateType(buildEntityAnnotations(entityMetaData));
// 添加字段
boolean hasPrimaryKey = false;
- for (EntityMeta.ColumnMeta column : entityMeta.getColumns()) {
+ for (EntityMetaData.ColumnMeta column : entityMetaData.getColumns()) {
builder = addColumnField(builder, column);
if (column.isPrimaryKey()) {
hasPrimaryKey = true;
@@ -61,25 +61,25 @@ public static Class> buildDynamicEntity(EntityMeta entityMeta) {
} catch (Exception e) {
throw new RuntimeException("Failed to build dynamic entity: " +
- entityMeta.getClassName(), e);
+ entityMetaData.getClassName(), e);
}
}
/**
* 构建实体类注解
*/
- private static AnnotationDescription[] buildEntityAnnotations(EntityMeta entityMeta) {
+ private static AnnotationDescription[] buildEntityAnnotations(EntityMetaData entityMetaData) {
List annotations = new ArrayList<>();
// @Entity 注解
annotations.add(AnnotationDescription.Builder.ofType(Entity.class).build());
// @Table 注解
- if (entityMeta.getTable() != null) {
+ if (entityMetaData.getTable() != null) {
AnnotationDescription.Builder tableBuilder =
AnnotationDescription.Builder.ofType(Table.class);
- EntityMeta.TableMeta tableMeta = entityMeta.getTable();
+ EntityMetaData.TableMeta tableMeta = entityMetaData.getTable();
if (tableMeta.getName() != null && !tableMeta.getName().isEmpty()) {
tableBuilder = tableBuilder.define("name", tableMeta.getName());
}
@@ -94,11 +94,11 @@ private static AnnotationDescription[] buildEntityAnnotations(EntityMeta entityM
}
// @Comment 注解 - 注释应该放在类上,而不是表注解上
- if (entityMeta.getTable() != null && StringUtils.hasText(entityMeta.getTable().getComment())) {
+ if (entityMetaData.getTable() != null && StringUtils.hasText(entityMetaData.getTable().getComment())) {
AnnotationDescription.Builder commentBuilder =
AnnotationDescription.Builder.ofType(Comment.class);
- EntityMeta.TableMeta tableMeta = entityMeta.getTable();
+ EntityMetaData.TableMeta tableMeta = entityMetaData.getTable();
commentBuilder = commentBuilder.define("value", tableMeta.getComment());
annotations.add(commentBuilder.build());
}
@@ -110,7 +110,7 @@ private static AnnotationDescription[] buildEntityAnnotations(EntityMeta entityM
* 添加字段
*/
private static DynamicType.Builder> addColumnField(DynamicType.Builder> builder,
- EntityMeta.ColumnMeta columnMeta) {
+ EntityMetaData.ColumnMeta columnMeta) {
// 确定字段类型
Class> fieldType = columnMeta.getType();
@@ -160,7 +160,7 @@ private static DynamicType.Builder> addColumnField(DynamicType.Builder> buil
* 构建字段注解
*/
private static List buildFieldAnnotations(
- EntityMeta.ColumnMeta columnMeta, String fieldName) {
+ EntityMetaData.ColumnMeta columnMeta, String fieldName) {
List annotations = new ArrayList<>();
@@ -170,7 +170,7 @@ private static List buildFieldAnnotations(
// @GeneratedValue 注解
if (columnMeta.getGeneratedValue() != null) {
- EntityMeta.GeneratedValueMeta genMeta = columnMeta.getGeneratedValue();
+ EntityMetaData.GeneratedValueMeta genMeta = columnMeta.getGeneratedValue();
AnnotationDescription.Builder genBuilder =
AnnotationDescription.Builder.ofType(GeneratedValue.class);
diff --git a/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/EntityMeta.java b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/EntityMetaData.java
similarity index 97%
rename from springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/EntityMeta.java
rename to springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/EntityMetaData.java
index 1ef9b4e0..171f405c 100644
--- a/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/EntityMeta.java
+++ b/springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/metadata/EntityMetaData.java
@@ -1,7 +1,6 @@
package com.codingapi.springboot.fast.metadata;
import com.codingapi.springboot.fast.classloader.DynamicEntityClassBuilder;
-import com.codingapi.springboot.fast.dynamic.DynamicEntityBuilder;
import jakarta.persistence.GenerationType;
import lombok.Getter;
import lombok.Setter;
@@ -10,13 +9,13 @@
import java.util.List;
@Getter
-public class EntityMeta {
+public class EntityMetaData {
private final String className;
private final TableMeta table;
private final List columns;
- public EntityMeta(String className) {
+ public EntityMetaData(String className) {
this.className = className;
this.table = new TableMeta();
this.columns = new ArrayList<>();
diff --git a/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java b/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java
index ca7fd49b..81a1d1fc 100644
--- a/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java
+++ b/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java
@@ -1,7 +1,7 @@
package com.codingapi.springboot.fast.dynamic;
import com.codingapi.springboot.fast.entity.Demo;
-import com.codingapi.springboot.fast.metadata.EntityMeta;
+import com.codingapi.springboot.fast.metadata.EntityMetaData;
import jakarta.persistence.GenerationType;
import org.hibernate.dialect.H2Dialect;
import org.junit.jupiter.api.Test;
@@ -36,12 +36,12 @@ void generateTableDDL() {
void dynamicGenerateTableDDL() {
DynamicEntityBuilder dynamicEntityBuilder = new DynamicEntityBuilder(H2Dialect.class,"jdbc:h2:file:./test.db");
- EntityMeta entityMeta = new EntityMeta("com.codingapi.entity.Test");
- entityMeta.setTable("test");
- entityMeta.addPrimaryKeyColumn(Long.class,"id", GenerationType.IDENTITY,"主键");
- entityMeta.addColumn(String.class,"name","姓名");
+ EntityMetaData entityMetaData = new EntityMetaData("com.codingapi.entity.Test");
+ entityMetaData.setTable("test");
+ entityMetaData.addPrimaryKeyColumn(Long.class,"id", GenerationType.IDENTITY,"主键");
+ entityMetaData.addColumn(String.class,"name","姓名");
- Class> entityClass = entityMeta.buildClass();
+ Class> entityClass = entityMetaData.buildClass();
List exceptions = dynamicEntityBuilder.validatorTable(entityClass);
System.out.println(exceptions);
From 52b5457e484e9eac9fc396e6f9b6a711e9b54f1a Mon Sep 17 00:00:00 2001
From: lorne <1991wangliang@gmail.com>
Date: Thu, 11 Dec 2025 20:48:02 +0800
Subject: [PATCH 3/3] fix #167
---
.../springboot/fast/dynamic/DynamicEntityBuilderTest.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java b/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java
index 81a1d1fc..16aa4ded 100644
--- a/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java
+++ b/springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/dynamic/DynamicEntityBuilderTest.java
@@ -17,7 +17,6 @@ void generateTableDDL() {
DynamicEntityBuilder dynamicEntityBuilder = new DynamicEntityBuilder(H2Dialect.class,"jdbc:h2:file:./test.db");
List exceptions = dynamicEntityBuilder.validatorTable(Demo.class);
System.out.println(exceptions);
- assertTrue(exceptions.isEmpty());
String createDDL = dynamicEntityBuilder.generateCreateTableDDL(Demo.class);
System.out.println("createDDL:\n" + createDDL);