20200916のJavaに関する記事は10件です。

Java カプセル化について private public

カプセル化とは

参考: 「徹底攻略 Java SE 11 Silver 問題集」から引用:

カプセル化は、ソフトウェアを分割する際に、関係するデータとそのデータを必要する処理を1つにまとめ、無関係なものや関係性の低いものをクラスから排除することで「何のためのクラスなのか?」というクラスの目的を明確化するために行い、ほかのクラスに重複するデータや処理がない状態を目指すもの。

修飾子
private 設定するとクラス外からアクセスする事ができなくなる(クラス内では可能) 非公開状態
public クラスの外からでもアクセスする事が可能  

ユーザが入力した値が0から10の場合private変数numに代入し表示する

class Number {
  private int num;//外からはアクセスできなくする

  public void setNum(int n){
    if(n >= 0&&n <= 10){
       num = n;
    }else{
      system.out.println("入力された値は無効です。");
    }
  }
  public int getNum(){//
    return num; //戻り値を返す
  }
}
import java.io.*;
class Sample {
  public static void main(String[] args) throws IOException{
    BufferedReader br = new BufferedReader(new inputstreamreader(system.in))
    String str = br.readLine();//8を入力した事にします。
    n = Integer.parseInt(str);
    Number nb1 = new Number();  
    //このようなアクセスはできない
    //nb1.num = 8;
    nb1.setNum(n);
    system.out.println("入力された値は"+nb1.getNum()+"です。");
  }
}

private変数を更新する為に同じクラス内のpublicメソッドを使い条件式を設定し通過した変数にのみ変数を更新する事で誤った値の更新を防ぐ事ができる。

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

Java クラス変数 クラスメソッドについて

それぞれの変数、メソッドについて

・インスタンス変数
各オブジェクトに関連づけされているフィールド(変数)の事を指す。
・インスタンスメソッド
各オブジェクトに関連づけされているメソッドの事を指す。

・クラス変数
クラス全体に関連づけされているフィールドの事を指す。
・クラスメソッド
クラス全体に関連づけされているメソッドの事を指す。

クラス変数定義方法

class Car {
    public static int Car //クラス変数 型名の前にstaticが必要 publicは修飾子
}                 型名 クラス名

クラスメソッド定義方法

class Car {
  public static void show(); //クラスメソッド
                     メソッド名
}
Carクラスファイルを利用するプログラムでクラスメソッドshow()を呼び出す方法
Car.show();

クラスメソッドの特徴

・クラスメソッドはオブジェクトが作成されていなくても呼び出せる。
・クラスメソッド内ではインスタンス変数、インスタンスメソッドにアクセスする事はできない。

余談
メソッド内で宣言した変数はローカル変数といい、宣言したメソッド外では利用する事ができず、値を格納しているのはメソッドが終了するまで。

class Car{
  int num;//ローカル変数
  static int sum;//クラス変数
  void setCar(int a){//ローカル変数
    int a //ローカル変数
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PowerMockでstaticイニシャライザを無効化する

目次

  1. PowerMockを使うための環境構築手順
  2. PowerMockにおけるモックとスパイ
  3. PowerMockでstaticメソッドをモック化する
  4. PowerMockでコンストラクタをモック化する
  5. PowerMockでprivateメソッドをモック化する
  6. PowerMockのWhiteBoxを使ってみる
  7. PowerMockでstaticイニシャライザを無効化する ←今ここ

概要

PowerMockにはstaticイニシャライザを無効化するための@SuppressStaticInitializationForというアノテーションが提供されています。

使用例

モック化クラス

クラスがロードされる際に、staticイニシャライザによってフィールドに"value"という文字列が設定されます。

ここでは、フィールドに"value"が設定されていればtrueを返し、そうでなければfalseを返すjudgeメソッドを用意しました。

SampleEm.java
public class SampleEm {

    private static String field = null;

    static {
        field = "value";
    }

    public boolean judge() {
        return "value".equals(field);
    }
}

テストクラス

JUnitでPowerMockを使用するために、@RunWithにはPowerMockRunnerを指定します。

@PrepareForTestには、モック化するクラスを指定します。

@SuppressStaticInitializationForにもモック化するクラスを指定するのですが、@SuppressStaticInitializationFor(SampleEm.class)ではない点に注意が必要です。

@RunWith(PowerMockRunner.class)
@PrepareForTest(SampleEm.class)
@SuppressStaticInitializationFor("jp.co.sample_powermock.staticinitializer.SampleEm")
public class SampleEmTest {

    @Test
    public void test() throws Exception {
        // 実行
        SampleEm em = new SampleEm();
        boolean result = em.judge();

        // 結果確認
        assertFalse(result);
    }
}

テストを実行すると、staticイニシャライザが無効化されることによりフィールドに"value"が設定されないため、このJUnitは成功します。

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

Visitorパターン

Visitorパターンとは

データ構造と処理を分離する。
データ構造を巡り歩く訪問者を表すクラスを用意し、そのクラスに処理を任せる。
データ構造側は、訪問者を受け入れてやる。

Visitor(訪問者)の役

Visitor役はデータ構造の具体的な要素(ConcreteElement役)ごとに「xxxを訪問した」という
visit(xxx)メソッドを宣言する。
visit(xxx)はxxxを処理するためのメソッドで、実際のコードはConcreteVisit役の側に書かれる。

package visitor;

public abstract class Visitor {
    public abstract void visit(File file);
    public abstract void visit(Directory directory);
}

ConcreteVisitor(具体的訪問者)の役

ConcreteVisitor役はVisitor役のインターフェースを実装する。
visit(xxx)という形のメソッドを実装し、個々のConcreteElement役ごとの処理を記述する。

package visitor;

import java.util.Iterator;

public class ListVisitor extends Visitor{
    private String currentDir = "";

    @Override
    public void visit(File file) {
        System.out.println(currentDir + "/" + file);
    }

    public void visit(Directory directory) {
        System.out.println(currentDir + "/" + directory);
        String savedDir = currentDir;
        currentDir = currentDir + "/" + directory.getName();
        Iterator<Entry> it = directory.iterator();
        while (it.hasNext()) {
            Entry entry = it.next();
            entry.accept(this);
        }
        currentDir = savedDir;
    }
}

Element(要素)の役

Element役はVisitor役の訪問先を表す役。
訪問者を受け入れるacceptメソッドを宣言する。
acceptメソッドの引数にはVisitor役が渡される。

package visitor;

public interface Element {
    public abstract void accept(Visitor v);
}

ConcreteElement(具体的要素)の役

ConcreteElement役はElement役のインターフェースを実装する役。

package visitor;

public class File extends Entry{
    private String name;
    private int size;

    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public String getName() {
        return name;
    }

    public int getSize() {
        return size;
    }

    @Override
    public void accept(Visitor v) {
        v.visit(this);
    }
}
package visitor;

import java.util.ArrayList;
import java.util.Iterator;


public class Directory extends Entry{
    private String name;
    private ArrayList<Entry> directory = new ArrayList<>();

    public Directory(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public int getSize() {
        int size = 0;
        Iterator<Entry> it = directory.iterator();
        while (it.hasNext()) {
            Entry entry = (Entry) it.next();
            size += entry.getSize();
        }
        return size;
    }

    public Entry add(Entry entry) {
        directory.add(entry);
        return this;
    }

    public Iterator<Entry> iterator() {
        return directory.iterator();
    }

    public void accept(Visitor v) {
        v.visit(this);
    }
}

ObjectStructure(オブジェクト構造)の役

ObjectStructure役はElement役の集合を扱う役。
ConcreteVisitor役が個々のElement役を扱えるようなメソッドを備えている。
この役は上記のDirectoryクラスが該当する。

呼び出し元

package visitor;

public class Main {
    public static void main(String[] args) {
        try {
            System.out.println("Making root entries...");
            Directory rootDir = new Directory("root");
            Directory binDir = new Directory("bin");
            Directory tmpDir = new Directory("tmp");
            Directory usrDir = new Directory("usr");
            rootDir.add(binDir);
            rootDir.add(tmpDir);
            rootDir.add(usrDir);
            binDir.add(new File("vi", 10000));
            binDir.add(new File("latex", 20000));
            rootDir.accept(new ListVisitor());

            System.out.println();
            System.out.println("Making user entryies...");
            Directory yuki = new Directory("yuki");
            Directory hanako = new Directory("hanako");
            Directory tomura = new Directory("tomura");
            usrDir.add(yuki);
            usrDir.add(hanako);
            usrDir.add(tomura);
            yuki.add(new File("diary.html", 100));
            yuki.add(new File("Composite.java", 200));
            hanako.add(new File("memo.tex", 300));
            tomura.add(new File("game.doc", 400));
            tomura.add(new File("junk.mail", 500));
            rootDir.accept(new ListVisitor());
        } catch (FileThreatmentException e) {
            e.printStackTrace();
        }
    }
}

実行結果

スクリーンショット 2020-09-16 18.12.57.png

https://github.com/aki0207/visitor

こちらを参考にさせていただきました。
増補改訂版Java言語で学ぶデザインパターン入門

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

OrientJSとOrientDBの併用方法

このチュートリアルでは、Alibaba Cloud上でOrientDBを設定し、OrientDBと一緒にOrientJSの使い方を探っていきます。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

前提条件

このチュートリアルは中程度の難易度と言えます。そのため、このチュートリアルでは、いくつかの関連する背景知識が必要となります。また、このチュートリアルを進める前に、いくつかの設定をしておくことも大前提となります。具体的には、以下のものが必要です。

1、Linuxのコマンドラインインターフェースの機能についての一般的な理解。
2、Alibaba Cloud の ECS セキュリティグループの一般的な理解。
3、Java(具体的には1.7以降)がインストールされており、関連する環境変数も設定されていること。
4、JavaScriptの一般的な理解。

Alibaba Cloud ECSへのOrientDBのインストール

このチュートリアルの最初のステップとして、Alibaba Cloud Elastic Compute Service (ECS) インスタンスを作成する必要があります。このチュートリアルでは、Ubuntuがインストールされ、ワンコアプロセッサと512MBのメモリを持つECSインスタンスを作成します。次に、SSHを使用するか、Alibaba Cloudコンソールを介してインスタンスにログオンします。その方法については、まだ知らない場合は、このガイドをチェックしてください。

次に、適切なバイナリパッケージをインストールする必要があります。まず、OrientDBの最新の安定版リリースをダウンロードします。あるいは、ウェブサイトから手動でダウンロードするのではなく、以下のコマンドを使って OrientDB 3.0.21 をダウンロードしてみることもできます。

curl  https://s3.us-east-2.amazonaws.com/orientdb3/releases/3.0.21/orientdb-3.0.21.tar.gz

ダウンロードが完了すると、最初に curl コマンドを入力したディレクトリに orientdb-3.0.21.tar.gz という名前の zip ファイルが存在します。その後、zip ファイルの内容を展開し、環境変数 ORIENTDB_HOME の下の適切なディレクトリに移動します。現在のバージョンに応じた対応するコマンドは以下の通りです。

  • tar -xvzf orientdb-3.0.21.tar.gz: フォルダを解凍します。
  • cp -r orientdb-3.0.21 /opt: フォルダ全体を/optディレクトリにコピーするために使用します。 /etc/environmentの内容は以下のようにします。
JAVA_HOME=/usr/lib/jvm/java-8-oracle
ORIENTDB_HOME=/opt/orientdb-3.0.21
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games :$ORIENTDB_HOME/bin" 

このチュートリアルの前提条件であるJava 1.7以降がインストールされていること、およびUbuntuでインストールされたインスタンスにスワップ領域が追加されていること、つまり、新しいインスタンスサーバーであり、まだインストールされていない場合です。

注: OrientDB を更新した後、必要であれば、このファイルをソースにして、新しい OrientDB の実行ファイルがターミナルで利用できるようにする必要があります。これに使用するコマンドは次のとおりです: source /etc/environment.

ここで、ORIENTDB_DIR の代わりに ORIENTDB_HOME の OrientDB ディレクトリの場所(もちろん ORIENTDB_HOME)と、USER_YOU_WANT_ORIENTDB_RUN_WITH の代わりに使用したいシステムユーザを入力して、ORIENTDB_HOME/bin にある orientdb.sh ファイルを編集する必要があります。

OrientDBのインストールが完全に機能している状態で、以下のコマンドでOirentDBサーバを制御することができます。

  • orientdb.sh status: サーバが稼働しているかどうかをチェックするために使用します。
  • orientdb.sh start: OrientDB サーバを起動するために使用します。
  • orientdb.sh stop: OrientDB をシャットダウンするために使用します。

ほとんどの場合、本番環境では非常に安全なインストールが必要です。つまり、どのユーザーも自分の意思でデータベースを起動したり停止したりする権限を持たないような、安全なOrientDBのインストールが必要になります。そのため、OrientDB bin/orientdb.shファイルでは、USER_YOU_WANT_ORIENTDB_RUN_WITHの代わりに管理ユーザーを入力することができます。そうすることで、管理者としてOriendDBの最も賢明なコマンドの完全な権利を持つ唯一のユーザーになることを意味します。

この種のことをもっと知りたい方は、OrientDBのドキュメントを見てください。

さて、これでこれらのことはすべて完了しましたので、次に進みましょう。orientdb.sh startコマンドを実行してインストールをテストすることができます。次のスクリーンショットに示すように、ポータル、特にOrientDB Studioには、http://our_ecs_ip:2480 または http://localhost:2480 のいずれかのアドレスからアクセスすることができます。

image.png

OrientDB に接続してダッシュボードにアクセスするためには、ここで説明したように $ORIENTDB_HOME/config/oritdenb-server-config.xml ファイルの最後にユーザーを定義する必要があります。

次に、2480番ポート(OrientDB Studioのポート)にインスタンスセキュリティグループを設定することを忘れないでください。

注: 外部からアクセスできるように設定する必要があります。

以下は、テスト用インスタンスの設定の出力です。

image.png

OrientJsの設定

OrientDBのOrientJSモジュールは、JavaScriptプロジェクトのための公式のOrientDBドライバとして記述することができます。これは、NodeJSの開発者の間で広く使われています。もちろん、他のパッケージと同様に、node package managerを使ってインストールするには、たった一つのコマンドが必要です。具体的には、ローカルにインストールするには、npm install orientjsコマンドを実行します。

そして、OrientJSがインストールされて初期化されると、以下のようなことができるようになります。

OrientJSの初期化

OrientJSとOrientDBを相互に連携させるための最初のステップは、サーバーAPIを初期化することです。これを行うことは、OreintJSがOrientDBのサーバーAPIと対話できるようにするために重要です。なぜなら、OrientDBサーバーのホストとそのポートにデータベースユーザーが接続されている必要があるからです。

// Initializing the Server API
var server = OrientDB({
  host:       'localhost',
  port:       2424,
  username:   'admin',
  password:   'admin'
});

注: この場合、ユーザー資格情報には admin:admin を使用しています。しかし、これはOrientDB設定ファイルに設定した対応する資格情報に変更する必要があります。

データベースのリスト

このチュートリアルの次のステップは、OrientJSを使って単一のクエリを実行して、ここまでに作成したすべてのデータベースを一覧表示することです。これに続いて、通常はDBオブジェクトを返すように、各データベースの名前とタイプを表示しています。

// Databases listing
server.list()
  .then(list => {
    console.log(list.length + ' databases created so far');

    list.forEach(db => {
      console.log(db.name + ' - ' + db.type);
    });
  });

データベースの作成

それでは、サーバーAPIからデータベースを作成する作業に移りましょう。これは比較的簡単です。この操作は、先ほど作成したデータベースオブジェクトとの約束を返す単一のコマンドでも行うことができます。

以下は、Create関数に関連するOrientJsの型の内容です。

/**
 * Create a database with the given name / config.
 *
 * @param  config The database name or configuration object.
 * @promise {Db}                  The database instance
 */
create(name: string | DbConfig): Promise<Db>;

この関数にコンフィギュレーション・オブジェクトまたは単にデータベース名を提供することで作成操作が完了することが明記されています。しかし、以下に示す2つ目のケースでは、デフォルト値は欠落しているフィールドのために選択されることになります。ここでは、設定オブジェクトを使ってデータベースを作成する方法を説明します。

// Creating a database
server.create({
    name:     'NewDatabase',
    type:     'graph',
    storage:  'plocal',
  }).then(dbCreated => {
    console.log('Database ' + dbCreated.name + ' created successfully');
  });

既存のデータベースを使用

データベースが作成された後は、後からインスタンスを取得して、より多くの操作を行うことができます。データベースのインスタンスを初期化するには、以下のメソッドを使用します。

var db = server.use('NewDatabase');

バージョン2.1.11からは、ODatabaseクラスを使ってServer APIを初期化し、すぐにデータベースに接続することも可能になりました。そのための構文は以下の通りです。

var ODatabase = require('orientjs').ODatabase;
var db = new ODatabase({
  host:     'localhost',
  port:     2424,
  username: 'admin',
  password: 'admin',
  name:     'NewDatabase'
});

console.log('Connected to: ' + db.name);

レコードAPI

データベースインスタンスが初期化されると、保存されたレコード、つまりデータベースに保存された情報を、データベースのレコードID(RID)を使用して取得したり操作したりすることができます。

注意: レコード ID は一意の値なので、一般的な SQL ベースのリレーショナル・データベースのように、主キーを参照するフィールドをもう 1 つ作成する必要はありません。

レコードIDの構文は以下の通りです。#<cluster>:<position>となります。このコードの場合

  • cluster:クラスタ識別子として機能します。これはクラスタが属するクラスタレコードを直接参照します。このパラメータの値は、正の値は永続的なレコードを示し、負の値は一時的なレコードを示します。
  • position:クラスタへのレコードの絶対位置を指定します。 ここでは、レコードの RID を指定して 1 つのレコードを取得してみましょう。
db.record.get('#1:1')
  .then(
    function(article) {
        console.log('Loaded article:', article);
      }
  );

レコードを取得したので、いくつかの操作について説明します。まず、削除操作です。一般的には、レコードの削除は比較的簡単で、以下のコードで行うことができます。

db.record.delete('#1:1');

次に、更新操作です。レコードの更新は少し複雑ですが、それでも私の中では問題ありません。更新したい対応するデータが読み込まれた後に行うことができます。以下に、更新関数の実装方法を示します。

db.record.get('#1:1')
  .then(function(article) {
    article.title = 'New Title';
    db.record.update(article)
      .then(function() {
        console.log("Article updated successfully");
      });
  });

注意:このコードを使用する際には、以下のことを考慮してください。

- The an asterisk (#) prefix is required to recognize a Record ID.
- When creating a new record, OrientDB selects the cluster to store it using a configurable strategy, which can be the default strategy, the round-robin one, or a balanced or local strategy.
- Also, note that, in our example, #1:1 represents the RID. 

クラスAPI

データベースの派生オブジェクトは、クラスにアクセスしたり、作成したり、操作したりするために特別に使用されます。具体的には、"クラス "と言うとdb.classのことを指します。例えば、ここにクラスを作成するためのメソッドがあります。

// Creating a new class(Article) using the Class API
var Article = db.class.create('Article');

既存のクラスを取得するには、以下のようにします。

var Article = db.class.get('Article');

これらはすべてプロミスを返していることに注意しましょう。プロミスが解決したら、さらにアクションを実行することを意識したスタイルになります。現在接続しているデータベースに保存されているすべてのクラスのリストを返すには、次のコードを適用します。

// List all the database classes
db.class.list()
  .then(
    function(classes){
      console.log(classes.length + ' existing classes into ' + db.name);

      classes.forEach(cl => {
        console.log(cl.name);
      });
    }
  );

次に、作成操作があります。クラスを作成することは、データベース構造を完全に設計する前に知っておいた方が良いことです。私たちは、プロパティを操作する前に作業するクラスを正しくロードしなければなりません。

Articleのクラスのプロパティのリストは次のようになります。

db.class.get('Article').then(function(Article) {
  Article.property.list()
  .then(
    function(properties) {
       console.log(Article.name + ' has the properties: ', properties);
    }
 );
});

プロパティの作成は、ほぼ同じ構文で行われます。

db.class.get('Article').then(function(Article) {
  Article.property.create([{
    name: 'title',
    type: 'String'
  },{
    name: 'content',
    type: 'String'
  }]).then(
    function(properties) {
      console.log("Successfully created properties");
    }
  );
});

クラスには1つのプロパティを設定するだけです。多くのプロパティを設定する必要はありません。では、いくつかのアクションを実行してみましょう。

まず、プロパティを名前で削除してみましょう。

db.class.get('Article').then(function(Article) {
  Article.property.drop('peroperty_to_drop').then(function(){
    console.log('Property deleted successfully.');
 });
});

続いて、プロパティ名を変更してみましょう。

db.class.get('Article').then(function(Article) {
  Article.property.rename('old_name', 'new_name').then(function(p) {
    console.log('Property renamed successfully');
 });
});

Class API の詳細については、こちらのドキュメントを参照してください。

OrientDB でのクエリ

クエリは、データをより良く管理するために、データベースエンジンが提供する最も重要な操作の一つであり、OrientDBでは2つの方法のいずれかでクエリを実行することができます。直接SQLリクエストを発行するか、Query Builderを使用してNodeJsで暗黙的にクエリを構築するかのどちらかです。

// Find articles viewed 200 times
var numberViews = 200;
db.query(
   'SELECT title, content FROM Article '
   + 'WHERE number_views = :numberViews,
   { params: { numberViews: numberViews, } }
).then(function(articles) {
   console.log(articles);
});

上のクエリでは、200回閲覧された記事を探しています。このクエリは比較的簡単に実行できます。この可能性を利用してエンジンに命令を出す方法は、AND, OR, LIKEなどの演算子を使って、より面白いSQL構文を使うことができます。リクエストのサブストリングとパラメータを連結してSQL文字列を完全に構築するのではなく、パラメトリック化されたリクエストを使用するこの可能性(より簡単)。OrientDBのSQL構文についての詳細はこちらを参照してください。

SQL クエリを完全に記述する代わりに、代わりに Query Builder を使用することができます。クエリビルダは、データベースAPIアクションを通じて内部的にクエリを実行している特定のメソッドを呼び出すことができるように機能します。ここでは、SQL で行ったのと同じクエリを Query Builder で実行しています。

var numberViews = 200;
var query = db.select('title, content').from('Article')
  .where({ "number_views": numberViews })
  .all();

イベント情報

OrientDBでは、イベントはコールバックメソッドとして機能し、クエリの終了時や開始時に実行することができます。イベントは、クエリのデバッグや、ログの記録、プロファイリング、データを調整するための特別なタスクの実行に便利です。イベントはデータベースに依存します。つまり、各イベントは単一のデータベースにアタッチされ、その作成には Database API を使用する必要があります。このAPIを使用する場合は、db.on()関数を使用します。以下の例では、BeginQueryイベントを使用して、OrientDBサーバに送信された全てのクエリをログに記録しています。(クエリの終了には endQuery を使用することもできます)。

db.on("beginQuery", function(queryObj) {
  console.log('DEBUG: ', queryObj);
});

結論

このチュートリアルでは、Alibaba Cloud ECSインスタンス上でOrientDBを設定する方法を見てきましたが、OrientDBと一緒にOrientJSを使用する方法も探ってきました。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

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

private public について

アクセス修飾子ってなに?とりあえずつけとこ。という程度の理解しかなかったのですが、なぜ存在しているのかを学ぶことができたので自分の復習のためにかいときます。

publicとprivateの違い

イラスト7 31.png

アクセス修飾子が必要な理由

・外部からアクセスされてはまずい変数やメソッドへのアクセスを遮断できる
わかる
・保守を容易にする
例 メソッドの修正が必要となる
       ↓       
publicを使っているものがたくさんあることにより、アクセスできる機能がたくさんでてくる
       ↓       
アクセスできる機能すべてが正常に動いているか確認しなければならない(修正により元の機能が失われていないか確認が必要)
       ↓       
そうならないためにも必要不可欠なデータ以外はprivateに設定してアクセスできる範囲を絞っておく

他にも様々な理由があると思うのですが私が理解した範囲をかかせて頂きました。

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

Java の org.w3c.dom.Document オブジェクトと XML 文字列を変換する

サンプルコード

MyApp.java というファイル名で以下のサンプルコードを保存する。

import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;

/**
 * XML 文字列と Document オブジェクトの変換サンプルコード (文字エンコーディングは UTF-8 固定)。
 */
public class MyApp {

  /**
   * XML 文字列を Document オブジェクトに変換します。
   * @param xml XML 文字列
   * @return Document オブジェクト
   * @throws ParserConfigurationException
   * @throws SAXException
   * @throws IOException
   */
  public static Document toDocument(String xml) throws ParserConfigurationException, SAXException, IOException {
    try (StringReader reader = new StringReader(xml)) {
      InputSource source = new InputSource(reader);
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      return builder.parse(source);
    }
  }

  /**
   * Document オブジェクトを XML 文字列に変換します。
   * @param doc Document オブジェクト
   * @return XML 文字列
   * @throws IOException
   * @throws TransformerException
   */
  public static String toString(Document doc) throws IOException, TransformerException {
    try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
      TransformerFactory factory = TransformerFactory.newInstance();
      Transformer transformer = factory.newTransformer();
      // 指定しなくてもデフォルトは UTF-8 だったりする
      transformer.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name());
      DOMSource source = new DOMSource(doc);
      StreamResult result = new StreamResult(output);
      transformer.transform(source, result);
      return output.toString(StandardCharsets.UTF_8);
    }
  }

  // 動作確認用メソッド
  public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException, TransformerException, XPathExpressionException {

    // 動作確認用の XML 文字列を用意
    // Java 15 から使える Text Blocks 機能による文字列リテラルを利用
    String xml = """
      <?xml version="1.0" encoding="UTF-8"?>
      <feed xml:lang="ja-JP" xmlns="http://www.w3.org/2005/Atom">
        <id>helloworldfeed</id>
        <author>niwasawa</author>
        <title>Hello World フィード</title>
        <updated>2000-08-06T00:00:00+09:00</updated>
        <entry>
          <id>helloworldfeed:helloworld1</id>
          <title>Hello World こんにちは世界</title>
          <content>Hello World こんにちは世界</content>
          <updated>2000-08-06T00:00:00+09:00</updated>
        </entry>
      </feed>
      """;

    // XML 文字列を Document オブジェクトに変換
    System.out.println("***** XML 文字列を Document オブジェクトに変換 *****");
    Document doc = toDocument(xml);
    System.out.println("タイトル: " + XPathFactory.newInstance().newXPath().evaluate("//title", doc, XPathConstants.STRING));
    System.out.println();

    // Document オブジェクトを XML 文字列に変換
    System.out.println("***** Document オブジェクトを XML 文字列に変換 *****");
    doc.setXmlStandalone(true);
    String outputXml = toString(doc);
    System.out.println(outputXml);
    System.out.println();
  }
}

サンプルの実行結果

実行環境: Java 15 (Oracle JDK) + macOS Catalina

$ java MyApp.java
***** XML 文字列を Document オブジェクトに変換 *****
タイトル: Hello World フィード

***** Document オブジェクトを XML 文字列に変換 *****
<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja-JP">
  <id>helloworldfeed</id>
  <author>niwasawa</author>
  <title>Hello World フィード</title>
  <updated>2000-08-06T00:00:00+09:00</updated>
  <entry>
    <id>helloworldfeed:helloworld1</id>
    <title>Hello World こんにちは世界</title>
    <content>Hello World こんにちは世界</content>
    <updated>2000-08-06T00:00:00+09:00</updated>
  </entry>
</feed>

参考資料

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

ローカル(ホストOS)のJavaプログラムからDockerコンテナ上のMySQLにアクセスする

はじめに

自分の技術スタックがあまりにもレガシーで情けなく感じ
レガシーおじさんを脱却し、技術者として再出発したく
勉強を始めました。宜しくお願いします?

ということでまずはDockerを勉強することに。

構築するもの(今回のゴール)

  • 構成図
    MySQL_Dockerトレーニング1.png

  • ソフトウェア情報
    OS:Windows10
    Docker:19.03.12
    Program:Java11
    MySQL:8.0.21
    Adminer:latest
    WebBrowser:なんでも

とりあえず今回はホストOS上の自前のJavaプログラムから
コンテナ上のDBにアクセスするところからチャレンジ。

構築作業

1. Dockerコンテナ作成

DockerHubのMySQLの説明ページにあるdocker-compose.ymlをちょっとアレンジして準備。
DockerHub MySQLページ

# Use root/example as user/password credentials
version: '3.1'

services:

  db:
    image: mysql:8.0.21 #変更
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: hoge #追加
      MYSQL_USER: hoge     #追加
      MYSQL_PASSWORD: hoge #追加
    ports:                 #追加
      - 3306:3306          #追加

  adminer:
    image: adminer:latest
    restart: always
    ports:
      - 8080:8080

#が付いてるところがアレンジ部分。
MySQLイメージはlatestを指定するとバージョンがころころ変わりそうな気がしたので8.0.21を指定。
今回はコンテナ外部からアクセスするため、
適当なDBの追加とポート3306を外部公開するように設定。

上記設定ファイルと同階層のフォルダで
docker-composeコマンドで起動。

docker-compose up

フォアグラウンド実行なのでずらずらログが出るのを見つつ、
別コンソールで立ち上がってるか確認

docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
0c5d267f22ee        mysql:8.0.21        "docker-entrypoint.s…"   26 seconds ago      Up 25 seconds       0.0.0.0:3306->3306/tcp, 33060/tcp   mysql_db_1
258f5885810d        adminer:latest      "entrypoint.sh docke…"   26 seconds ago      Up 25 seconds       0.0.0.0:8080->8080/tcp              mysql_adminer_1

(´・ω・`)おぉー

2. Adminerでテーブル、データ作成

AdminerとはPHPで作られたDB操作できるWebクライアントらしい。
MySQL、Adminerのコンテナが立ち上がってる状態で
http://localhost:8080/
にアクセスすると以下の画面が出るので
さっきのdocker-compose.ymlに記載したDB、ユーザ情報を入れる。
スクリーンショット 2020-09-16 025707.png

そしたらこんな感じの適当なテーブルと
スクリーンショット 2020-09-16 030143.png

こんな感じの適当なレコードを入れて、DBは完了。
スクリーンショット 2020-09-16 030441.png

3. Javaプログラム作成

まずgradleにMySQLドライバの依存関係を記載。

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'eclipse'

repositories {
    mavenCentral()}

dependencies {
    compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.21'
    testImplementation 'junit:junit:4.12'
}

そしてMySQLにSQLクエリを投げて結果を表示するクラスを作成。

public class DockerMySQLAccessor {

    public static void main(String[] args) {

        System.out.println("DockerコンテナのMySQLにアクセスするよ");

        try(Connection con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/hoge?useSSL=false",
                "hoge", // UserId
                "hoge"  // Password
              )) {

            PreparedStatement pstmt = con.prepareStatement("select * from TEST_TBL");
            ResultSet rs = pstmt.executeQuery();

            while (rs.next()) {
                System.out.printf("ID:%d, HOGE:%s \n", rs.getInt("ID"), rs.getString("HOGE"));
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

4. 実行

EclipseからさっきのJavaコードを実行。
スクリーンショット 2020-09-16 032059.png
さっき入れたレコードが取得できてる!
やったぜ。(´・ω・`)v

まとめ

とりあえずDockerを使って手軽に仮想的なDBサーバを立ち上げ、
ローカルのプログラムからアクセスすることができた。

今回はDocker触りということで
設定ほぼ丸写しでしかもいきなりdocker-composeの方を使ったけど
実際の運用ではコンテナ毎にDockerfile作ってイメージを作っていくのかな?
あと、プログラムもコンテナ上で実行し、コンテナ間で通信したいところ。
ここら辺はまた今度。

謝辞

Win10にDockerを入れるの大いに参考にさせて頂きました。感謝<(_ _)>
レガシーエンジニアによるDocker入門

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

Eclipse 画面レイアウト変更方法 (Java編)

画面レイアウト変更方法

参考動画

【Eclipse入門】初心者はまずココをイジれ!「Java編」
 https://www.youtube.com/watch?v=5p_3OudszfA

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

JDK 11 ドキュメント Java 初学者向け

JDK11 の公式ドキュメントです? (All English:flag_us:)

 公式URL ➡ https://docs.oracle.com/en/java/javase/11/

2020-09-16 (5).png

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