django-webpack-loader  {% render_bundle 'main' %}で「string indices must be integers」と言われる

Django + Vue.jsの環境作成については、以下の記事を参考にさせていただきました。 settings.pyやwebpack.config等の値も同じように設定しています。 Django + Webpack を使ってVueを動かす - Qiita

ハマったこと

templateの{% render_bundle 'main' %}string indices must be integersというエラーが発生してしまう。

index.html

{% load render_bundle from webpack_loader %}
<!DOCTYPE html>
<html>
 <head>
 <meta charset="UTF-8">
 <title>Example</title>
 </head>

 <body>
 {% verbatim %}
 <div id="app">
 {{ message }}
 </div>
 {% endverbatim %}

{% render_bundle 'main' %}

 <script>
 var app = new Vue({
 el: '#app',
 data: {
 message: 'Hello Vue!'
 }
 })
 </script>
 </body>

冒頭の{% load render_bundle from webpack_loader %}が動いていない?

一応解決

github.com

webpack-bundle-trackerのバージョンを下げる必要があるらしい。

{
  "devDependencies": {
    "vue": "^2.6.11",
    "vuetify-loader": "^1.4.3",
    "webpack": "^4.42.1",
    - "webpack-bundle-tracker": "^1.0.0-alpha.1",
    + "webpack-bundle-tracker": "^0.4.3",
    "webpack-cli": "^3.3.11",
    "webpack-dev-server": "^3.10.3"
  }
}

これで動くようになった。

gradle buildで「GradleWorkerMainを検出およびロードできませんでした」

Gradle 6.0.1
java 11.0.5
Spring Boot2

エラー

gradle clean buildを実行すると以下のエラーが出る。

> Task :test
エラー: メイン・クラスworker.org.gradle.process.internal.worker.GradleWorkerMainを検出およびロードできませんでした
原因: java.lang.ClassNotFoundException: worker.org.gradle.process.internal.worker.GradleWorkerMain
エラー: メイン・クラスworker.org.gradle.process.internal.worker.GradleWorkerMainを検出およびロードできませんでした
原因: java.lang.ClassNotFoundException: worker.org.gradle.process.internal.worker.GradleWorkerMain
エラー: メイン・クラスworker.org.gradle.process.internal.worker.GradleWorkerMainを検出およびロードできませんでした
原因: java.lang.ClassNotFoundException: worker.org.gradle.process.internal.worker.GradleWorkerMain
エラー: メイン・クラスworker.org.gradle.process.internal.worker.GradleWorkerMainを検出およびロードできませんでした
原因: java.lang.ClassNotFoundException: worker.org.gradle.process.internal.worker.GradleWorkerMain
エラー: メイン・クラスworker.org.gradle.process.internal.worker.GradleWorkerMainを検出およびロードできませんでした
原因: java.lang.ClassNotFoundException: worker.org.gradle.process.internal.worker.GradleWorkerMain
Process 'Gradle Test Executor 83' finished with non-zero exit value 1
org.gradle.process.internal.ExecException: Process 'Gradle Test Executor 83' finished with non-zero exit value 1
        at org.gradle.process.internal.DefaultExecHandle$ExecResultImpl.assertNormalExitValue(DefaultExecHandle.java:417)
        at org.gradle.process.internal.worker.DefaultWorkerProcess.onProcessStop(DefaultWorkerProcess.java:141)
        at org.gradle.process.internal.worker.DefaultWorkerProcess.access$000(DefaultWorkerProcess.java:42)
        at org.gradle.process.internal.worker.DefaultWorkerProcess$1.executionFinished(DefaultWorkerProcess.java:94)
        at jdk.internal.reflect.GeneratedMethodAccessor622.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:42)
        at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:231)
        at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:150)
        at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:141)
        at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:37)
        at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
        at com.sun.proxy.$Proxy69.executionFinished(Unknown Source)
        at org.gradle.process.internal.DefaultExecHandle.setEndStateInfo(DefaultExecHandle.java:221)
        at org.gradle.process.internal.DefaultExecHandle.finished(DefaultExecHandle.java:357)
        at org.gradle.process.internal.ExecHandleRunner.completed(ExecHandleRunner.java:110)
        at org.gradle.process.internal.ExecHandleRunner.run(ExecHandleRunner.java:84)
        at org.gradle.internal.operations.CurrentBuildOperationPreservingRunnable.run(CurrentBuildOperationPreservingRunnable.java:42)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
        at java.base/java.lang.Thread.run(Thread.java:834)
  • 開発ブランチからmasterのブランチに切り替えてbuild実行
    -> 同じエラーが発生。ソースコードや設定ファイルの問題ではないらしい。

解決

gradle --stop実行後に再度 gradle clean buildしたら正常終了しました。
ThreadPoolExecutorとか吐かれてたね…

SpringBootでBeanクラス内にバリデーションメソッドを書く場合

SpringBootでBeanクラス内にバリデーションメソッドを書く場合、
is(has)XXX()というメソッド名にしないとチェックが実行されない。


これはチェックが走らない

import java.io.Serializable;
import javax.validation.constraints.AssertTrue;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class TestForm implements Serializable {

    private static final long serialVersionUID = 1L;

    private String telNumber;

    /**
     * 電話番号 形式チェック.
     * 
     * @return 判定結果.
     */
    @AssertTrue(message = "電話番号はハイフン無し数字10~11桁で入力してください")
    public boolean validateTelNumber() {
        if (!StringUtils.hasLength(telNumber)) {
            return true;
        }
        return telNumber.matches("^\\d{10,11}$");
    }

}

常識なのですか?知りませんでした…。

php 区切られていない日付文字列に区切り文字を付与する

yyyymmddまたはyyyymmの形式で入力されている文字列を
yyyy/mm/ddの形にしたかったメモ

/**
 * 区切られていない日付文字列に区切り文字を付与する
 * @param int $targetDate yyyymm(dd)
 * @return string yyyy/mm(/dd)
 */
function nonDelimiterDateToSlash($targetDate)
{
  if (strlen($targetDate) == 6) {
    return substr($targetDate, 0, 4) . "/" . substr($targetDate, 4, 2);
  }
  return substr($targetDate, 0, 4) . "/" . substr($targetDate, 4, 2) . "/" . substr($targetDate, -1, 2);
}

または

      $target_yyyymmdd = (string)$item->target_yyyymm."01"; // 型変換のために日付を付与
      $edited_year_month' => date('Y/m', strtotime($target_yyyymmdd)),

js(typescript) 子孫の要素を再帰処理で取得する

やりたいこと

[{id:"XXX", parentsId:"", contents: ...},{id:"yyy", parentsId:"XXX", contents: ...}]

こんな感じのデータ構造のコンテンツを、

{id:"XXX", parentId:"",contents:..., descendants:[{id:"yyy", parentsId:"XXX", contents: ...,descendants:[]}]}

という形で階層化したい。

書いた

Typescriptで書いてます。

type originalInfo = {
  id:string,
  parentsId:string,
  contents:any,
};

type NodeInfo = {
  data: originalInfo;
  descendants: NodeInfo[];
};


// Idの子要素を探して返却する処理
function findDescendants(Id: string, nodelist: NodeInfo[]): NodeInfo[] {
  let target = [];
  let other = [];
  for (let n of nodelist) {
    if (n.parentId === Id) {
      target.push(n);
    } else {
      other.push(n);
    }
  }

  for (let t of target) {
    const d = findDescendants(t.Id, other);
    t.descendants = d;
  }
  return target;
}

// 階層化処理
function createNodeList(originalData: originalInfo[]): NodeInfo[] {
  let preNodeList: NodeInfo[] = [];
  originalData.forEach((c: originalInfo, index) => {
    preNodeList.push({
      id c.id,
      parentId: c.parentId,
      descendants: [],
    });
  });

  let parentList: NodeInfo[] = [];
  let childList: NodeInfo[] = [];
  // 親要素と子要素とで分割
  for (let node of preNodeList) {
    if (node.parentId) {
      childList.push(node);
    } else {
      parentList.push(node);
    }
  }

  for (let p of parentList) {
    const descendants = findDescendants(p.id,childList);
    p.descendants = descendants;
  }
  return parentList;
}

function mainFunction(originalData:originalInfo[]) {
  const nodeList = createNodeList(originalData)
}

オブジェクトの配列の上書き

オブジェクトの配列において、
重複するidを持つオブジェクトが既に格納されている場合、新しい方のオブジェクトで上書きしたい場合

  // 初めに書いていたindexのとり方
   const targetIndexOLD = this.targetArray.map(t => t.id).indexOf(info.dateString);

  // こちらの方がわかりやすい
    const targetIndex = this.targetArray.findIndex(t => r.id === newInfo.id);

    if (targetIndex === -1) {
      this.targetArray.push(info);
    } else {
      this.targetArray[targetIndex] = info; 
    }

js 配列の中の特定のオブジェクトを上書き - Afterwardsと似たようなことをしているけど
(書いていて気が付いた…)
今回の方は破壊的なやり方。 でも古い方の記事の処理ももう少しスマートに書けそうだな。。

js リストの並び順比較処理

reactで、propsから渡ってきている初期リストと
画面上でsortしてstateに保存しているリストの並び順を比較した時のメモ。
戻り値のbooleanとbreak用のreturn falseがややこしいから戻り値を変数に格納してます forEachはbreakできないね!

  /**
   * 並び順が変更されたか判定
   */
  isSorted() {
    let isSorted: boolean = false;
    const defaultOrderList = this.props.targetList
      .slice()
      .sort((a: ContentsInfo, b: ContentsInfo) => {
        return a.sort_no - b.sort_no;
      });

    this.state.currentData.forEach((v: any, index: number) => {
      if (
        v.sort_no !==
        defaultOrderList[index].sort_no
      ) {
        isSorted = true;
        return;
      }
    });
    return isSorted;
  }