Top / Java / TIPS集

あ、これってべんりだなあって思ったコーディングのメモ。

Apache Axisで、プロキシーを越える。

Apache Axisを使ったWEBサービスのProxyクライアントで、HTTPのプロキシー(ややこしい)を越える方法を探していました。

いやあEclipseでソースにブレークポイントつけまくって、探したー。。。。どうやら、

 org.apache.axis.components.net.DefaultHTTPTransportClientProperties

てクラスが、なにやらプロパティをセットしていて、そこがAxisの環境設定値になってる模様。そしてこのクラスは、org.apache.axis.AxisProperties?というjava.util.Properties みたいなのを使っている。ソースを見ると、httpプロキシを越えるためのキー値は

AxisProperties.setProperty("http.proxyHost", "proxyのサーバ名");
AxisProperties.setProperty("http.proxyPort", "proxyのポート番号");
AxisProperties.setProperty("http.proxyUser", "xxxx");
AxisProperties.setProperty("http.proxyPassword", "xxxx");

越えた。。キター。。。

HSQLDBの起動、フロントエンドの起動

ブラウザのCookieを手軽に参照する

JavaのTIPではないけど、J2EE開発中によく使うので。ブラウザのURLに

javascript:document.cookie;

と入力すると、クライアントのCookie(今開いているサイトに対するもののみ)を参照できます。

Jakarta Commons Langのいろいろ

Jakarta Commons LangはJavaのライブラリだけでは足りないようなユーティリティ的な機能を提供するクラスライブラリです。たとえば、こんな感じで使うことができます。

フィールドをカプセル化する

設定ファイルとかの場所がフィールドに定数で埋め込まれていて、単体テストのときだけそのパスを変えたいなあなんてときがあります。最近はDIとかで変えれるようにするのがはやってますが、DIコンテナなども使ってないときなどはどうすればよいでしょうか。

例としてテスト対象クラスがHogeだとして

public class Hoge{
  private String path ="hoge/hogehoge.properties";
  .....
  public void exe(){
    new File(path).....;
  }
}

なんてのがあるとき、どうすればよいかってことです。

この場合、まずはソースを変更して単体テストしやすくします。そのソースの変更はEclipseなどを用いて、きっちりやる、と。やる手順は

具体的には上のクラスは以下のように変更します。

ってところですね。。ソースの変更に関してはEclipseなどで論理的に安全に行うことはできますが。手順は、

変数を参照している箇所(new File(path)の"path")を選択して、リファクタリング >> フィールドのカプセル化

定数がフィールドにすらいない場合は、上の前にさらにこれをやる

変数を選択して、 リファクタリング >> ローカル変数を フィールドに変換

プレースホルダを使う

MessageFormat?を使うと、{0}のようなプレースホルダを使うことができます。

SimpleDateFormat yyyy = new SimpleDateFormat("yyyy");
SimpleDateFormat MM = new SimpleDateFormat("MM");
SimpleDateFormat dd = new SimpleDateFormat("dd");
Date selectedDate = new Date();
String year = yyyy.format(selectedDate);
String month = MM.format(selectedDate);
String date = dd.format(selectedDate);
Object[] dateArgs = { year, month, date };
MessageFormat form = new MessageFormat("{0}年{1}月{2}日"); <-プレースホルダ
System.out.println(form.format(dateArgs));

実行結果は

2005年03月18日

e.printStackTrace?()の文字列を取得する、出力先を変更する

例外のインスタンスをexとして

StringWriter stringWriter = new StringWriter();
ex.printStackTrace(new PrintWriter(stringWriter));
String message = stringWriter.getBuffer().toString();

WSAD5.1.2でサーバの設定が格納されているディレクトリ

${WORKSPACE}\.metadata\.plugins\com.ibm.wtp.server.core\configs

プロクシ認証などなど

-Dhttp.proxyHost=[プロクシサーバ名] -Dhttp.proxyPort=[ポート番号]
-Dhttp.proxyUser=[UserID] -Dhttp.proxyPassword=[password]

privateなフィールドにアクセスする

たとえばインスタンス名instance のフィールド(Stringで変数名aField)にアクセスするには

Class clazz = instance.getClass();
Field field = clazz.getDeclaredField("aField");
field.setAccessible(true);
String answer = (String)field.get(instance));

で取得できる。ここが参考になりました。

<%@ page %> タグ内の意味。

たとえば

<%@ page contentType=text/html; charset=EUC-JP" pageEncoding="Shift_JIS" %>

とした場合、pageEncodingがソースコードの文字コード、contentTypeで指定できるのが出力文字コードです*1。この場合はソースをShift_JISで書いて、EUC-JPで出力するってことですね。

key=value&...の形式ではないPOSTリクエストの電文を取得する方法

requestからReaderを取得して、そこから文字を取得すればよいわけですね。

BufferedReader reader = request.getReader();
StringBuffer buffer = new StringBuffer();
String line = null;
while ((line = reader.readLine()) != null) {
  buffer.append(URLDecoder.decode(line));
  buffer.append("\n");
}
String reqMsg = new String(buffer);

DOM2String

ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
  TransformerFactory tfactory = TransformerFactory.newInstance();
  Transformer transformer = tfactory.newTransformer();
  transformer.setOutputProperty("encoding", encoding);
  transformer.transform(new DOMSource(document), new StreamResult(out));
} catch (TransformerConfigurationException e) {
  logger_.error(e);
} catch (TransformerException e) {
  logger_.error(e);
}
return out.toString();

String2DOM

例外処理はとりあえずおいといて

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
StringReader stringReader = new StringReader(str); <- str: xmlの文字列
InputSource inputSource = new InputSource(stringReader);
return builder.parse(inputSource); <- Document

ファイル書きだし(バイナリで)

InputStream in = .....;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int j;
while ((j = in.read(b)) != -1)
    baos.write(b, 0, j);
byte[] pix = baos.toByteArray();
write("hoge.dat", pix);

private void write(String filename, byte[] b) {
    BufferedOutputStream stream = null;
    try {
        File file = new File(DictionariesPlugin.getDefault()
                .getStateLocation().toFile(), filename);
        FileOutputStream fstream = new FileOutputStream(file);
        stream = new BufferedOutputStream(fstream);
        stream.write(b);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

    }
}

ファイル書きだし(テキスト)

public boolean write(String log) {
  BufferedWriter writer = null;
  try {
    //第二引数がtrueなら追記、falseなら上書き。
    writer = new BufferedWriter(new FileWriter("./log.txt", true));
    writer.write(log, 0, log.length());
    writer.newLine();
  } catch (FileNotFoundException e) {
    e.printStackTrace();
    return false;
  } catch (IOException e) {
    e.printStackTrace();
    return false;
  } finally {
    try {
      if (writer != null) {
        writer.flush();
        writer.close();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  return true;
}

あるディレクトリからの相対パスを計算して、他のディレクトリに連結したい。

うまく説明できませんが、別のディレクトリに同じパス構成をコピーしたいときなどに使用できると思います。

 //たとえば "c:/temp", "c:/temp/fuga/aaaaa.txt", "d:/huge/hoho" に対して
 // d:/huge/hoho/fuga/aaaaa.txt としたい
 public static String trimAndConcat(String base, String path, String other) {
   URI uriBase = new File(base).toURI();
   URI uriPath = new File(path).toURI();
   URI uriRelativised = uriBase.relativize(uriPath);
   return new File(other, uriRelativised.toString()).getAbsolutePath();
 }

URLからファイルパスへ。

URLクラスからそのファイルまでのパスを取得する方法です。

String path = new File(url.getPath()).getPath();

とやることで、

URL : file:/C:/hoge/config/hoge.txt
File: C:\hoge\config\hoge.txt

に変換ができます。*2*3

(たとえば)拡張子がxmlのファイルをリストする

File mainDirectory = new File([ディレクトリ]);
String[] files = mainDirectory.list(new FilenameFilter() {
  public boolean accept(File dir, String name) {
    if (name.endsWith("xml")) {
      return true;
    }
    return false;
  }
});

filesが拡張子がxmlのファイル(ファイル名、の配列)

拡張子より後ろの文字列を取得する

String hoge="aaa.xml";
hoge.substring(hoge.lastIndexOf('.'));

で.xmlが取得できる。

拡張子より前の文字列を取得する

String hoge="aaa.xml";
hoge.substring(0, hoge.indexOf('.'));

でaaaが取得できる。/etc/aaa.xml.bakとかには使えないけど。。

Javaから、WEBブラウザを起動(Windowsのみ)

try {
	Runtime.getRuntime().exec(
		new String[] {
			"rundll32.exe",
			"url.dll,FileProtocolHandler",
			"http://jp.sun.com/" });
} catch (IOException e) {
	e.printStackTrace();
}

SWTから起動したい方は こちら

WEBアプリケーションのルートを取得してパスを生成する

String root_path = this.getServletContext().getRealPath("/");
String file_path = root_path + "hoge.dat"

DOMオブジェクトをファイルに書き出す

try {
	TransformerFactory tfactory = TransformerFactory.newInstance();
	Transformer transformer = tfactory.newTransformer();
	//			transformer.setOutputProperty("encoding", "EUC-JP");
	transformer.transform(new DOMSource(document), <-document : XMLのDOMです
	//new StreamResult(System.out)); <- こっちだとコンソール出力
	new StreamResult(new FileOutputStream(new File(output))));

} catch (TransformerConfigurationException e) {
	e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
	e.printStackTrace();
} catch (TransformerException e) {
	e.printStackTrace();
} catch (FileNotFoundException e) {
	// TODO 自動生成された catch ブロック
	e.printStackTrace();
}

JSPやServletのOutにDOMを書き出したい。

public void write(HttpServletRequest request, HttpServletResponse response) {
	response.setContentType("text/xml; charset=UTF-8");
	try {
		PrintWriter out = response.getWriter();
		transformer.transform(new DOMSource(getDocument()),
		new StreamResult(out));
	} catch (IOException e) {
	} catch (TransformerException e) {
	}
}

Servletで、コンテンツタイプを指定する。

response.setContentType("text/xml; charset=UTF-8");

プロキシ越えとか、HttpConnection?

fileplain
//プロキシ認証の記述方法
BASE64Encoder encoder = new BASE64Encoder();
urlConnection.setRequestProperty(
 "Proxy-Authorization",
 "Basic " + encoder.encode((userid + ":" + password).getBytes()));

javaの実行

>java -classpath ".;lib;classes;lib\log4j-1.2.8.jar;swt.jar" kino.swt.JavaDocSearchForm
>java -classpath ".;lib;classes;lib\log4j-1.2.8.jar;swt.jar;lib\kino_javadocsearch.jar" 
 kino.swt.JavaDocSearchForm
>java -classpath "クラスパス(セミコロン区切り)" クラス

このサイトよいかも。

Javadoc書き方

@see	UserInformationManager#getUserInformation(String)

とすると、リンクが張られる。

{@link	InformationController	InformationController}のファイル読み込みの実装です。

とか

{@link クラス名#メンバ名 表示テキスト}

なんて使い方もできる

コレクションを配列に変換

type: 型
collection: コレクションクラス
(type[]) collection.toArray(new type[collection.size()]);

配列をコレクションに変換

fileList: Object[]型
java.util.Arrays.asList(fileList);

ファイルを読み込む

BufferedReader reader = null;
try {
	reader = new BufferedReader(new FileReader(path));
	//もしくは
	//new BufferedReader(
	//  new InputStreamReader(url.openStream(), "JISAutoDetect"));
  
	String line;
	while ((line = reader.readLine()) != null) {
		buffer.append(line);
		buffer.append("\n");
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
} finally {
	if (reader != null) {
		try {
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		reader = null;
	}
}

Objectのシリアライズ

try {
	//FileInputStreamオブジェクトの生成
	FileInputStream inFile =
		new FileInputStream([serializeしたファイル名]);

	//ObjectInputStreamオブジェクトの生成 
	ObjectInputStream inObject = new ObjectInputStream(inFile);

	Object object = (クラス名) inObject.readObject();

	inObject.close(); //オブジェクト入力ストリームのクローズ
	inFile.close(); //ファイル入力ストリームのクローズ

	//FileOutputStreamオブジェクトの生成
	FileOutputStream outFile =
		new FileOutputStream([書き出したいファイル名]);

	//ObjectOutputStreamオブジェクトの生成 
	ObjectOutputStream outObject = new ObjectOutputStream(outFile);

	//クラスVectorのオブジェクトの書き込み
	outObject.writeObject(object);

	outObject.close(); //オブジェクト出力ストリームのクローズ
	outFile.close(); //ファイル出力ストリームのクローズ

} catch (FileNotFoundException e) {
} catch (IOException e) {
} catch (ClassNotFoundException e) {
}

インナクラス、無名クラス

インナークラス・無名クラスは、フィールドにはアクセス可能、ローカル変数には不可能。

finalなフィールドの初期化

宣言時に初期化する必要があるのかと思ってたんですが、コンストラクタ内でもよいんですね。知らなかった。


この記事は

選択肢 投票
おもしろかった 12  
そうでもない 2  

Top / Java / TIPS集

現在のアクセス:129673


*1 JSP1.1の場合は、pageEncoding が使えないので、ページの文字コードと出力文字コードは同じになります。
*2 URLクラスをそのままtoStringすると、よけいな文字(file)がついちゃうんですよね。
*3 スペースなどが入っている場合のために、URLDecoder#decodeをかけねばっ

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS