質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

2341閲覧

Javaでbyte配列の置き換え

katliner

総合スコア13

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2018/01/31 12:59

編集2018/01/31 13:40

Javaのバイトコード操作をかんたんにやりたいと思っています
バイトコード操作はimport書き換えのために使いたいです。
ASMやJavassistを見てみましたが僕の想像するバイトコード操作ではなかったので自分で作ろうかと思いました

そこでInputStreamからbyte配列にclassファイルの中身を読み込まさせ、Stringに変換後置き換えなどを行い、再度getBytes()でbyteを取得して出力という方法を取りました。

ですができたclassファイルをリフレクションを使用して実行させようとすると
java.lang.ClassFormatError: Unknown constant tag 119 in class file クラス名
というエラーが出ます。
Stringを経由させるのが行けないのだと思ったのですが、byte[]にreplace関数がないのでどうしたらbyteの置き換えが行なえますか?
String.replaceと同じような感じで置き換えがしたいです。

Java

1InputStream stream = zip.getInputStream(entry); 2byte[] b = new byte[(int) entry.getSize()]; 3stream.read(b); 4String a = new String(b,"ISO-8859-1"); 5a = a.replace("cpw/mods/fml/common/network/NetworkMod", "versionsmod/src/cpw/mods/fml/common/network/NetworkMod"); 6zipout.putNextEntry(new ZipEntry(entry.getName())); 7zipout.write(a.getBytes("ISO-8859-1")); 8zipout.closeEntry();

entry・・・ZipEntry
zipout・・・ZipOutputStream

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/01/31 15:25

アスペクトっぽいことをやろうとしてるのだったらメモリ上だけでやるべきよディジットを計算しなおす羽目になるから
guest

回答1

0

ベストアンサー

少なくとも2つの点からいってご質問のコードでは期待通りのことはできません。

文字列とバイナリーとの変換は非可逆変換

Javaのクラスファイルの中身はテキストではなくバイナリーデータです。クラスファイルの内容を扱うのにStringを用いるのは、質問文にもコメントしておられるとおり無理です。

クラスファイルのフォーマット

クラスファイル中にある文字列の単純置き換えだけができればよいとして、そこには少々面倒な点があります。

クラスファイルの中身にある文字列は修正UTF-8エンコーディングが用いられているのですが、エンコードされたバイト列に先立ってそのバイト数の情報が格納されてます。

従ってバイナリーデータを置き換えるようなことが可能なライブラリーがあったと仮定してもそう単純には置き換えられません。クラスファイルの中身自体のフォーマットを意識して「ある文字列を表す部分を正確に抜き出し」それを置き換える結果、修正UTF-8エンコーディングでバイト数がどう変化するかも意識して文字列全体を置き換えるような操作が必要です。

例:
文字列 修正UTF-8エンコーディング
"abc" 0x00 0x03 0x61 0x62 0x63
"abcd" 0x00 0x04 0x61 0x62 0x63 0x64

上の例では"c"を"cd"に置き換えたものですが、その部分以外に文字列先頭にある0x00 0x03を0x00 0x04に置き換えなければならないといった具合です。

これをするには結局クラスファイルのフォーマットを意識した解析が必要になりますので数十行程度のコードで書けるかと言うとちょっと苦しそうです。多分少なくとも数百行、ことによると1000行以上になるかも知れません。

そのようなものを自前で作るよりはクラスファイルを置換するためのライブラリーをなんとか使うことをまずは検討した方がよいように思います。

投稿2018/01/31 17:06

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

katliner

2018/01/31 22:52

ありがとうございます 結構複雑なんですね... ではライブラリを使うとしたら a = a.replace("cpw/mods/fml/common/network/NetworkMod", "versionsmod/src/cpw/mods/fml/common/network/NetworkMod"); のように書き換えられるライブラリはありますか?
KSwordOfHaste

2018/01/31 22:59 編集

質問に述べた理由があるためbyteのまま置き換える必要はないと思いますよ。どのみちクラスファイルレイアウトを意識し「文字列部分を抜き出して」「それを文字列として変更し」「元の文字列全体を新たな文字列で置き換える」必要があるのですから。多分そういうことを簡単にできるとしたら単なるバイナリーの変更機能なのではなく「Javaのクラスファイル自体の変更機能」に特化したものであると思います。そういう目的で使い得るものがJavassistなどではないのでしょうか・・・(スミマセンが自分はJavassistの機能詳細をみたことがないのでこれが使えるかどうかまではお答えできません。)
退会済みユーザー

退会済みユーザー

2018/02/01 00:57

おや? Java クラスのバイトコードて 16か32じゃなかったけ
katliner

2018/02/01 14:00

ではもうすこしJavassistについて調べてみようかと思います。
KSwordOfHaste

2018/02/04 07:55

>asahina1979さん お返事遅れてすみません。指摘意図がつかみきれませんでした。自分が考えていたことは「クラスファイルの中に出現するFQCNやメソッド名等は結局のところコンスタントプール上の「修正UTF-8エンコーディング文字列」を参照しているので、何かの名称を変更するということは修正UTF-8エンコーディング文字列全体の置き換えが必要という意図だったのですが?
katliner

2018/02/04 08:04

JavassistのCtClass.replaceClassName(oldName,newName)を使えばうまくできました。ありがとうございました。
KSwordOfHaste

2018/02/04 08:48

なるほど、そういう機能があるのですね!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問