搜索
首页Javajava教程将 JPA 实体转换为 Mendix

最近在探索 Mendix 时,我注意到他们有一个 Platform SDK,允许您通过 API 与 mendix 应用程序模型进行交互。

这给了我一个想法,探索它是否可以用于创建我们的领域模型。具体来说,是基于现有的传统应用程序创建领域模型。

如果进一步推广,这可用于将任何现有应用程序转换为 Mendix 并从那里继续开发。

将 Java/Spring Web 应用程序转换为 Mendix

因此,我创建了一个带有简单 API 和数据库层的小型 Java/Spring Web 应用程序。为了简单起见,它使用嵌入式 H2 数据库。

在这篇文章中,我们将仅转换 JPA 实体。让我们来看看它们:

@Entity
@Table(name = "CAT")
class Cat {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
    private int age;
    private String color;

    @OneToOne
    private Human humanPuppet;

    ... constructor ...
    ... getters ...
}

@Entity
@Table(name = "HUMAN")
public class Human {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    ... constructor ...
    ... getters ...
}

如您所见,它们非常简单:一只有名字、年龄、颜色的猫和它的人类傀儡,因为正如我们所知,猫统治着世界。

它们都有一个自动生成的 ID 字段。猫与人类有一对一的联系,这样它就可以随时称呼它的人类。 (如果它不是 JPA 实体,我会放置一个 meow() 方法,但让我们将其留到将来)。

应用程序功能齐全,但现在我们只对数据层感兴趣。

提取 json 中的实体元数据

这可以通过几种不同的方式来完成:

  1. 通过静态分析包中的实体。
  2. 通过使用反射在运行时读取这些实体。

我选择了选项 2,因为它更快,而且我无法轻松找到可以执行选项 1 的库。

接下来,我们需要决定构建后如何公开 json。为了简单起见,我们只需将其写入文件即可。一些替代方法可能是:

  • 通过 api 公开它。这更加复杂,因为您还需要确保端点受到很好的保护,因为我们不能公开暴露我们的元数据。
  • 通过一些管理工具公开它,例如 Spring Boot Actuator 或 jmx。它更安全,但仍然需要时间来设置。

现在让我们看看实际的代码:

public class MendixExporter {
    public static void exportEntitiesTo(String filePath) throws IOException {
        AnnotatedTypeScanner typeScanner = new AnnotatedTypeScanner(false, Entity.class);

        Set<class>> entityClasses = typeScanner.findTypes(JavaToMendixApplication.class.getPackageName());
        log.info("Entity classes are: {}", entityClasses);

        List<mendixentity> mendixEntities = new ArrayList();

        for (Class> entityClass : entityClasses) {
            List<mendixattribute> attributes = new ArrayList();
            for (Field field : entityClass.getDeclaredFields()) {

                AttributeType attributeType = determineAttributeType(field);
                AssociationType associationType = determineAssociationType(field, attributeType);
                String associationEntityType = determineAssociationEntityType(field, attributeType);

                attributes.add(
                        new MendixAttribute(field.getName(), attributeType, associationType, associationEntityType));
            }
            MendixEntity newEntity = new MendixEntity(entityClass.getSimpleName(), attributes);
            mendixEntities.add(newEntity);
        }

        writeToJsonFile(filePath, mendixEntities);
    }
    ...
}
</mendixattribute></mendixentity></class>

我们首先查找应用程序中标有 JPA 的 @Entity 注释的所有类。
然后,对于每堂课,我们:

  1. 使用entityClass.getDeclaredFields()获取声明的字段。
  2. 循环该类的每个字段。

对于每个字段,我们:

  1. 确定属性的类型:

    private static final Map<class>, AttributeType> JAVA_TO_MENDIX_TYPE = Map.ofEntries(
            Map.entry(String.class, AttributeType.STRING),
            Map.entry(Integer.class, AttributeType.INTEGER),
            ...
            );
    // we return AttributeType.ENTITY if we cannot map to anything else
    </class>

    本质上,我们只是通过在 JAVA_TO_MENDIX_TYPE 映射中查找 java 类型与我们的自定义枚举值进行匹配。

  2. 接下来,我们检查这个属性是否实际上是一个关联(指向另一个@Entity)。如果是这样,我们确定关联的类型:一对一、一对多、多对多:

    @Entity
    @Table(name = "CAT")
    class Cat {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        private String name;
        private int age;
        private String color;
    
        @OneToOne
        private Human humanPuppet;
    
        ... constructor ...
        ... getters ...
    }
    
    @Entity
    @Table(name = "HUMAN")
    public class Human {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        private String name;
    
        ... constructor ...
        ... getters ...
    }
    

    为此,我们只需检查之前映射的属性类型。如果它是 Entity,这仅意味着在之前的步骤中我们无法将其映射到任何原始 java 类型、String 或 Enum。
    然后我们还需要决定它是什么类型的关联。检查很简单:如果是 List 类型,则它是一对多,否则是一对一(尚未实现“多对多”)。

  3. 然后我们为找到的每个字段创建一个 MendixAttribute 对象。

完成后,我们只需为实体创建一个 MendixEntity 对象并分配属性列表。
MendixEntity 和 MendixAttribute 是我们稍后将用来映射到 json 的类:

public class MendixExporter {
    public static void exportEntitiesTo(String filePath) throws IOException {
        AnnotatedTypeScanner typeScanner = new AnnotatedTypeScanner(false, Entity.class);

        Set<class>> entityClasses = typeScanner.findTypes(JavaToMendixApplication.class.getPackageName());
        log.info("Entity classes are: {}", entityClasses);

        List<mendixentity> mendixEntities = new ArrayList();

        for (Class> entityClass : entityClasses) {
            List<mendixattribute> attributes = new ArrayList();
            for (Field field : entityClass.getDeclaredFields()) {

                AttributeType attributeType = determineAttributeType(field);
                AssociationType associationType = determineAssociationType(field, attributeType);
                String associationEntityType = determineAssociationEntityType(field, attributeType);

                attributes.add(
                        new MendixAttribute(field.getName(), attributeType, associationType, associationEntityType));
            }
            MendixEntity newEntity = new MendixEntity(entityClass.getSimpleName(), attributes);
            mendixEntities.add(newEntity);
        }

        writeToJsonFile(filePath, mendixEntities);
    }
    ...
}
</mendixattribute></mendixentity></class>

最后,我们保存一个List;使用 Jackson 转换为 json 文件。

将实体导入 Mendix

有趣的部分来了,我们如何读取上面生成的 json 文件并从中创建 mendix 实体?

Mendix 的 Platform SDK 有一个 Typescript API 可以与之交互。
首先,我们将创建对象来表示我们的实体和属性,以及关联和属性类型的枚举:

private static final Map<class>, AttributeType> JAVA_TO_MENDIX_TYPE = Map.ofEntries(
        Map.entry(String.class, AttributeType.STRING),
        Map.entry(Integer.class, AttributeType.INTEGER),
        ...
        );
// we return AttributeType.ENTITY if we cannot map to anything else
</class>

接下来,我们需要使用 appId 获取我们的应用程序,创建临时工作副本,打开模型,并找到我们感兴趣的域模型:

private static AssociationType determineAssociationType(Field field, AttributeType attributeType) {
    if (!attributeType.equals(AttributeType.ENTITY))
        return null;
    if (field.getType().equals(List.class)) {
        return AssociationType.ONE_TO_MANY;
    } else {
        return AssociationType.ONE_TO_ONE;
    }
}

SDK 实际上会从 git 中提取我们的 mendix 应用程序并进行处理。

读取 json 文件后,我们将循环实体:

public record MendixEntity(
        String name,
        List<mendixattribute> attributes) {
}

public record MendixAttribute(
        String name,
        AttributeType type,
        AssociationType associationType,
        String entityType) {

    public enum AttributeType {
        STRING,
        INTEGER,
        DECIMAL,
        AUTO_NUMBER,
        BOOLEAN,
        ENUM,
        ENTITY;
    }

    public enum AssociationType {
        ONE_TO_ONE,
        ONE_TO_MANY
    }
}
</mendixattribute>

这里我们使用domainmodels.Entity.createIn(domainModel);在我们的域模型中创建一个新实体并为其分配一个名称。我们可以分配更多属性,例如文档、索引,甚至实体在域模型中呈现的位置。

我们在单独的函数中处理属性:

interface ImportedEntity {
    name: string;
    generalization: string;
    attributes: ImportedAttribute[];
}

interface ImportedAttribute {
    name: string;
    type: ImportedAttributeType;
    entityType: string;
    associationType: ImportedAssociationType;
}

enum ImportedAssociationType {
    ONE_TO_ONE = "ONE_TO_ONE",
    ONE_TO_MANY = "ONE_TO_MANY"
}

enum ImportedAttributeType {
    INTEGER = "INTEGER",
    STRING = "STRING",
    DECIMAL = "DECIMAL",
    AUTO_NUMBER = "AUTO_NUMBER",
    BOOLEAN = "BOOLEAN",
    ENUM = "ENUM",
    ENTITY = "ENTITY"
}

这里我们唯一需要付出一些努力的就是将属性类型映射到有效的 mendix 类型。

接下来我们处理关联。首先,由于在我们的Java实体中关联是通过字段声明的,因此我们需要区分哪些字段是简单属性,哪些字段是关联。为此,我们只需要检查它是实体类型还是原始类型:

const client = new MendixPlatformClient();
const app = await client.getApp(appId);
const workingCopy = await app.createTemporaryWorkingCopy("main");
const model = await workingCopy.openModel();
const domainModelInterface = model.allDomainModels().filter(dm => dm.containerAsModule.name === MyFirstModule")[0];
const domainModel = await domainModelInterface.load();

让我们创建关联:

function createMendixEntities(domainModel: domainmodels.DomainModel, entitiesInJson: any) {
    const importedEntities: ImportedEntity[] = JSON.parse(entitiesInJson);

    importedEntities.forEach((importedEntity, i) => {
        const mendixEntity = domainmodels.Entity.createIn(domainModel);
        mendixEntity.name = importedEntity.name;

        processAttributes(importedEntity, mendixEntity);
    });

    importedEntities.forEach(importedEntity => {
        const mendixParentEntity = domainModel.entities.find(e => e.name === importedEntity.name) as domainmodels.Entity;
        processAssociations(importedEntity, domainModel, mendixParentEntity);
    });
}

除了名称之外,我们还有 4 个重要的属性需要设置:

  1. 父实体。这是当前实体。
  2. 子实体。在最后一步中,我们为每个 java 实体创建了 mendix 实体。现在我们只需要根据实体中java字段的类型找到匹配的实体:

    function processAttributes(importedEntity: ImportedEntity, mendixEntity: domainmodels.Entity) {
        importedEntity.attributes.filter(a => a.type !== ImportedAttributeType.ENTITY).forEach(a => {
            const mendixAttribute = domainmodels.Attribute.createIn(mendixEntity);
            mendixAttribute.name = capitalize(getAttributeName(a.name, importedEntity));
            mendixAttribute.type = assignAttributeType(a.type, mendixAttribute);
        });
    }
    
  3. 关联类型。如果是一对一的,它会映射到一个引用。如果是一对多,则映射到参考集。我们现在将跳过多对多。

  4. 协会所有者。一对一和多对多关联都具有相同的所有者类型:两者。对于一对一,所有者类型必须为默认。

Mendix Platform SDK 将在我们的 mendix 应用程序的本地工作副本中创建实体。现在我们只需要告诉它提交更改:

@Entity
@Table(name = "CAT")
class Cat {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
    private int age;
    private String color;

    @OneToOne
    private Human humanPuppet;

    ... constructor ...
    ... getters ...
}

@Entity
@Table(name = "HUMAN")
public class Human {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    ... constructor ...
    ... getters ...
}

几秒钟后,您可以在 Mendix Studio Pro 中打开应用程序并验证结果:
Converting JPA entities to Mendix

现在你已经看到了:猫和人的实体,它们之间存在一对一的关联。

如果您想亲自尝试或查看完整代码,请访问此存储库。

对未来的想法

  1. 在这个示例中,我使用了 Java/Spring 应用程序进行转换,因为我最精通它,但任何应用程序都可以使用。 只需能够读取类型数据(静态或运行时)来提取类和字段名称就足够了。
  2. 我很好奇尝试读取一些 Java 逻辑并将其导出到 Mendix 微流程。我们可能无法真正转换业务逻辑本身,但我们应该能够获得它的结构(至少是业务方法签名?)。
  3. 本文中的代码可以推广并制作成一个库:json 格式可以保持不变,并且可以有一个库用于导出 java 类型,另一个库用于导入 mendix 实体。
  4. 我们可以使用相同的方法进行相反的操作:将 mendix 转换为另一种语言。

结论

Mendix Platform SDK 是一项强大的功能,允许以编程方式与 mendix 应用程序进行交互。他们列出了一些示例用例,例如导入/导出代码、分析应用程序复杂性。
如果您有兴趣,请看一下。
对于本文,您可以在此处找到完整代码。

以上是将 JPA 实体转换为 Mendix的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
平台独立性如何使企业级的Java应用程序受益?平台独立性如何使企业级的Java应用程序受益?May 03, 2025 am 12:23 AM

Java在企业级应用中被广泛使用是因为其平台独立性。1)平台独立性通过Java虚拟机(JVM)实现,使代码可在任何支持Java的平台上运行。2)它简化了跨平台部署和开发流程,提供了更大的灵活性和扩展性。3)然而,需注意性能差异和第三方库兼容性,并采用最佳实践如使用纯Java代码和跨平台测试。

考虑到平台独立性,Java在物联网(物联网)设备的开发中扮演什么角色?考虑到平台独立性,Java在物联网(物联网)设备的开发中扮演什么角色?May 03, 2025 am 12:22 AM

JavaplaysigantroleiniotduetoitsplatFormentence.1)itallowscodeTobewrittenOnCeandrunonVariousDevices.2)Java'secosystemprovidesuseusefidesusefidesulylibrariesforiot.3)

描述一个方案,您在Java中遇到了一个特定于平台的问题以及如何解决。描述一个方案,您在Java中遇到了一个特定于平台的问题以及如何解决。May 03, 2025 am 12:21 AM

ThesolutiontohandlefilepathsacrossWindowsandLinuxinJavaistousePaths.get()fromthejava.nio.filepackage.1)UsePaths.get()withSystem.getProperty("user.dir")andtherelativepathtoconstructthefilepath.2)ConverttheresultingPathobjecttoaFileobjectifne

Java平台独立对开发人员有什么好处?Java平台独立对开发人员有什么好处?May 03, 2025 am 12:15 AM

Java'splatFormIndenceistificantBecapeitAllowSitallowsDevelostWriTecoDeonCeandRunitonAnyPlatFormwithAjvm.this“ writeonce,runanywhere”(era)橱柜橱柜:1)交叉plat formcomplibility cross-platformcombiblesible,enablingDeploymentMentMentMentMentAcrAptAprospOspOspOssCrossDifferentoSswithOssuse; 2)

将Java用于需要在不同服务器上运行的Web应用程序的优点是什么?将Java用于需要在不同服务器上运行的Web应用程序的优点是什么?May 03, 2025 am 12:13 AM

Java适合开发跨服务器web应用。1)Java的“一次编写,到处运行”哲学使其代码可在任何支持JVM的平台上运行。2)Java拥有丰富的生态系统,包括Spring和Hibernate等工具,简化开发过程。3)Java在性能和安全性方面表现出色,提供高效的内存管理和强大的安全保障。

JVM如何促进Java的'写作一次,在任何地方运行”(WORA)功能?JVM如何促进Java的'写作一次,在任何地方运行”(WORA)功能?May 02, 2025 am 12:25 AM

JVM通过字节码解释、平台无关的API和动态类加载实现Java的WORA特性:1.字节码被解释为机器码,确保跨平台运行;2.标准API抽象操作系统差异;3.类在运行时动态加载,保证一致性。

Java的较新版本如何解决平台特定问题?Java的较新版本如何解决平台特定问题?May 02, 2025 am 12:18 AM

Java的最新版本通过JVM优化、标准库改进和第三方库支持有效解决平台特定问题。1)JVM优化,如Java11的ZGC提升了垃圾回收性能。2)标准库改进,如Java9的模块系统减少平台相关问题。3)第三方库提供平台优化版本,如OpenCV。

说明JVM执行的字节码验证的过程。说明JVM执行的字节码验证的过程。May 02, 2025 am 12:18 AM

JVM的字节码验证过程包括四个关键步骤:1)检查类文件格式是否符合规范,2)验证字节码指令的有效性和正确性,3)进行数据流分析确保类型安全,4)平衡验证的彻底性与性能。通过这些步骤,JVM确保只有安全、正确的字节码被执行,从而保护程序的完整性和安全性。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。