20201014のJavaに関する記事は7件です。

PowerMockでEnumをモック化する

概要

PowerMockを導入すれば、Enumクラスをモック化してJUnitでテストコードを作成できます。

環境

バージョン
Java 8
JUnit 4.12
Mockito 2.23
PowerMock 2.0.2

使用ライブラリ一覧

  • byte-buddy-1.10.14.jar
  • cglib-nodep-3.2.9.jar
  • hamcrest-core-1.3.jar
  • javassist-3.24.0-GA.jar
  • junit-4.12.jar
  • mockito-core-2.23.0.jar
  • objenesis-3.0.1.jar
  • powermock-mockito2-2.0.2-full.jar

サンプルコード

モック化対象クラス

public enum SampleEnum {

    ELEM1("val1"),
    ELEM2("val2");

    private String val;

    private SampleEnum(String val) {
        this.val = val;
    }

    public String getVal() {
        return this.val;
    }
}

テストクラス

@RunWith(PowerMockRunner.class)
@PrepareForTest(SampleEnum.class)
public class SampleEnumTest {

    @Test
    public void test() throws Exception {

        // 期待値
        String expected_elem1 = "test";
        String expected_elem2 = "val2";

        // Enumをモック化する
        SampleEnum mocked = Mockito.mock(SampleEnum.class);

        // メソッドに戻り値を設定してスタブ化する
        Mockito.when(mocked.getVal()).thenReturn(expected_elem1);
        // スタブ化しない場合
        // Mockito.when(mocked.getVal()).thenCallRealMethod();

        // Enumの要素にモック化したオブジェクトをセットする
        Whitebox.setInternalState(SampleEnum.class, "ELEM1", mocked);

        // 実行
        String actual_elem1 = SampleEnum.ELEM1.getVal(); // "test"が返る
        String actual_elem2 = SampleEnum.ELEM2.getVal(); // "val2"が返る

        // 結果確認
        assertEquals(expected_elem1, actual_elem1);
        assertEquals(expected_elem2, actual_elem2);
    }
}

ポイント①

実はEnumのモック化それ自体には、PowerMockライブラリを使用していません。
Mockito.mock(SampleEnum.class)のように、Mockitoライブラリでモック化可能です。
(Mockitoの代わりにPowerMockito.mock、PowerMockito.whenを使用しても動作します。)

ポイントは、@RunwithにPowerMockRunnner.classを指定し、@PrepareForTestにモック化したいEnumクラスを記述する点にあります。

後は、thenReturn()で戻り値を設定したり、thenCallRealMethod()でスタブ化せずに実物のメソッドを呼び出すことも可能です。

試しに@Runwith@PrepareForTestをコメントアウトし、実行してみると以下のエラーログが吐かれます。

org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class jp.co.sample_powermock.enumtest.SampleEnum
Mockito cannot mock/spy because :
 - final class

JUnit4のテストランナーはEnumクラスのモック化に対応していないようです。

ポイント②

Enumの定数は1つ1つがEnumのインスタンスと考えることができます。
モック化したEnumオブジェクトを、このインスタンスそれぞれに注入することで、Enumのモック化が成立します。

サンプルコードではPowerMockライブラリのWhitebox.setInternalState()を使用して、Enumの要素"ELEM1"にモックオブジェクトを注入しています。

その結果、SampleEnum.ELEM1は設定したモックオブジェクトの振る舞い、SampleEnum.ELEM2は実物の通りに振る舞います。

Whiteboxを使用せずとも、java.lang.reflectでモックオブジェクトを設定することもできますが、Whiteboxを使用する方がコードを簡潔に保てると思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Mockito3.4でstaticメソッドをモック化する

概要

Mockitoのバージョン3.4からstaticメソッドのモック化に対応しました。
これにより、staticメソッドのモック化のみならPowerMockを導入する必要はなくなりました。

環境

  • mockito-core-3.4.0.jar
  • byte-buddy-1.10.16.jar

上記jarに加え、新たにmockito-inlinebyte-buddy-agentが必要になります。
- mockito-inline-3.4.0.jar
- byte-buddy-agent-1.10.16.jar

それぞれ、Mockito公式サイトByteBuddy公式サイトからダウンロードできます。

バージョン
java 8
JUnit 5

サンプルコード

モック化対象のクラス

staticメソッドを含みます。

public class MockedClass {

    public static String methodA() {
        return "val1";
    }

    public static String methodB() {
        return "val2";
    }

    public static String methodC(String str) {
        return str;
    }
}

テストクラス

public class MockedClassTest {

    @Test
    public void test() throws Exception {

        // 期待値
        String expected_methodA = "test";
        String expected_methodB = "val2";

        // 対象クラスのモック化
        MockedStatic<MockedClass> mocked = Mockito.mockStatic(MockedClass.class);
        // 戻り値を設定してスタブ化
        mocked.when(MockedClass::methodA).thenReturn(expected_methodA);
        // スタブ化しない場合
        mocked.when(MockedClass::methodB).thenCallRealMethod();

        // 実行
        String actual_methodA = MockedClass.methodA();
        String actual_methodB = MockedClass.methodB();

        // 結果確認
        assertEquals(expected_methodA, actual_methodA);
        assertEquals(expected_methodB, actual_methodB);
    }
}

モック化するにはMockito.mockStatic()
戻り値の設定にはthenReturn()
戻り値を設定せず、実物を呼びたい場合はthenCallRealMethod()
を使用できます。

staticメソッドの指定方法

サンプルコードでは、MockedClass::methodAのようにメソッド参照で指定していますが、引数がある場合の記述方法は以下のようになります。

mocked.when(() -> { MockedClass.methodC(Mockito.anyString()); })
      .thenReturn("stub");

引数リストにはMockitoのany()を指定できます。
もちろん、引数なしの場合でもラムダ式による書き方は有効です。
ラムダ式の記述ルールに従い、{}の省略も可能。

mocked.when(() -> MockedClass.methodA())
      .thenReturn("stub");
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring Cloud Gatewayを徹底解説してみる

はじめに

本記事は https://tech-blog.yoshikiohashi.dev/posts/spring-cloud-gateway-explain のクロスポスト記事になります。

この記事はGatsbyというヘッドレスCMS技術で構成されています。

Spring Cloud Gatewayとは?

一言でいうと「マイクロサービス向けのOAuth2認証API基盤」になります。

公式が親切に日本語で解説してるので見てみましょう。

このプロジェクトは、Spring MVC の上に API Gateway を構築するためのライブラリを提供します。Spring Cloud Gateway は、API にルーティングするためのシンプルでありながら効果的な方法を提供し、セキュリティ、モニタリング / メトリック、復元力などの横断的な懸念を API に提供することを目的としています。

つまり?

マイクロサービス間などでOAuth2などの認証問題を解決してくれるフレームワークになります。アプリ間のルーティングもしてくれるので認証機能を備えたAPI上のプロキシーのような存在になります。

アーキテクチャ

それぞれの役割をわかりやすくするため図で見てみましょう。

全体的なアーキテクチャ図

仮にVue.jsなどのFront AppからGatewayのURLにアクセスするとCognito(AWSの場合)などのIDMとOAuth2認証を行い、指定のResource APIと通信ができるようになります。

後述しますが、Front to Gateway間はSessionで状態管理されており、Gateway to API間はJWTの形式で認証のやり取りがされます。

なのでAPI側はJWTの認証チェックだけ行えばOKということになります。(APIはSpringがBetterではあるが別言語でもSo Good)

Workshop

この記事でWorkshopを作ってもよいのですが、大変長くなるので認証サーバのUAAを使用したこちらのRepositoryを進めると理解が深まると思います。

認証の手順

導入する目的・メリット

  • Front, BFFにAccessTokenを持たせないための設計ができる
  • OAuth2の複雑な認証フローを自分で開発したくない
  • 認証に必要な設定情報を埋め込むだけで認証を行う役割をもつ
  • 認証部分が独立しているため他言語APIと連携も容易なのでマイクロサービスアーキテクチャの認証部分として適している。
  • 再利用が可能!!!

ちなみに

マイクロサービス関係なくAPI内に認証を入れる場合であれば、Spring OAuth2 Clientを設定しても良い

デメリット。。。

Spring Cloud GatewayというよりSpring 5のWebFluxの問題かもしれませんが、NettyというWebサーバ上でConnectionが切れる問題が多発したり(こちらの記事で解説)、RefreshTokenの自動更新処理などは自分で入れる必要があります。

つまり、既存のISSUEがあり既存問題に対して自分たちの力で解消できるどうかが導入のキーになると思います。

認証の仕組み

わかりやすく図化してみました。一般的にFrontにJWTを直接持つとセキュリティ的にグレー(?)なのでSessionを保持してクレデンシャル情報をサーバ内に内包しているためかなりセキュアであると言えます。

今回はCognito User Poolを使用していると仮定しているためAWS Resourceと疎通しています

アクセストークンの自動更新処理はしてくれないの?

Spring Cloud GatewayのFilter機能により実現できます。通信間に処理を入れ込むことができる。HTTP通信の際に有効期限を確認し、切れていれば更新を行う処理を入れることができます。

該当ISSUE

すでにCloseしてるので標準搭載されるかもしれません。

コードだとこんな感じ

    private static ReactiveOAuth2AuthorizedClientManager createDefaultAuthorizedClientManager(
            ReactiveClientRegistrationRepository clientRegistrationRepository,
            ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {

        final ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
                ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
                        .authorizationCode()
                        .refreshToken(configurer -> configurer.clockSkew(accessTokenExpiresSkew))
                        .clientCredentials(configurer -> configurer.clockSkew(accessTokenExpiresSkew))
                        .password(configurer -> configurer.clockSkew(accessTokenExpiresSkew))
                        .build();
        final DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(
                clientRegistrationRepository, authorizedClientRepository);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

        return authorizedClientManager;
    }

    public GatewayFilter apply() {
        return apply((Object) null);
    }

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> exchange.getPrincipal()
                // .log("token-relay-filter")
                .filter(principal -> principal instanceof OAuth2AuthenticationToken)
                .cast(OAuth2AuthenticationToken.class)
                .flatMap(this::authorizeClient)
                .map(OAuth2AuthorizedClient::getAccessToken)
                .map(token -> withBearerAuth(exchange, token))
                // TODO: adjustable behavior if empty
                .defaultIfEmpty(exchange).flatMap(chain::filter);
    }

    private ServerWebExchange withBearerAuth(ServerWebExchange exchange, OAuth2AccessToken accessToken) {
        return exchange.mutate().request(r -> r.headers(headers -> headers.setBearerAuth(accessToken.getTokenValue()))).build();
    }

    private Mono<OAuth2AuthorizedClient> authorizeClient(OAuth2AuthenticationToken oAuth2AuthenticationToken) {
        final String clientRegistrationId = oAuth2AuthenticationToken.getAuthorizedClientRegistrationId();
        return Mono.defer(() -> authorizedClientManager.authorize(createOAuth2AuthorizeRequest(clientRegistrationId, oAuth2AuthenticationToken)));
    }

    private OAuth2AuthorizeRequest createOAuth2AuthorizeRequest(String clientRegistrationId, Authentication principal) {
        return OAuth2AuthorizeRequest.withClientRegistrationId(clientRegistrationId).principal(principal).build();
    }

どうでも良いけどMonoとかFluxの非同期処理難しいよね。

使い方

基本的に引数ゲーです。こんな感じで設定すれば後々docker-composeファイルにも適用できます。

docker-compose

  spring-cloud-gateway-service:
    build: ./spring-cloud-gateway
    image: barathece91/gateway-service-k8s
    ports:
      - "9500:9500"
    depends_on: 
      - jio-microservice
      - airtel-microservice
      - vodaphone-microservice
    environment:
      SPRING_PROFILES_ACTIVE: path
      SPRING_CLOUD_GATEWAY_ROUTES[0]_URI: http://jio-microservice:9501
      SPRING_CLOUD_GATEWAY_ROUTES[0]_ID: jio-service
      SPRING_CLOUD_GATEWAY_ROUTES[0]_PREDICATES[0]: Path= /jio/*
      SPRING_CLOUD_GATEWAY_ROUTES[0]_FILTERS[0]: StripPrefix=1
      SPRING_CLOUD_GATEWAY_ROUTES[1]_URI: http://airtel-microservice:9502
      SPRING_CLOUD_GATEWAY_ROUTES[1]_ID: airtel-service
      SPRING_CLOUD_GATEWAY_ROUTES[1]_PREDICATES[0]: Path= /airtel/*
      SPRING_CLOUD_GATEWAY_ROUTES[1]_FILTERS[0]: StripPrefix=1
      SPRING_CLOUD_GATEWAY_ROUTES[2]_URI: http://vodaphone-microservice:9503
      SPRING_CLOUD_GATEWAY_ROUTES[2]_ID: vodaphone-service
      SPRING_CLOUD_GATEWAY_ROUTES[2]_PREDICATES[0]: Path= /vodaphone/*
      SPRING_CLOUD_GATEWAY_ROUTES[2]_FILTERS[0]: StripPrefix=1

Sample

kubenetes

kubenetesワカラナイ...サンプルをどうぞ。

https://github.com/spring-cloud/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-examples

関連資料

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Yellowfinの高度な関数を作成する

目的

Yellowfin(BIツール)にはもともと用意された関数の他に、自分で関数を作って拡張できる「高度な関数」というものがあります。これまで使ったことがなく、プログラムを書かないといけないことから手を付けていなかったのですが、幾何平均を求めたいという要望があり、作ってみた感じを記事にしています。個人的には、正直公式のWikiだけではなかなか理解するのが難しいところもあったのでそこをフォローできたらいいなと思います。

はじめに

基本的な開発の始め方としては、Eclipseを使って開発するのですが、高度な関数の基礎を見ながら設定すれば自動的に必要なメソッドがAnalyticalFunctionからOverrideして追加されるので、その中のパラメータを設定して、必要な処理をapplyAnalyticFunctionメソッドの中で記述していく流れになります。

1つのカラムの合計を出す関数(累積合計)であれば、高度な関数の作成を見ればわかると思います。この例では選択したカラムから1レコードずつ足していくだけですね。結果的に、applyAnalyticFunctionのreturnの値がレポートの方に返されます。

公式wikiから抜粋↓

simpleAdvancedFunction.java
import com.hof.mi.interfaces.AnalyticalFunction;

public class AccumulativeTotal
    extends AnalyticalFunction{

    private Double total = 0.0;
    public String getName()
    {
        return "Accumulative Total";
    }
    public String getDescription()
    {
        return "Calculates the accumulative total for the selected field";
    }

    public String getCategory()
    {
        return "Analysis";
    }
    public String getColumnHeading(String colName)
    {
        return "Accumulative Total of " + colName;
    }
    public int getReturnType()
    {
            return TYPE_NUMERIC;
    }
    public boolean acceptsNativeType(int type)
    {
        return type == TYPE_NUMERIC;
    }
    public Object applyAnalyticFunction(int index, Object value) throws Exception
    {
            if (value == null) return null;
            this.total += Double.valueOf(value.toString());
            return this.total;
    }
}

TYPE_NUMERICのような定数については高度な関数付録を参照してください。Integer値と定数とどちらでも大丈夫です。

カラム全体に対しての数値の処理について(例.幾何平均)

image.png

これは詳しくはあまり載っていなかったので手探りで試してみたのですが、高度な関数の作成にしれっと書いてあるpreAnalyticFunctionメソッドを使用します。データセット全体に渡り操作を実行するために使用されます。と書かれているんですがサンプルが書いてないのでイメージしにくいんですよね。先程のコードの追加・変更の部分のみ記載します。

解説としては、preAnalyticFunctionの引数selectedColにカラムの値のオブジェクト配列がレコード分格納されているので、初めだけthis.totalに代入してその後は何回処理を繰り返したかをcntでインクリメントしながら掛けていきます。
最終的に、Math.powで処理を繰り返した数で冪根(累乗根)したものをapplyAnalyticFunctionでそのまま返(表示)しているだけです。

geometricMean.java
    private int cnt = 0;//add
    public Object applyAnalyticFunction(int index, Object value) throws Exception {//modify method
        // TODO Auto-generated method stub
        if (value == null) return null;
        return this.total;
    }

    public void preAnalyticFunction(Object[] selectedCol){//add method
        this.total=0.0;
        for (Object value : selectedCol) {
            if (value!=null) {
                if(this.total==0.0){
                    this.total = Double.valueOf(value.toString());
                } else {
                    this.total= this.total * Double.valueOf(value.toString());
                }
                cnt++;
            }
        }
        this.total = Math.pow( this.total, (double)1/cnt);
    }

    public Object applyAnalyticFunction(int index, Object value) throws Exception {//modify
        // TODO Auto-generated method stub
        if (value == null) return null;
        return this.total;
    }

選択したカラムに対して他のカラムを比較したい・他のカラムも含めて処理したい場合(例.共分散)

image.png

高度な関数を使用するカラムの他に任意のカラムに対しての影響・比較をしたい時にユーザーにカラムを指定させて関数を実行するといったこともできるようです。
これもwikiでは分かりづらかったのですが、パラメーターセットアップのsetupParametersのaddParameterメソッドを通してパラメーターに加えることでgetParameterValue("ユニークキー")でその設定したパラメーターが取得できます。この時にparameterのsetDataTypeをTYPE_FIELD(100)にすることで任意のカラムを選択できるようになります。
image.png

コードの解説ですが、これも一番初めのwikiのコードからの変更点のみ記載します。
preAnalyticFunctionで高度な関数を適用した値(selectedCol)のオブジェクト配列と、早速getParameterValueで先程解説したユニークキー"FIELD_SELECTION"のカラムの値(inputColumn)のオブジェクト配列を取得し(上の画像では要素1)、それぞれDouble型にキャストして配列に加えていきます。そこでこの2つの配列をcovarianceに渡して共分散の値を取得しています。
covarianceとsumメソッドについては共分散と合計を求めるだけなので解説を割愛します。

covariance.java
import java.util.ArrayList;//add
import java.util.List;//add

    private List<Double> items1 = new ArrayList<>();//add
    private List<Double> items2 = new ArrayList<>();//add

    protected void setupParameters() {//add
       Parameter p = new Parameter();
       p.setUniqueKey("FIELD_SELECTION");
       p.setDisplayName("Column");
       p.setDescription("Compare this numeric field to the selected field");
       p.setDataType(TYPE_FIELD);//100
       p.setAcceptsFieldType(TYPE_NUMERIC, true);
       p.setDisplayType(DISPLAY_SELECT);//6
       addParameter(p);
    }

    public void preAnalyticFunction(Object[] selectedCol){//add
        this.total=0.0;
        Object [] inputColumn = (Object[]) getParameterValue("FIELD_SELECTION");
          for (Object value : selectedCol) {
            items1.add(Double.valueOf(value.toString()));
          }
          for (Object value : inputColumn) {
              items2.add(Double.valueOf(value.toString()));
          }
          Double r = covariance(items1, items2);
          this.total = r;
    }

    public Object applyAnalyticFunction(int index, Object value) throws Exception {//modify
        // TODO Auto-generated method stub
        if (value == null) return null;
        return this.total;
    }

    public Double covariance(final List<Double> items1, final List<Double> items2) {//add
        List<Double> items3 = new ArrayList<>();
        int n = items1.size();
        Double i1Mean = sum(items1)/n;
        Double i2Mean = sum(items2)/n;
        for (int i = 0; i < n; i++) {
            items3.add((i1Mean - items1.get(i)) * (i2Mean - items2.get(i)));
        }
        Double i3Sum = sum(items3);
        return i3Sum / n;
    }

    public Double sum(final List<Double> items) {//add
        Double result = 0.0;
        for (Double item : items) {
            result += item;
        }
        return result;
    }

ということで

少し説明が長くなってしまいましたが、高度な関数を作成することでレポートで表現するには少しめんどくさいこと(多重なreportFromReportなど)をJavaで書ける範囲ですぐに値を出すことができるようになり、コーディングの手間はかかりますが、いつも社内で使っているある一定の式を当てたい・2つのカラムの関係性を求めたいなどの処理を簡単にてきようできるようになりますね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クラスとインスタンス 初心者向け Java

環境
・MacBookpro
・IntelliJ IDEA CE

Java学習中アウトプットのため投稿します。

クラスとインスタンスについて

クラス・・・設計書、骨組み
インスタンス・・・クラスを元に作られた実体

あなたは上司から大量生産猫型ロボット工場から、人間界世話型ロボットとその妹ロボットを1体ずつ作るよう指示を受けました。

上司から詳細データが渡されました。

人間界世話型ロボットについて
名前:ドラ絵もん
色:青
性別:男

ドラ絵もんの妹ロボットについて
名前:ドラ美ちゃん
色:ピンク
性別:女

以上2体を作成するように。

詳細データを見ると3要素が必要です。
・名前(name)
・色(color)
・性別(sex)

それではまず上司の指示通りのクラスを完成させます。

Robot.java
class Dora {
    String name;
    String color;
    String sex;

    Robot(String name, String color , String sex){
        this.name = name;
        this.color = color;
        this.sex = sex;
    }

    String sayBox(){
        return name +"です。色は、"+color+"です。性別は"+sex+"です。";
    }
}

これでクラスが作れました。

次はインスタンス(詳細)を作ります。

RobotFactory.java
public class RobotFactory {
    public static void main(String[] args){
        Dora robota = new Dora("ドラ絵もん","青","男");
        System.out.println(robota.sayBox());

        Dora roboco = new Dora("ドラ実ちゃん","ピンク","女");
        System.out.println(roboco.sayBox());
    }
}


出力してみます。
スクリーンショット 2020-10-14 14.57.28.png

成功です。:relaxed:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javaでwebApi備忘録

事前準備

・エクリプスの最新版

①eclipsのインストール方法
https://snome.jp/framework/springboot-install-win/
SpringBootの使用の前までで完了
ワークスペースのなぞ?
Eclipse はワークスペースとして指定されてディレクトリに “.metadata” という隠しディレクトリを作るので、これを検索します。
②Javaコンパイラの設定
特に設定しなくてもOK
③WEBAPIの作成方法
 サンプルを元にマーベンのPOMを変更
 https://codezine.jp/article/detail/11380?p=3
 
 ④Java Spring Boot JSONの送信と受信のサンプル
 https://itsakura.com/java-springboot-json#s7
ハローワールドの出し方
https://qiita.com/kuro227/items/d7da647e9f3be78a5f92
アクセスするURL
http://localhost:8081/hello/
リファレンスAPI スプリング
https://spring.pleiades.io/guides/tutorials/bookmarks/
マーベンのPOM
https://mvnrepository.com/search?q=javax.validation
spring boot で web api サーバを作る
https://qiita.com/kuro227/items/d7da647e9f3be78a5f92
修正点
・HelloWorldController.java
・Syain.java

ファイル(test.html)
```java

でマッピング
@RequestMapping(method = RequestMethod.GET)
public String getHello() {
return "hello world!";
}
file:///C:/Users/shimizu/Desktop/test2.html
でここにマッピングされる
@RequestMapping(value = "/index",method = {RequestMethod.POST})
@ResponseBody
public Syain output1(
@RequestBody Syain syain) {
System.out.println(syain.getBangou());
System.out.println(syain.getName());
return syain;
}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker, java, vscodeの開発環境を構築

前回の記事

初心者がdocker for macをインストールしてphp7.0の動作環境を用意する

この記事

前回はphp7.0の動作環境を用意しました。
今回はjavaを用意してみます。
目標はdocker + java + vscode。

参考記事

Visual Studio CodeのRemote DevelopmentとDockerで快適な開発環境をゲット

Remote Development

Remote Developmentの拡張機能をインストール

Microsoftが公開してるテストプロジェクトのクローンを用意

git
git clone https://github.com/Microsoft/vscode-remote-try-java

テストプロジェクトを開く

Visual Studio Codeの左下の緑のボタンをクリック>Remote-Containers: Open Folder in Container>gitのクローンフォルダを選択

dockerでコンテナが起動しているか確認

スクリーンショット 2020-10-14 8.17.54.png

ビルドしてプロジェクトが動作するか確認

スクリーンショット 2020-10-14 8.20.36.png

まとめ

前回の記事の方法よりRemote Developmentを使用するのが簡単ですね。
javaのバージョンも選択できるみたい。
ありがとう、Microsoft!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む