ホームページ > Java > &#&チュートリアル > JPA エンティティを Mendix に変換する

JPA エンティティを Mendix に変換する

Linda Hamilton
リリース: 2025-01-13 18:04:42
オリジナル
315 人が閲覧しました

最近、Mendix を探索しているときに、API を介して mendix アプリ モデルと対話できるプラットフォーム SDK があることに気付きました。

これにより、ドメイン モデルの作成に使用できるかどうかを検討するというアイデアが生まれました。具体的には、既存の従来のアプリケーションに基づいてドメイン モデルを作成します。

さらに一般化すると、これを使用して既存のアプリケーションを 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 フィールドがあります。猫は人間と 1 対 1 で関連付けられているため、いつでも人間を呼び出すことができます。 (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);
    }
    ...
}
ログイン後にコピー
ログイン後にコピー

まず、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
    
    ログイン後にコピー
    ログイン後にコピー

    基本的には、JAVA_TO_MENDIX_TYPE マップで検索して Java 型をカスタム列挙値と照合するだけです。

  2. 次に、この属性が実際に関連付け (別の @Entity を指している) であるかどうかを確認します。そうである場合、関連付けのタイプが 1 対 1、1 対多、多対多であるかどうかを判断します:

    @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 型の場合は 1 対多、それ以外の場合は 1 対 1 (「多対多」はまだ実装されていません)。

  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);
    }
    ...
}
ログイン後にコピー
ログイン後にコピー

最後に、List を保存します。 jackson.

を使用して json ファイルに変換します。

Mendix へのエンティティのインポート

ここからが楽しい部分です。上で生成した json ファイルをどのように読み取り、そこから mendix エンティティを作成するのでしょうか?

Mendix のプラットフォーム 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
ログイン後にコピー
ログイン後にコピー

次に、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 は実際に mendix アプリを git からプルし、それに取り組みます。

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
    }
}
ログイン後にコピー

ここでは、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 エンティティでは関連付けがフィールドによって宣言されているため、どのフィールドが単純な属性であり、どのフィールドが関連付けであるかを区別する必要があります。そのためには、それが ENTITY 型であるかプリミティブ型であるかを確認するだけです:

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. 関連付けタイプ。 1 対 1 の場合は、参照にマッピングされます。 1 対多の場合は、参照セットにマッピングされます。現時点では多対多はスキップします。

  4. 協会のオーナー。 1 対 1 の関連付けと多対多の関連付けのどちらも、同じ所有者のタイプ (両方) を持ちます。 1 対 1 の場合、所有者のタイプはデフォルトである必要があります。

Mendix プラットフォーム 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 対 1 の関連付けを持つエンティティができました。

自分で実験したい場合、または完全なコードを確認したい場合は、このリポジトリにアクセスしてください。

将来へのアイデア

  1. この例では、私が最も習熟している Java/Spring アプリケーションを変換元に使用しましたが、どのアプリケーションでも使用できます。 型データを (静的または実行時に) 読み取ってクラス名とフィールド名を抽出できれば十分です。
  2. Java ロジックを読み取って、Mendix マイクロフローにエクスポートしてみたいと思っています。ビジネス ロジック自体を実際に変換することはおそらく不可能ですが、その構造 (少なくともビジネス メソッドの署名?) は取得できるはずです。
  3. この記事のコードは一般化してライブラリにすることができます。json 形式は同じままで、Java 型をエクスポートするライブラリと mendix エンティティをインポートするライブラリが 1 つ存在する可能性があります。
  4. 同じアプローチを使用して、その逆、つまり mendix を別の言語に変換することもできます。

結論

Mendix プラットフォーム SDK は、Mendix アプリとプログラムで対話できる強力な機能です。コードのインポート/エクスポート、アプリの複雑さの分析など、いくつかのサンプル ユースケースがリストされています。
ご興味がございましたら、ぜひご覧ください。
この記事の完全なコードはここにあります。

以上がJPA エンティティを Mendix に変換するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート