interfaceのprivateメソッドJava9からinterfaceにprivateメソッドを記述することができるようになった。privateメソッドのため子クラスから参照することは出来ない。interfaceに実装したdefaultメソッドやstaticメソッドすることを想定した機能だと思う。使うときにはこのように実装する。普通に継承すればいいだけ。abstractクラスとinterfaceの違いがなくなってしまったような気がする。違いとして考えられるのはinterfaceはいくらメソッドを書けるといってもinterfaceなので、いくつでもimplementsすることが出来る。interfaceだとabstractとは異なり多重継承のようなことが出来てしまう。これはdefaultメソッドを使えるようになったJava8のときから出来る。Java9になってprivateメソッドも実装できるようになったのでこの機能がより強化された形になったと思う。多重継承というとあまりいいイメージがない。C++で開発を行うときにも内部的な規約で禁止していたりと、何かと嫌われている感じがする。うまくやればより柔軟な設計が可能になるわけで、使う、使わないの選択はプログラマが行うほうがいいと思う。ファクトリメソッドが追加されている。これがJava9になると、このように書くことができるようになった。このコードはJava8だとコンパイルエラーになってしまう。Listなどのコレクションクラスを使う場合にいちいち実装クラス(ArrayListやLinkedList)を指定してやらないといけないところが面倒だと感じていたので、この面倒さが解消されるのが嬉しい。Listの使用方法によって、実装クラスを使い分けたほうが速度面で優位なのかもしれないけれど、そこまでシビアに処理能力の差を求められることも少ないんじゃないだろうか。作っているプログラムによるわけだけれど。List.of();」とする。Setでも同様にコードを書くことができる。Setは要素の重複が許されないので、下記のように書いてしまうと実行時にIllegalArgumentExceptionが発生してしまうので注意が必要となる。最後にMapも試してみる。・・・・」というようにKeyとValueを繰り返し書いていくことになる。注意しないといけないのは、Mapの場合は10個までしか指定できないこと。下記のように書くとコンパイルエラーとなる。JShellJava9から導入されたJavaのREPL環境であるJShellで少し遊んでみたので、やったことをまとめておく。PowerShell。JShellのディレクトリだが、JDKインストールフォルダ配下のbinディレクトリ。Files\java\jdk-9.0.1\bin」となっている。JShell上でプログラムを実行してみる。コマンドを打つと確認できる。1行でも書くことはできるが、行の途中で改行するとJShellの方で勝手に判断してくれる。コマンドを打つと確認できる。クラスも作ったりできるのだけれど、書くのが大変なのでこの辺りで・・・。コマンドを打つとヘルプを見られる。ヘルプの全文は以下の通り。色々な機能を持っていることが分かる。Java言語の式、文または宣言を入力します。ファイルにスニペット・ソースを保存します。intro'などです。/reloadおよび/resetの評価コンテキスト・オプション以前、同僚がJShellを作る意味(存在意義)が分からないと言っていたのだけれど、ちょっと動作を確認したいときなどには便利。今まではクラスをいちいち作成してなど、ちょっと面倒だった。APIを呼び出して結果を得ることも簡単にできる。手軽に試せるのが何よりの利点だろうと思った。これからJavaを学習する人にとっては、クラスやなんだといちいち書かなくていいので、学習の敷居も下げてくれるものだと思う。RubyやPythonなどにはREPL環境があるわけで、ある環境とない環境のどちらを使いたいかと言われれば、断然ある環境なわけだし、他の言語に対抗するうえでも必要なものなんじゃないだろうか。使ってJSONを作成するクラスJavaでMapとListを使ってJSON文字列を返却するクラスを作成した。Jackson等のライブラリを使えば楽なのかもしれないけれど、仕事によっては外部ライブラリを自由に使うことができなかったりすることもあるので、そうしたときには使えると思う。出力結果ちょっと使いづらい気もするけれど実用に耐え無いわけじゃないし、これで良しとしておこう。Ajaxの基本的なやり方Ajaxをうまく使えば、ブラウザアプリであっても操作性の優れたアプリを作ることが出来る。サブミットしなくてもサーバと通信が出来るだけで、UIの幅がかなり広がる。この記事では、jQueryを用いたAjaxの基本的なやり方を説明していく。Ajaxプログラム上記のプログラムはAjaxを利用してサーバと通信を行うことができる。リクエストパラメータの指定を行う。サーバとの通信の成否に関わらず行う処理を記述するAjaxによる処理は非同期処理となるので、そこはプログラム設計をするときに考慮にいれる必要があるが、asyncというプロパティもありこれのtrue/falseを切り替えることで同期処理とすることも可能だ。jsonオブジェクトの空の判定方法Object.keys().lengthを使うことでjsonオブジェクトが空であるかどうかの判定を行える。sharingというキーワードをクラスにつけることができる。実のところ、これが何を意味するかは調べもせずに使っていた。気になってはいたので今回調べてみた。この2つのキーワードはクラスに共有ルールをクラスに適用するかどうかを設定するものらしい。sharingキーワードを指定すると、現在のユーザの共有ルールが適用されたうえでApexコードが実行されるようになる。sharingを指定する。sharingは逆で、共有ルールを適用したいことを明示的に示すものとなる。注意したいのはクラスで指定しているキーワードのほうの共有ルールが適用されるということだ。sharingを指定したクラスのメソッドには共有ルールが適用される。apex:outputLinkタグで勘違いapex:outputLinkタグでちょっとした勘違いをしていた。valueにリンク先を指定すればリンクを画面上に表示してくれるわけだけど、リンク先がSalesforce上の画面だったときに毎度URLFORを指定していたのだ。このソースの5行目にURLFORを使っているところが問題の箇所。これで正常に動作はするので問題ないといえば問題ないのだけど、相対パスを指定できるからURLFORは不要だということについ先日気がついた。value="/{!a.Id}">これだけで同じ処理が実現できる。なんとなく損をした気分だ。sqlType)を使う。sqlTypeのほうにはjava.sql.Typesで定義される型を指定する。下記のサンプルソースではjava.sql.Types.NULLを使っている。x)の場合、第2引数にNULLが許容されないので、NULLをセットしたい場合は回避するようなプログラムを書く必要がある。サーブレットのユニットテストサーブレットのユニットテストを行うときに困るのが、HttpServletRequestとHttpServletResponseがインターフェースなのでインスタンスを作成できないところ。自前でテスト用のモッククラスを作成するのだと非常に面倒である。そこで、利用したいのがspring-test-5.0.1.RELEASE.jar。MockHttpServletRequestクラス、MockHttpServletResponseクラスを使うとHttpServletRequest、HttpServletResponseを簡単に用意できる。これでサーブレットのdoPostやdoGetメソッドのユニットテストのソースを楽に書ける。インスタンス作成してsetParameterなどのメソッドを使ってデータを渡すだけで、モッククラスが使える。そのあとで、サーブレットのdoPostやdoGetにパラメータを渡してやる。これだけだと、実行時エラーが出てしまうので以下のjarをクラスパスに配置してやる必要がある。ひとつ目が、spring-core-5.0.1.RELEASE.jar。リンク先へ飛んで、spring-framework-5.0.1.RELEASE-dist.zipをクリックしてzipファイルを解凍すると中にあるのが確認できる。ふたつ目が、commons-logging-1.2.jar。こちらもリンク先へ飛んでcommons-logging-1.2-bin.zipをクリックしてzipファイルを解凍すると中にあるのが確認できる。sqliteに接続してデータを取得するsqliteに接続してデータを取得するには、Connection、Statement、DriverManagerなどを使う。sqliteのJDBCドライバがビルドパスに存在していることが前提となるので、まだ無いようだったらダウンロードする必要がある。JDBCドライバは使用しているPCにインストールされているsqliteのバージョンとそろえないといけない。バージョンが分からないようなら、以下のコマンドでsqliteのバージョンを確認しよう。-versionConnectionとSatementは使用後にcloseする必要があるので注意する。URLを指定してformのサブミット<form>タグをsubmitするときに、クリックされたボタンによって遷移先のURLを変えたい場合がある。そんなときは、jQueryを使うと簡単に実現できる。'http://btn1.com');この部分(3行目と8行目)でURLを指定している。ユーザーの入力に応じて動作を変えたり、ひとつの<form>タグ中に複数のボタンを置いて、それぞれ別の遷移先を指定したいときなどに便利。プログラミング2017年11月6日月曜日フロントコントローラWebサイトが複雑化してくると、認証、承認、セッション管理や共通のログ出力などあらゆるリクエストで同じ処理を行う必要が出てくることがある。した振る舞いがあちこちに散らばってしまったら、非常にメンテナンスのし難いプログラムになってしまう。認証の処理を変えようとしたら、あらゆる画面のプログラムを書き換えないといけないなんてゾッとする。したときには、フロントコントローラパターンを用いてコントローラを実装すればよいと思う。フロントコントローラパターンを使うと、あらゆるリクエストを、ひとつのコントローラが受け付けるため共通の処理を一か所に組み込むことが出来る。以下のソースはJavaによるフロントコントローラパターンの例。Streamを使った配列の検索でNullPoiterExceptionが出てしまう先日、Streamを利用した配列の検索について書いたのだが、色々とやっているうちにNullPointerExceptionが発生するようになってしまった。いうケースで発生するするかというと、2回検索を行ったときだ。上記の14行目でNullPointerExceptionが発生する。仕方がないのでasListで一旦Listに変換してから、List.containsを使うことで検索を行う。これで複数回検索してもExceptionが発生しないのだけど、Streamでやる方法はないのだろうか。やり方にこだわりがあるわけではないのだが、分からないので少し気持ち悪い。配列の要素の検索を行う配列の要素を検索する方法。Listであればcontainsメソッドがあるので簡単だけれど、配列だと少しだけ手順が必要になる。StreamクラスのanyMatchメソッドを使うことで配列の要素検索を行える。propertiesファイルが文字化けするメッセージをpropertiesファイルに外だししたら、ブラウザに表示したときに文字化けしてしまった。propertiesファイルもブラウザもUTF-8なので大丈夫かと思っていたらそうでもなかったようだ。デバックして確認したらJavaプログラムでpropertiesファイルからメッセージを取得したタイミングで文字化けしていた。ResourceBundle.getBundle("hoge");System.out.println(rb.toString());上記のプログラムだと文字化けしてしまう。調べてみると、ResourceBundle.Controlクラスを継承したクラスを作ることで対処可能なことが分かった。}}このクラスを作って、下記のようにpropertiesファイルを読み込むと文字化けしない。/>上記のようにjsp:useBeadでArrayList<String>を使おうとしたら下記のようなエラーが出た。値が無効ですGenericの型指定のところでエラーが出てしまっているようなのだが、使えないと不便だし非常に困る。対応策としては、class属性だけでなくtype属性も指定すること。/>このように書き換えたらエラーが出なくなった。formのサブミットjQueryでformのサブミットをすると、サブミット前に送信データの加工やバリデーションチェックといった処理を行える。</body></html>ボタンがクリックされたタイミングでサブミットを行うようにしている。すると、サブミットを実行する前に処理を行うことができる。Mapの並び順JavaにはMapにはHashMap、LinkedHashMap、TreeMapの3種類があるのだけれど、それぞれ役割が異なっているので場面によって使い分ける必要がある。Keyの昇順の順番になるMapにKey/Valueをputしたあとに、ループで処理したいといった要件があるときは、HashMapを使ってしまうと出力の順番が保障されないので困ってしまう。m.getValue());}上記のプログラムの実行結果を見てみると、HashMapではバラバラな順番で出力されていることが分かる。熊本県これがLinkedHashMapだと、putした順番に並ぶ。m.getValue());}出力結果を確認すると、ちゃんとputした順番に並んでいる。高知県これをTreeMapに変えるとKEY順に並べ直してくれる。m.getValue());}出力結果を確認するとKEYの昇順に並んでいることが分かる。v4.0.0-betaにしたらパンくずリストがうまく表示できなくて困った。3.xではこれで良かったと思うのだけれど表示が下記のようになってしまい、これではパンくずリストとは言えない。4.xではパンくずリストの書き方が変わってしまったようなので修正する。指定することでパンくずリストになる。ちなみにnavタグを利用してもパンくずリストを作れるようになっている。loadを使ってHTMLをパーツ読み込むjQueryのloadを使うことで、パラメータに指定したHTMLを読み込んでDOMに挿入することが出来る。すべての画面で共通で利用するヘッダなどをパーツとして切り出しておき、それを読み込むといったことを行える。../parts/header.html");})ローカルで試してみたら、実は動かなかった。Chromeはセキュリティの関係でローカルファイルへのAjax要求を許可していない。いうことで、これをやるためだけにTomcatを起動して・・・など、色々と面倒なことをやってようやく動いた。HTML・CSS・javascriptでモックをお手軽に作ろうと思っただけなのに。betaを使おうとしたら下記のようなエラーが出てしまった。src="../js/bootstrap.min.js"></script></head>何やらよく分からないが、Popper.jsというのが必要ということらしい。popper.js自体はエラーに記載されているURLへ行けばダウンロードできる。https://popper.js.orgこのPopper.jsは何なのかというと、ツールチップ用のjsのらしい。日本語の情報があまりなかったが、下記のリンクを見つけた。http://design-develop.net/web-design/popper.html私は使ったことがないので具体的なところはよく分からないが、ツールチップの制御が簡単に行えて、しかもかゆいところに手が届くようなものになっているようだ。popper.jsを読み込むように書き換えたらエラーは出なくなった。v4.0への移行ガイドにpopper.jsに依存するとのことが書かれているのを見つけた。いうShift_JISを拡張したエンコード。WindowsはShift_JISで定義されていない文字も扱うことができる。これ知らずに、昔ひどい目にあったことがある。■概要RubyのプログラムでExcelの以下の操作を試してみる。Excelファイルの新規作成Excelファイルを開くExcelファイルのセルへの書き込みExcelファイルのセルや範囲指定してのコピー&ペーストExcelの行・列の削除RubyでExcel操作を行うライブラリはいくつかあるようだが、ここではWin32OLEを利用する。■Win32OLEについてWindows上でのみ使用可能。xls、xlsx、両方の形式に対応している。book.worksheets(1)#行削除sheet.Range('A1').EntireRow.Delete#列削除sheet.Range('A1').EntireColumn.Delete#開いたブックを上書きbook.save#Excelを閉じるbook.closeexcel.quit()■まとめWin32OLEを利用することでExcel操作がRubyから行える。マクロ付きブックのxlsm形式は未確認だが、動作に問題はないと思う。b)を使うことで簡単に分数の計算を行うことができる。約分も自動でやってくれる。ような文字列のようにRubyのプログラムの中に直接書き込むことのできる値のことを指す。Rubyではダブルクォーテーションで囲われた文字列のなかに、式の内容を埋め込むことができる。Hello■まとめダブルクォーテーションで囲われた文字列のなかに以下のような形式で記述すると式の内容を埋め込むことが出来ている。#{式}実行結果を見るとシングルクォーテーションでは式の内容が展開されていないことが分かる。変数が$または@ではじまるばあいは{}を省略することできる。便利なのは式展開のなかではRubyの式をそのまま書くことができることだと思う。InteractClass.new()■まとめgets.chompの部分でユーザーの入力を受け取っている。「RubyでSSH接続」を実施して動作することを確認する。以下のコマンドを実行してSCPのライブラリを取得する。local_pathendまとめssh.scp.upload、ssh.scp.downloadでscpのアップロード、ダウンロードの実行を行っている。ssh.exex!('<コマンド>')を利用してscpコマンドを発行することもできると思う(検証していない)が、それより手軽に実現できると思う。プログラミング2017年9月21日木曜日RubyでSSH接続を試してみる概要Rubyで他の端末へSSH接続して、コマンド発行を行う。print(ssh.exec!('ls'))end説明これだけでSSH接続ができる。プログラミング2017年8月11日金曜日SalesforceでAjaxを使ってみる3昨日調べたところによると、<apex:commandButton>タグでAjaxを実現ができるようなので、これが一番簡単そうだし深堀してみることにした。https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_compref_commandButton.htmこのリンク先を見てみると、「Ajax」という単語がところどころに出てくる。このメソッドを参照するには、差し込み項目の構文を使用します。いうように書かれている。actionはよく使っていたが、Ajax要求とは知らなかったので少し驚いた。</apex:form></apex:page>action="{!upload}"の部分が該当箇所で、TestControllerクラスに実装されたuploadメソッドを呼び出している。プログラミング2017年8月10日木曜日SalesforceでAjaxを使ってみる2Ajaxはブラウザと非同期にサーバーと通信を行うことができて、うまく使えばけっこう便利なWebアプリの開発を行えるようになるだろう。ページ遷移を伴わない動的なWebアプリは、きっとユーザのうけもいいものになるに違いない。AjaxはjQueryなどのフレームワークを利用すると簡単に記述することができ、尚且つブラウザごとの互換性もあまり心配しなくてよくなる(はず)。Toolkitというのがあり、これを利用することでAjaxを実現できるようだ。Visualforceの<apex:commandButton>タグのrerender属性を指定すると、メソッドの呼び出しをsubmitではなく、Ajaxで処理してくれるらしい。あとは、メソッドに@RemotoActionアノテーションをつけることや、jQueryを組み込む方法などがある。実際のソースコードを作ったわけではないが、それぞれ長所、短所ともにあるようなので、使いどころを覚えていく必要がありそうだ。色々な方法があるようなのでひとつずつ試していこうと思う。プログラミング2017年8月9日水曜日SalesforceでAjaxを使ってみる最近は仕事のほうが忙しくて、まあ暇しているのに比べれば何よりなのだけれど、あまり学習の時間が取れていない。続けているものの、なかなかブログに書くほどの分量は貯まらないし、日々気力は落ちていくしで悪循環だった。いうわけで、5分10分くらいのことで、まとまり切らなくてもちょっとずつ書いていこうと思う。SalesfroceでAjaxを使ってみたいと思った。いまの仕事(Salesforceではない)でAjaxを結構使う機会があったので、じゃあSalesforceでAjaxを実現するには何をしたらいいのかということを調べた。このサイトが参考になりそうだ。プログラミング2017年7月21日金曜日メンタルヘルスケアの記事を読んでhttp://itpro.nikkeibp.co.jp/atcl/column/16/081800177/061500031/?ST=spleafこの話はとても分かりやすかった。メンタルヘルスケアについての話なんだけれど、ある日突然パタッといったりするもんだよということが書かれている。頑張って働くというのは大変なようで、案外簡単だったりする。仕事だとやらないと、なんていう義務感も働くのでなおさら。いまは残業にたいして厳しいのでそうでもないけれど、私が仕事を始めた頃はそうでもなかった。プログラマという職業を選んだということもあるかもしれないけれど。大丈夫なんて自分に言い聞かせはじめたら、かなり危ない兆候で、本当は休まないといけない。大丈夫なんて、通常の状態じゃ思ったりしない。趣味が楽しくなくなったり、休日に起きれなくなったりと、体からシグナルは意外とたくさん出ていたりする。「大丈夫?」なんて声をかけたところで「大丈夫」と大抵は答えが返ってくる。普段と言動が変わってしまった人の「大丈夫」なんてまったく信用ならない。冒頭の記事にもあるようにストレスとはうまく付き合わないといけないわけだけど、これって周囲の協力が必要と思う。セルフケアが重要なのは当然だけど、ストレスの感じかたは人それぞれで、一概に決めつけられない。精神的に強い人というのはあまり見たことなくて、特定の状況において強いとか、得意なところが人によってちがう。お互いがお互いをという関係になってくると思うので、あるときは助けるし、別のときは助けてもらえるというのがいい関係だと思う。ContentDocumentに新しいバージョンをアップロードContentVersionのinsertをしてやればApexでContentDocumentに新しいファイルのアップロードを行える。アップロードされているファイルの新しいバージョンをアップロードするにはどうすればいいのだろうか。ContentVersionはContentDocumentIdというフィールドを持っている。これはContentVersionが紐づいているContentDocumentのIDを保持するフィールドだ。insertしてやるときに、新しいバージョンをアップロードしたいContentDocumentのIDをこのフィール―ドにセットしてやればいい。ContentDocument?昨日ContentVersionへのアップロードに成功したのだけれど、このページのURLが気にかかっている。*****/sObject/ContentDocument/homeContentVersionにアップロードすると、ContentDocumentに格納されているようなのだ。ContentVersionについて調べているときに、ちらほらと見かけたのを見て見ぬふりをしていたが、真面目に取り組みあわないといけないようだ。調べた感じだとこんなイメージ。ContentDocumentHistoryなるオブジェクトも存在していて、VersionとHistoryってなにが違うのかがよく分からない。ContentVersionはどこに?昨日ContentVersionのinsertに成功したと思しき結果が得られた。成功したと言いきれないのは、insertした結果のファイルがどこに行ってしまうのかを知らないからだ。ContentVersionなんだから何かのバージョン管理してるものなんだろうなあ、とか考えてみると気になることはあるのだけれど、とりあえず、insertされたファイルの行方を探そうと思う。アプリケーションランチャーを開いてみると、「ファイル」という名前の項目がいた。これじゃないだろうか?思った通り、アップロードしたファイルを見つけることが出来た。transientキーワードビューステートにはガバナ制限があるので、128KB以上のデータを扱えない。それ以上のデータを扱うには、このガバナ制限を回避する必要がある。その方法としてtransientキーワードを使う。transientキーワードを使うとビューステートとして送信できなくなるのだが、逆に考えるとビューステートのガバナ制限は気にしなくていいとも言える。}さっそく、昨日失敗したファイルアップロードを試してみる。}}エラーは発生しなかったので、うまくいったような気がする。ひとつ問題があって、ContentVersionにinsertしたファイルはどこに行けば確認できるのかが分からない。したことのはずなのに課題はなくなってくれないなあ。ビューステートのガバナ制限を回避したいビューステートには128KBというガバナ制限がある。ファイルアップロードするようなVisualforceを作成したら、その程度のガバナ制限はすぐに超えてしまう。出来ないかなと思って考えたのが次のこと。実はapex:formタグの外にファイルアップロードを書けばいいんじゃないかというわけでさっそく試してみた。</apex:form></apex:page>このように書き直した。action="{!upload}"/></apex:page>そしたら、エラーになってしまった。タグ間に存在する必要があります。いえば、apex:commandButtonタグはapex:formタグに囲われた領域にいないといけないんだった。</apex:form></apex:page>これだと、apex:commandButtonタグはapex:formタグの内側にあるからOK。ちなみにapex:outputTextタグとapex:inputFileタグは外側にあってもエラーにはならない。したら回避できるんだろう。ビューステートファイルをアップロードするプログラムを書いたのだけれど、エラーとなってしまった。何かのサイズ制限に引っかかったようなのだが、何のことなのかよく分からない。「ビューステート」という用語が理解できれば解決するだろうと辺りをつけて調べてみる。Visualfoceでは画面遷移のときの情報を自動的に保持してくれるようになっていて、この保持してくれるやつのことをビューステートと呼ぶらしい。これにはガバナ制限があって、128KBしか保持できないとのことのようだ。エラーメッセージでは135KBになっているけれど、バージョンの違いのせいだろうか?アップロードするファイルのサイズは、400KBを超えていたのでこのガバナ制限に引っかかっているよというのがこのエラーの内容。このくらいのサイズのファイルをアップロードしたくなるときはあると思うのだけれど。HTMLのテーブルに縦スクロール昨日はtableに横スクロールをつけたので、今日は立てスクロール。</body></html>単純にこう書いてもできるのだけれど、これだと少しだけ具合が悪い。ヘッダーも一緒にスクロールされてしまうからだ。tableタグの外側にあるdivタグでスクロールさせているので当然と言えば当然。ヘッダーがスクロールされてしまうと実用性がない。tbodyタグだけスクロールするように修正する。</body></html>tbodyタグにoverflow-y:scrollをスタイルで指定してあげる。theadとtbodyにdisplay:block。これで、tblodyだけのスクロールの準備ができた。あとは、tbodyで縦幅を指定してあげれば、tbodyの表示要素が指定した以上の縦幅を持っているときにスクロールできるようになる。HTMLのtableに横スクロールHTMLのテーブルに横スクロールをつけたい。簡単に出来るかと思ったら意外なほど時間がかかった。毎日ブログを更新すると決めているので急いで書かないと間に合わない。</body></html>こんな感じでtableタグのひとつ上の階層をdivタグで囲ってあげて、そこにoverflow-x:scrollをスタイルで指定する。これだけで横スクロールするテーブルの出来上がり。何に嵌っていたかというと、最初こんなソースを書いてしまった。</body></html>何が違うかというとdivタグとtableタグのところにstyleでwidthを指定していないこと。スクロールバーは出ているけれども、スクロールしたいという要望には堪えられなさそうだ。tableより外側にいるdivタグのほうが狭くないとスクロールできない。Visionはなかなか進まないので、とっかかりになりそうなところから進めていこうと思う。'GeneralImageClassifier');}アップロードされたファイルをEinsteinに渡しているのがこのメソッドなんでけれど、実を言うと"ContentVersion"が何なのかよく分かっていない。ひとつひとつ知識を身につけていきたい。調べてみると"ContentVersion"はSalesforceのファイルストレージの種類のひとつらしい。Salesforceのファイルストレージの種類は以下の4つがある。添付ファイル:Attachmentドキュメント:Documentコンテンツ:ContentVersionファイル:FeedItem各ファイルストレージごとに少しずつ役割やアップロードできるファイル容量に差があるみたい。https://base.terrasky.co.jp/articles/GhMtp明日はContentVersionにアップロードしてみよう。クエリの結果の受け取りかたApexでSOQLクエリを発行してた下記のように結果を受け取る。Account];どちらでもいいのだけれど、「sObjectで結果を受け取る」のほうの場合でクエリの結果が複数レコード取得出来てしまうとエラーとなってしまう。使用できる箇所は限定的だ。逆に言えば、クエリの結果が1件であることが保証できるのであればリストでクエリの結果を受け取る必要はないと言える。ところが昨日、複数レコードデータが取得できるはずのないクエリでエラーとなってしまった。1"を指定しているし、そもそもIDを条件句に入れているのだから、複数レコード取得できるはずがない。SObject昨日は勘違いしていたが、冷静になってこのメッセージを読み返すとクエリの結果がゼロ件だからエラーになっているようである。これ、私にとっては新事実なのだけれど。いうわけで試してみる。'???'];データを取得できない条件を指定してSOQLクエリを発行し結果を受け取る。SObject同じメッセージが得られたので、ゼロ件だとエラーになるみたいだ。ゼロ件でもエラーとはならないと思い込んでいた。本当なら「sObjectで結果を受け取る」なんてプログラムを書くメリットがまったくないと言える。100%確実に、データが1件のときというの保証するのは難しい。1];クエリは最大でも1件しかデータを返さない。絶対に1件取得できる保証ができないケースのほうが多い気がする。Listを使って受け取るようにしようと思う。Visionで使うプログラムには最初からコメントアウトされている部分がある。昨日、うまくアップロードした画像を認識できなかったので、この部分を少し調べてみたい。何か解決のヒントが得られるかもしれない。-->コメントアウトされているVisualforceの箇所が上記の部分。そのまま動きそうな雰囲気を出している。こいつのコメントアウトをはずす。こいつはVisionControllerクラスのcallVisionContentメソッドを呼び出している。'GeneralImageClassifier');}よくみると、こいつはVisionクラスのpredictBlobメソッドを呼び出している。私が昨日作ったソースではエラーになったがこいつはどうだろうか。エラーになってしまった。これはクエリの結果が複数件なのに、単一(リストではなく)オブジェクトで受け取ろうとしたときに発生するエラー(だったと思う)。確かにプログラムはクエリの結果をリストではなく単一のオブジェクトで受け取っている。1"となっているため、クエリの結果は複数件にはならないはず。謎が増えてしまったわけだが、このあたりで今日は終わり。画像認識をアップロードファイルでやりたい3ファイルアップロードできるようになったので、あとはそのデータをEinsteinに渡してあげるだけ。"predictBlob"というメソッドがいるので、そいつに渡してやる。認識させるのは私の好きな花、準絶滅危惧種のチョウジソウ。思ったのだけれど、残念ながら失敗。メソッドが用意されているから簡単にできると思ったのだけれど、うまくいかなかった。原因はよく分からない。調べる必要がありそうだ。画像認識をアップロードファイルでやりたい2画像認識をアップロードファイルでやるには、ローカルのファイルをアップロードできるようにしないといけない。ファイルアップロードには<apex:inputFile>を使う。value="{!uploadFile}"/>こんな感じ。"ファイルを選択"をクリックするとファイル選択ダイアログが表示されるので、ファイルを選ぶだけ。valueは必ず指定する。valueに指定するのはBlob型。