Jakarta NoSQLを使用したNoSQLデータベースエンジンにおけるポリモーフィズムの導入

多型性(Polymorphism)は、面向对象プログラミングの基本理念で、異なるタイプのオブジェクトを共通の超クラスのインスタンスとして扱うことができます。この柔軟性は、容易に拡張して保守管理できるシステムの作成に不可欠です。従来のSQLデータベースとジャカルタ・ペレジェンス(JPA)は多型データを処理することができますが、NoSQLデータベースは独自の長所を持っています。SQLデータベースは堅牢なスキーマ定義を必要とる一方、NoSQLデータベースはスキーマレスアプローチを取るため、多型および柔軟なデータ構造を本来よりも適切にサポートします。この柔軟性は、Jakarta NoSQLと統合されたときに特に魅力的になります。これは、カスタムコンバーターを通じて多型フィールドの定義と管理に健全なサポートを提供するツールです。

多くのエンタープライズアプリケーションでは、異なるタイプのデータオブジェクトを管理する一般的な必要性があります。例えば、電子商取引プラットフォームはクレジットカード、デジタルウォレット、銀行振替などのさまざまな支払方法を扱い、それぞれ固有の属性を持っています。同様に、大企業の資産管理システムは不動産、機械、知的財産などのさまざまなタイプの資産を処理し、それぞれ固有の特性を有している。医療システムは個人情報から始まって医療記録や検査結果に至るまでさまざまなデータタイプを対応する必要があります。NoSQLデータベースと多型フィールドを使って、これらの多様なデータタイプを統合して管理することができます。NoSQLデータベースのスキーマレスの性質は、リレーショナルデータベースに比べて要求変化に適応しやすくします。

この チュートリアルでは、Jakarta NoSQL を使用して、カスタム コンバーターを使用して多型フィールドを管理する方法を説明します。Helidon と Oracle NoSQL を使用した REST サービスの統合のサンプル コードを含めます。この例では、スキーマレスの NoSQL データベース環境で、さまざまなデータ型を効率的に管理するための多型の実際の適用例を示します。

NoSQL と Jakarta NoSQL での多型の使用

このチュートリアルでは、Oracle NoSQL、Java Helidon、REST API を使用して、Java の世界における NoSQL およびスキーマレスの機能を探ります。Machine エンティティを作成し、JSON に変換される engine フィールドを提供します。Oracle NoSQL の自然な柔軟性とスキーマレスの設計により、このアプローチは seamlessly に機能します。

最初のステップは Helidon プロジェクトの作成で、Helidon スターターを使用できます: Helidon スターター

マイクロプロファイル対応プロジェクトを作成したら、次のステップは Oracle NoSQL ドライバーを含めることです: Oracle NoSQL ドライバー

プロパティ ファイルでは、ローカルで実行するため、ホスト接続を定義する 1 つのプロパティと、データベース名を定義する 2 つ目のプロパティが必要です:

Properties files

 

jnosql.document.database=machines
jnosql.oracle.nosql.host=http://localhost:8080

さらに、ポートを 8181 に更新します。

Properties files

 

server.port=8181

Shell

 

docker run -d --name oracle-instance -p 8080:8080 ghcr.io/oracle/nosql:latest-ce

DockerでOracle NoSQLの設定と実行を簡素化し、Oracle インフラストラクチャーのクラウド展開もサポートされています。Dockerを使うことで、設定プロセスが簡単になり、Oracle NoSQLインスタンスが制御された環境で実行されるようになります。このセットアップは、クラウドインフラストラクチャーを含む、さまざまな環境でOracle NoSQLを展開する際の実用的なアプローチを示しています。

設定とデータベースの設定が完了したら、次のステップはEntityの定義とConverterの実装を行うことです。この例では、Jakarta NoSQLとJakarta JSON-Bの滑らかな統合を示し、さまざまなJakartaの仕様がどのように効果的に連携できるかを説明します。

最初のステップは、ポリモーフィックなEngineフィールドを含むMachineエンティティを定義することです。

Java

 


@Entity
@JsonbVisibility(FieldAccessStrategy.class)
public class Machine {

    @Id
    private String id;

    @Column
    @Convert(EngineConverter.class)
    private Engine engine;

    @Column
    private String manufacturer;

    @Column
    private int year;

    // Getters and setters
}

次に、JsonbTypeInfoを使ってポリモーフィズムを処理するように指定しながら、Engineクラスを定義します。

Java

 

@JsonbTypeInfo(
        key = "type",
        value = {
                @JsonbSubtype(alias = "gas", type = GasEngine.class),
                @JsonbSubtype(alias = "electric", type = ElectricEngine.class)
        }
)
@JsonbVisibility(FieldAccessStrategy.class)
public abstract class Engine {
    // Common engine attributes

    // Getters and setters
}

エンジンコンバーターはプロバイダーによって変更される可能性があり、StringMap<String, Object>BSONなどとして機能できます。

設定とデータベースの設定が完了したら、次のステップはアプリケーションとデータベースのブリッジを作成することです。Eclipse JNoSQLは、Jakarta NoSQLとJakarta Dataの2つの仕様を統合し、単一のインターフェイスを使ってこれを実現します。注釈で必要な手順を処理します。

まず、MachineRepositoryインターフェイスを定義します。

Java

 

@Repository
public interface MachineRepository extends BasicRepository<Machine, String> {

    @Query("from Machine where engine.type = :type")
    List<Machine> findByType(@Param("type") String type);
}

このリポジトリインターフェイスにより、JSONデータ内の要素を直接検索できるようになり、rigid な構造を作成することなく拡張できます。

次に、このリソースを公開するコントローラーを定義します。

Java

 


@Path("/machines")
@ApplicationScoped
public class MachineResource {

    private static final Logger LOGGER = Logger.getLogger(MachineResource.class.getName());

    public static final Order<Machine> ORDER_MANUFACTURER = Order.by(Sort.asc("manufacturer"));

    private final MachineRepository repository;

    @Inject
    public MachineResource(@Database(DatabaseType.DOCUMENT) MachineRepository repository) {
        this.repository = repository;
    }

    @GET
    public List<Machine> getMachines(@QueryParam("page") @DefaultValue("1") int page, @QueryParam("page_size") @DefaultValue("10") int pageSize) {
        LOGGER.info("Get machines from page " + page + " with page size " + pageSize);
        Page<Machine> machines = this.repository.findAll(PageRequest.ofPage(page).size(pageSize), ORDER_MANUFACTURER);
        return machines.content();
    }

    @GET
    @Path("gas")
    public List<Machine> getGasMachines() {
        return this.repository.findByType("gas");
    }

    @GET
    @Path("electric")
    public List<Machine> getElectricMachines() {
        return this.repository.findByType("electric");
    }

    @GET
    @Path("{id}")
    public Machine get(@PathParam("id") String id) {
        LOGGER.info("Get machine by id " + id);
        return this.repository.findById(id)
                .orElseThrow(() -> new WebApplicationException("Machine not found with id: " + id, Response.Status.NOT_FOUND));
    }

    @PUT
    public void save(Machine machine) {
        LOGGER.info("Saving a machine " + machine);
        this.repository.save(machine);
    }
}

このコントローラーは、マシンの取得やタイプ別検索、ページネーションなど、マシンを管理するためのエンドポイントを公開します。

最後に、アプリケーションを実行し、以下のcurlコマンドを使ってデータを挿入します。

Shell

 

curl --location --request PUT 'http://localhost:8181/machines' \


"id": "1",
"model": "Thunderbolt V8",
"engine": {
"type": "gas",
"horsepower": 450
},
"manufacturer": "Mustang",
"year": 2021,
"weight": 1600.0
}'

curl --location --request PUT 'http://localhost:8181/machines' \


    "id": "2",
    "model": "Eagle Eye EV",
    "engine": {
        "type": "electric",
        "horsepower": 300
    },
    "manufacturer": "Tesla",
    "year": 2022,
    "weight": 1400.0
}'

curl --location --request PUT 'http://localhost:8181/machines' \


    "id": "3",
    "model": "Road Runner GT",
    "engine": {
        "type": "gas",
        "horsepower": 400
    },
    "manufacturer": "Chevrolet",
    "year": 2020,
    "weight": 1700.0
}'

curl --location --request PUT 'http://localhost:8181/machines' \


    "id": "4",
    "model": "Solaris X",
    "engine": {
        "type": "electric",
        "horsepower": 350
    },
    "manufacturer": "Nissan",
    "year": 2023,
    "weight": 1350.0
}'

curl --location --request PUT 'http://localhost:8181/machines' \


    "id": "5",
    "model": "Fusion Hybrid 2024",
    "engine": {
        "type": "electric",
        "horsepower": 320
    },
    "manufacturer": "Toyota",
    "year": 2024,
    "weight": 1450.0
}'

この設定により、JSONの中でタイプ別に検索できるようになり、ページネーションも簡単に実装できます。ページネーションの詳細については、こちらの記事を参照してください。

データを挿入したら、検索機能がどのように動作するかを探索できます。

  • ページネーションを使ったマシンの取得
  • すべてのマシンの取得
  • ガスマシンの取得

最終的な考察

Jakarta NoSQL and Jakarta JSON-Bを使用したNoSQLデータベースとポリモーフィズムの統合は、多様なデータ型の管理に柔軟性と効率性をもたらします。NoSQLのスキーマレスな特性を活用することで、開発が簡素化され、アプリケーションの適応性が向上します。完全な例とソースコードについては、soujava/helidon-oracle-json-typesをご覧ください。

Source:
https://dzone.com/articles/intro-to-polymorphism-with-db-engines-in-nosql