動かして覚える山

エンジニアリング関連のことについて色々書いていきます。これは、自分が何ができるかを外部に公開すること。アウトプットの場にすること。他のエンジニアの参考になるものを投稿すること。自分用のメモとしてなどを目的として書いています。ですので、投稿の頻度や質は今の所まばらです。

DynamoDB Hello world とりあえずローカルでDynamoDBを動かしてみる

読者

とりあえずDynamoDBをローカル環境で動かしたい方

紹介すること

Docker上にDynamoDBサーバーを立ち上げ、dockerのaws-cliでDynamoDBのサーバーに問い合わせをする。 テーブルの作成、データのWrite、get-item等によるデータのReadを実施する。 awsの公式サイトのテーブルの作成のサンプルを参考にしています。 ステップ 1: テーブルを作成する - Amazon DynamoDB

環境

Windows 10 Home, WSL2, Docker

ソースコード

https://github.com/syuh31/practice_dynamo_db

DynamoDBを立ち上げる

docker pull amazon/dynamodb-local:1.17.0
docker run -d --name dynamodb -p 8000:8000 amazon/dynamodb-local

止めるときと再起動するとき

docker stop dynamodb
docker restart dynamodb

この方法では作成したテーブル等のデータは保持されないので、保持したい場合は、適切なオプションを設定したりdocker-composeを使って細かい設定をすれば良いと思います。

Dockerのaws-cliをつかって問い合わせしてみる

エイリアスを設定しておき、awsコマンドとして、docker経由のaws-cliを使えるようにしておきます。

alias aws='docker run --rm -it -v $(pwd)/.aws:/root/.aws -v $(pwd):/aws amazon/aws-cli:2.3.4 --endpoint-url http://host.docker.internal:8000'

上記コマンドでは、ローカルの.awsフォルダをマウントするようにしています。 作業用フォルダに、.awsフォルダを準備し、そのフォルダ配下に設定ファイルを配置してください。 設定ファイルは2種類config,とcredentialsファイルです。 どちらもそれを設定していないと設定して!と怒られるため適当な値を設定しています。

config

[default]
region = us-west-2

credentials

[default]
aws_access_key_id = test_key_id
aws_secret_access_key = test_ac_key

この状態で、

aws dynamodb list-tables

を実行してみてください。テーブル一覧が取得できると思います。

テーブルの作成及びデータの追加

ソースコードより、sampleのデータをダウンロードしておいてください。 その状態で、下記のコマンドを実行すると、テーブルと、その中のデータを作ってくれます。

aws dynamodb create-table --cli-input-json file://sample1/table/ProductCatalog.json
aws dynamodb batch-write-item --request-items file://sample1/data/ProductCatalog.json
aws dynamodb create-table --cli-input-json file://sample1/table/Forum.json
aws dynamodb batch-write-item --request-items file://sample1/data/Forum.json
aws dynamodb create-table --cli-input-json file://sample1/table/Thread.json
aws dynamodb batch-write-item --request-items file://sample1/data/Thread.json
aws dynamodb create-table --cli-input-json file://sample1/table/Reply.json
aws dynamodb batch-write-item --request-items file://sample1/data/Reply.json

テーブル上のデータの読み込み

テーブル上のデータを読み込むget-itemとqueryは以下のコマンドで実施できます。

aws dynamodb get-item --cli-input-json file://sample1/get_item_product_catalog_1.json
aws dynamodb query --cli-input-json file://sample1/query_product_catalog_1.json
aws dynamodb query --cli-input-json file://sample1/query_reply_1.json

さいごに

雑な記事ですみません。参考になれば幸いです!

javac でコンパイルはできるが、javaで実行時エラー

使用環境はWindows10です。

次のようなエラーが発生した。

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: HelloWorld has been compiled by a more recent version of the Java Runtime (class file version 57.0), this version of the Java Runtime only recognizes class file versions up to 52.0
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access$100(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

新しいバージョンのコンパイラコンパイルしたクラスファイルは、古いランタイムでは解釈できないから実行できないみたいなことを言っている。 javaとjavacのバージョンを確認してもよくわからない。

C:\Users\syuh31\work\example\java\hello_world>java -version
java version "1.8.0_241"
Java(TM) SE Runtime Environment (build 1.8.0_241-b07)
Java HotSpot(TM) 64-Bit Server VM (build 25.241-b07, mixed mode)

C:\Users\syuh31\work\example\java\hello_world>javac -version
javac 13.0.2

どこのファイル使ってるんだ?

C:\Users\syuh31\work\example\java\hello_world>where javac
C:\Program Files\Java\jdk-13.0.2\bin\javac.exe

C:\Users\syuh31\work\example\java\hello_world>where java
C:\Program Files (x86)\Common Files\Oracle\Java\javapath\java.exe
C:\Program Files\Java\jdk-13.0.2\bin\java.exe

なるほど、そういうことか、使っているjavaが違いますね。 私の場合は、システム環境変数のPATHに C:\Program Files (x86)\Common Files\Oracle\Java\javapath\java.exe が設定されていたので削除しました。 エラーによると、ランタイムのほうが古いといっているので、新しいランタイムを使うようにして問題ないでしょう。 下位互換性はあるはずですから。

修正後のwhichとversionを見ておきましょう

C:\Users\syuh31\work\example\java\hello_world>which java
/c/Program Files/Java/jdk-13.0.2/bin/java

C:\Users\syuh31\work\example\java\hello_world>which javac
/c/Program Files/Java/jdk-13.0.2/bin/javac

C:\Users\syuh31\work\example\java\hello_world>javac -version
javac 13.0.2

C:\Users\syuh31\work\example\java\hello_world>java -version
java version "13.0.2" 2020-01-14
Java(TM) SE Runtime Environment (build 13.0.2+8)
Java HotSpot(TM) 64-Bit Server VM (build 13.0.2+8, mixed mode, sharing)

ちなみに今回使った。whichコマンドですが、ubuntuだとwhereコマンドに相当します。 使用しているコマンドがどのパスにあるか確認するときに結構使いますので覚えておいて損はないはずです。

はてなブログMarkdownユーザーがソースコードにタイトルを付ける方法

コードのシンタックスハイライトできることは皆さん知っているようですが、markdown形式でタイトルを付けている人の記事が見つけられなかったので、紹介したいと思います。

ポイント

  1. markdown形式でブログを書いている
  2. markdownを特定の書式で書くことで、タイトルを付ける
  3. スマホ版はProユーザーじゃないと対応できない。(Proじゃないとスマホのデザインにスクリプトを仕込ない。)

現状私は、無料ユーザーなので、スマホ版ではタイトルがうまく表示できていないはずです。また、スマホ版の検証はできてないですが、ソースを見る限りできそうです。

今回利用する方法は、特定の書式の文字をmarkdownに入れ、markdownによって生成したタイトルのDom要素をスクリプトでいじっていい感じのタイトルにするという方法です。

以下のように書くと

title:markdown

title:main.dart
(バッククォート3つ)dart
import 'package:flutter/material.dart';

void main() {
  runApp(
      Text(
        "Hello World",
        textDirection: TextDirection.ltr)
  );
}
(バッククォート3つ)

((バッククォート3つ)が情弱感凄まじいですが、外側を4つにして内側を3つにするって書き方が通用しないので、仕方ないと思ってます。) このようなタイトル表示になるようにします。

title:main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(
      Text(
        "Hello World",
        textDirection: TextDirection.ltr)
  );
}

早速設定していきます。

ブログ管理画面->デザイン->カスタマイズ(タブ)->ヘッダ->タイトル下

に次のスクリプトを追加してください。

title:script

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
  // add title
  $(document).ready(function(){
    var elms = document.getElementsByClassName('code');
    for(var i = 0, elmNum = elms.length; i < elmNum; i++) {
      if ('P' == elms[i].previousSibling.previousSibling.tagName) {
        var target = elms[i].previousSibling.previousSibling
        var text = ''
        target.childNodes.forEach(targetChild => {
          if ('A' == targetChild.tagName) {
            text += targetChild.text
          } else {
            text += targetChild.textContent
          }
        });
        var title_index = text.indexOf('title:', 0);
        if (title_index == 0) {
          var title = text.substring(6)
          const createElem = document.createElement('div');
          createElem.appendChild(document.createTextNode(title));
          createElem.classList.add('code-title')
          elms[i].parentNode.insertBefore(createElem, elms[i])
          elms[i].parentNode.removeChild(target);
        } 
      }
    }
  });
</script>

スマホに対応したいProユーザーは

ブログ管理画面->デザイン->スマートフォン(タブ)->ヘッダ->タイトル下

にも追加してください。

コードの説明を簡単にしておくと

  1. codeクラスを持つ要素を全て取得する
  2. codeクラスの上にあるタイトルが書かれているp要素を自分で作成したdiv要素と入れ替える。
  3. このとき、p要素の中に、はてなキーワードリンクの設定により、リンク要素が入っていれば、文字に変換する

みたいなことをしています。

また、

ブログ管理画面->デザイン->カスタマイズ(タブ)->デザインCSS

に以下のコードを追加してください。 (Proユーザースマホも同様)

title:css

.code-title{
  background: #666;
  padding-left: 15px;
  color: #ccc;
}

いろんな条件で動かしていないし、markdownをhtmlにどんな仕様で変換しているのかも知らないし、その仕様も変更される可能性があるため、不具合があるかもしれませんが、フロントエンドは専門外ですのでご容赦ください。

また、これは私が知りたいことのなのですが、Android Studioのコンソール出力のシンタックスハイライトをするためのキーワードとかってあるんですかね。知っている人がいれば教えてほしいです。

お粗末な記事ですが、読んでいただいてありがとうございます。

flutter 最小コードから理解を深めてみた

flutterを理解するのに、最小のコードに肉付けしていくことで理解が深まったので、記事にしてみる。 早速以下が、最小コードだ。

title:main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(
      Text(
        "Hello World",
        textDirection: TextDirection.ltr)
  );
}

f:id:yama_shu99:20200219013758p:plain:w100

見ずらいけど、左上の時刻の部分にHelloWorldと表示されている。 Text(...)の部分はnew Text(...)のようにも書いて良い。どうやらDart2ではnewを省略できるようになったらしい。 Textの引数としてtextDirectionというのがある。これを外すと以下のようなエラーとなる。

title:console

I/flutter (22688): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (22688): The following assertion was thrown building Text("Hello World"):
I/flutter (22688): No Directionality widget found.
I/flutter (22688): RichText widgets require a Directionality widget ancestor.
I/flutter (22688): The specific widget that could not find a Directionality ancestor was:
I/flutter (22688):   RichText
I/flutter (22688): The ownership chain for the affected widget is: "RichText ← Text ← [root]"
I/flutter (22688): Typically, the Directionality widget is introduced by the MaterialApp or WidgetsApp widget at the
I/flutter (22688): top of your application widget tree. It determines the ambient reading direction and is used, for
I/flutter (22688): example, to determine how to lay out text, how to interpret "start" and "end" values, and to resolve
I/flutter (22688): EdgeInsetsDirectional, AlignmentDirectional, and other *Directional objects.

Directionality widgetがないと怒られる。 テキストを書く方向がわからないからのよう。 TextはRichTextを継承していて、RichTextはDirectionalityWidgetを親に持たなければなならない。ただ、このコードでは、Text自体にDirectionを指定してDirection(方向)を与えている。ここでは最小のコードにしたかったため、Directionを指定しているが、普通はMaterialAppやWidgetsApp widgetを親に指定することで、方向をRitchTextに与えるらしい。ということで書いてみる。

title:main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(
      MaterialApp(
          home: Text("Hello World")
      )
  );
}

f:id:yama_shu99:20200219013846p:plain:w100

エラーが出ずにコンパイルできる。

runAppにはWidgetを指定しなければならない。 TextはStatelessWidgetを継承しているため、Widgetである。 ここで指定しているMaterialAppもStatefulWidgetを継承しているため、Widgetである。

title:main.dart

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Text("Hello World"),
    );
  }
}

f:id:yama_shu99:20200219013846p:plain:w100

StatelessWidgetは状態を持っていないWidget。StatefulWidgetは逆に状態を持っているWidget。 StatelessWidgetを継承するクラスはをWidgetを戻り値としたbuild関数をオーバーライドする必要がある。 この戻り値のWidgetが画面に描画されるみたいな作りになってるみたい。 なるほど、なんとなくわかってきた。

title:main.dart

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My First App',
      home: Center(
        child: Text("Hello World"),
      ),
    );
  }
}

f:id:yama_shu99:20200219013851p:plain:w100

この、CenterもWidgetだ。ここまでくれば、WidgetTreeによってUIが構成されるんだなと感覚で理解できてきた。

title:main.dart

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My First App',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}

f:id:yama_shu99:20200219013855p:plain:w100

なるほど、ScaffoldってのはこういうWidgetなんやね。

ここからは、公式サイトのGetStartedと同じなんやけど、statefulwidgetはこんなふうなコードになる。

title:main.dart

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My First App',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
          child: RandomWords(),
        ),
      ),
    );
  }
}

class RandomWordsState extends State<RandomWords> {
  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random();
    return Text(wordPair.asPascalCase);
  }
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

StetefulWidgetを使うには、StateとStateのインスタンスを作成するStatefulWidgetを作成する必要がある。StatefulWidget自身は普遍で、可変の値をStateで持つ作り。

Stateを持つありがたみが、これでは全くわからないので、それは、これから理解していこうと思う。

javaで日本語を使用するときの文字化けの解決方法

$>java HelloWorld
????????

対象環境

検証環境

  • windows10
  • jdk-13.0.2
  • IntelliJ IDEA Community Edition 2019.3.1

文字化けしないようにチェックするポイント

準備.想定するソースコード

文字コードUTF-8として書かれたコード

HelloWorld.java

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("こんにちは世界!");
    }
}

java のみを使う環境の場合

1. コンパイル時の文字コードを正しく指定する。

コンパイラソースコード文字コードを教えてあげて、正しくコンパイルする。

javac -encoding UTF-8 HelloWorld.java

2.実行時の文字コードを正しく指定する。

javaVMが正しい文字コードを使うようにする。

java -Dfile.encoding=UTF-8 HelloWorld
こんにちは世界!

memo.ソースコード文字コードSJISのとき、UTF-8コンパイルしようとした場合エラー

間違った文字コードコンパイラに指定した場合、unmappableエラーとなる。

javac -encoding UTF-8 HelloWorld.java
HelloWorld.java:30: error: unmappable character (0x81) for encoding UTF-8
        System.out.println("??????????E?I");

memo.javaVMに正しい文字コードを指定しなかった場合文字化け

java -Dfile.encoding=UTF-16 HelloWorld
 S00k0a0oNuL

intellij,gradle,javaの場合

1.コンパイル時の文字コードを正しく設定する。

gradleを使用しした、コンパイル時、正しい文字コードを使用するようにbuild.gradleファイルに下記のコードを追記する。

build.gradle

compileJava.options.encoding = 'UTF-8'
compileTestJava.options.encoding = 'UTF-8'

2.実行時の文字コードを正しく指定する

intellijが起動する実行環境javaVMの文字コードを正しく指定してあげる。

%USERPROFILE%.IdeaIC2019.3\config\idea64.exe.vmoptionsに追記

-Dfile.encoding=UTF-8
-Dconsole.encoding=UTF-8

(%PROGRAMFILES%\JetBrains\IntelliJ IDEA Community Edition 2019.3.1\bin\idea64.exe.vmoptions というのもあるので、編集するファイルを間違えないように。)