最近、Mendix を探索しているときに、API を介して mendix アプリ モデルと対話できるプラットフォーム SDK があることに気付きました。
これにより、ドメイン モデルの作成に使用できるかどうかを検討するというアイデアが生まれました。具体的には、既存の従来のアプリケーションに基づいてドメイン モデルを作成します。
さらに一般化すると、これを使用して既存のアプリケーションを 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() メソッドを追加したでしょうが、それは将来のために残しておきます)。
アプリは完全に機能していますが、現時点ではデータ層のみに注目しています。
これはいくつかの異なる方法で行うことができます:
オプション 2 を選択したのは、その方が早いのですが、オプション 1 を実行できるライブラリが簡単に見つからなかったためです。
次に、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); } ... }
まず、JPA の @Entity アノテーションが付いているアプリ内のすべてのクラスを検索します。
次に、クラスごとに次のことを行います:
各フィールドについて、次のことを行います。
属性のタイプを決定します:
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 型をカスタム列挙値と照合するだけです。
次に、この属性が実際に関連付け (別の @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 (「多対多」はまだ実装されていません)。
次に、見つかったフィールドごとに 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
ここからが楽しい部分です。上で生成した 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 つの重要なプロパティがあります。
子エンティティ。最後のステップでは、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); }); }
関連付けタイプ。 1 対 1 の場合は、参照にマッピングされます。 1 対多の場合は、参照セットにマッピングされます。現時点では多対多はスキップします。
協会のオーナー。 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 でアプリを開いて結果を確認できます。
これで、猫と人間の間に 1 対 1 の関連付けを持つエンティティができました。
自分で実験したい場合、または完全なコードを確認したい場合は、このリポジトリにアクセスしてください。
Mendix プラットフォーム SDK は、Mendix アプリとプログラムで対話できる強力な機能です。コードのインポート/エクスポート、アプリの複雑さの分析など、いくつかのサンプル ユースケースがリストされています。
ご興味がございましたら、ぜひご覧ください。
この記事の完全なコードはここにあります。
以上がJPA エンティティを Mendix に変換するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。