package com.ftinc.si.assist.test;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.ftinc.si.assist.run.DBMediator;
import com.ftinc.si.assist.run.Messages;
import com.ftinc.si.assist.run.VCentral;

import javassist.CannotCompileException;
import javassist.NotFoundException;


//Gsonの必要な機能を自作する。
public class Fson {
	static final Pattern p_map = Pattern.compile("\\A\\{(.*)\\}\\s*\\z", Pattern.DOTALL);
	static final Pattern p_array = Pattern.compile("\\A\\s*\\[(.*)\\]\\s*\\z", Pattern.DOTALL);
	static final Pattern p_float = Pattern.compile("\\A\\s*\\-?([1-9][0-9]*|0)\\.[0-9]+\\s*\\z");
	static final Pattern p_int = Pattern.compile("\\A\\s*\\-?([1-9][0-9]*|0)\\s*\\z");//0単体、もしくは[1-9]から始まる文字列。。
	static final Pattern p_bool = Pattern.compile("\\A\\s*(true|false)\\s*\\z");
	static final Pattern p_string = Pattern.compile("\\A\\s*\"(.*?)\"\\s*\\z", Pattern.DOTALL);
	static final Pattern p_object = Pattern.compile("\\A\\s*\\{(.*)\\}\\s*\\z", Pattern.DOTALL);

	//キャストは総称型を指定してはいけない。制限事項である。
	static final Pattern p_withCast = Pattern.compile("\\A\\s*\\(([\\w\\.\\$\\[\\]]+)\\)(.*)\\s*\\Z", Pattern.DOTALL);

	//(FQNクラス名(テンプレートID)){“更新対象属性までのJsonPath”:新しい属性値,….}
	static final Pattern p_byJsontemplate = Pattern.compile("\\A\\s*\\(([\\w\\.\\[\\]<>,]+)\\([\\w\\-@]+\\)\\)([\\{\\]]?.*[\\}\\]]?)\\s*\\Z", Pattern.DOTALL);

	//デフォルトコンストラクタを作れないサーバ側クラスのためにコンストラクタパラメータのJSONを保持する。
	public static HashMap<String, String> s_defaultParams = null;
	private static ArrayList<Object> o_stack = new ArrayList<Object>();
	public static void initDefaultParams() {
		s_defaultParams = new HashMap<String, String>();
		if (s_defaultParams == null) {
			//RemoteDBの中で呼ばれるかもしれないので、直にResultSetを使う。
			Connection t_con = DBService.s_connect;
			if (t_con == null) {
				t_con = DBMediator.s_connect;
			}
			if (t_con != null) {
				String t_sql = "select * from \"tbl_JSONRecord\" where \"Name\"='CONSTRUCTOR'";
				try {
					Statement t_state = t_con.createStatement();
					ResultSet t_res = t_state.executeQuery(t_sql);
					while ( t_res.next() ) {
						String cname  = t_res.getString("ClassName");
						String json = t_res.getString("Content");

						if (s_defaultParams != null && s_defaultParams.containsKey(cname)) {
							s_defaultParams.put(cname, json);
						}
					}
					t_res.close();
					t_state.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}

	//現在、toJasonを実行中のクラスをスタックに乗せる。
	private static void pushed(Object o) {
		if (o != null) {
			o_stack.add(o);
		}
	}

	//現在、toJasonを実行中のクラスをスタックから外す。
	private static void popped(Object o) {
		if (o != null && o.equals(o_stack.get(o_stack.size() - 1))) {
			o_stack.remove(o_stack.size() - 1);
		}
	}

	//toJsonが無限ループしないようにする。
	private static boolean isLooped(Object obj) {
		if (obj != null) {
			if (o_stack.contains(obj)) {
				return true;
			}
		}
		return false;
	}

	public static class NotSupportedClassException extends Exception {
		public NotSupportedClassException(String msg) {
			super(msg);
		}
	}

	//  Mapならば、key,valueを展開する。
	//  Primitiveなら、toStringを返す。
	//  Arrayなら、[]の排列形式の文字列にする。
	//  Objectなら、インタフェース以外のフィールドを再帰呼び出しで展開する。
	public static String toJson(Object obj, Class<?> c) throws ClassNotFoundException, SecurityException,
												NoSuchMethodException, IllegalAccessException, NoSuchFieldException, NotSupportedClassException {
		return toJson(obj, c, null);
	}

	//上記に加え、正規表現resgが指定されていれば、それにマッチするフィールドのみをJson化する。
	public static String toJson(Object obj, Class<?> c, String regs) throws ClassNotFoundException, SecurityException,
												NoSuchMethodException, IllegalAccessException, NoSuchFieldException, NotSupportedClassException {
		if (isLooped(obj) || obj == null) {
			//isLoopedはリンクが無限ループになっているかをどうかをチェックする。
			return "null";
		}

		String result = "";
		if (c == null) {
			result = toJson(obj, obj.getClass(), regs);
		} else {
			pushed(obj);//クラスがある状態では、objが同一引数で再帰呼び出しはしないので、この位置に置く。

			try {
				String cname = c.getSimpleName();

				if (cname.equals("int") || cname.equals("Integer")) {
					result = Integer.toString((Integer)obj);
				} else if (cname.equals("long") || cname.equals("Long")) {
					result = Long.toString((Long)obj);
				} else if (cname.equals("boolean") || cname.equals("Boolean")) {
					result = Boolean.toString((Boolean)obj);
				} else if (cname.equals("char") || cname.equals("Character")) {
					result = "(java.lang.Character)" + Character.toString((Character)obj);
				} else if (cname.equals("float") || cname.equals("Float")) {
					result = Float.toString((Float)obj);
				} else if (cname.equals("byte") || cname.equals("Byte")) {
					result = "(java.lang.Byte)" + Byte.toString((Byte)obj);
				} else if (cname.equals("double") || cname.equals("Double")) {
					result = "(java.lang.Double)" + Double.toString((Double)obj);
				} else if (cname.equals("AtomicInteger")) {
					result = "(java.util.concurrent.atomic.AtomicInteger)" + obj.toString();
				} else if (cname.equals("AtomicLong")) {
					result = "(java.util.concurrent.atomic.AtomicLong)" + obj.toString();
				} else if (cname.equals("BigDecimal")) {
					result = "(java.math.BigDecimal)" + obj.toString();
				} else if (cname.equals("BigInteger")) {
					result = "(java.math.BigInteger)" + obj.toString();
				} else if (cname.equals("Class")) {
					//objがClass<?>の場合
					return ((Class<?>)obj).getName() + ".class";
				} else if (cname.equals("String")) {
					Matcher t_m = p_string.matcher(obj.toString());
					if (t_m.find()) {
						result = escape(obj.toString());
					} else {
						result = "\"" + escape(obj.toString()) + "\"";
					}
				} else if (c.isArray()) {
					Class<?> c_obj = obj.getClass();
					if (c_obj.isArray()) {
						Class<?> t_c = c.getComponentType();
						String json ="[";
						for (int i = 0; i < Array.getLength(obj); i++) {
							json += toJson(Array.get(obj, i), t_c, regs);
							if (i < Array.getLength(obj) - 1) {
								json += ",";
							}
						}
						result = json + "]";
					} else {
						//クラス系統が異なるのでエラー
						throw new IllegalAccessException(c_obj.getName() + Messages.getString("Fson.0") + c.getName() + "."); //$NON-NLS-1$
					}
				} else if (c.isEnum()) {
					Object[] en_list = c.getEnumConstants();
					String t_json = null;
					for (int i = 0; i < en_list.length; i++) {
						if (obj.equals(en_list[i])) {
							t_json = "(" + c.getName() + ")" + Integer.toString(i);
						}
					}
					if (t_json != null) {
						result = t_json;
					} else {
						//不正なenumでエラー
						throw new IllegalAccessException(c.getName() + "has not " + obj.toString() + ".");
					}
				} else if (obj instanceof Map) {
					String json = "{";
					@SuppressWarnings("unchecked")
					Map<Object, Object> t_map = (Map<Object, Object>)obj;
					for(Entry<Object, Object> entry : t_map.entrySet()) {
						if (json.length() > 1) {
							json += ",";
						}
						String t_key = toJson(entry.getKey(), null);
						if (t_key != null && !t_key.equals("null")) {
							//keyはnullであってはならない。
							json += toJson(entry.getKey(), null, regs) + ":" + toJson(entry.getValue(), null, regs);
						}
					}
					result = json + "}";
				} else if (java.util.List.class.isAssignableFrom(c)) {
					//List系クラスの場合
					String json ="[";
					@SuppressWarnings("rawtypes")
					Object[] t_array = ((java.util.List)obj).toArray();
					for (int i = 0; i < t_array.length; i++) {
						Object x_obj = t_array[i];
						String s_json = "null";
						String t_cast = "";
						if (x_obj != null) {
							//List系にはCastが必要。
							s_json = toJson(x_obj, null, regs);
							if (s_json.startsWith("{") || s_json.startsWith("[")) {
								String xcname = x_obj.getClass().getName();
								if (x_obj.getClass().isArray()) {
									xcname = x_obj.getClass().getComponentType().getName() + "[]";
								}
								t_cast = "(" + xcname + ")";
							}
						}
						json += t_cast + s_json;
						if (i < t_array.length - 1) {
							json += ",";
						}
					}
					result = json + "]";
				} else if (java.util.Collection.class.isAssignableFrom(c)) {
					throw new NotSupportedClassException(c.getName() + ">>Fson cuurently not support.");
				} else if (Tool.isFake(cname)) {
					//Fakeなら$._impl._tableをJsonにする。
					ArrayList<Object> t_fakes = valueByJsonPath(obj, "$");
					if (t_fakes.size() > 0) {
						result = toJson(t_fakes.get(0), HashMap.class, regs);
					}
				} else if (cname.indexOf("$") < 0) {
					//一般的なオブジェクトの場合。インナークラスは除外する。
					//現在のオブジェクトをスタックに積む。
					String t_cast = "";//Interfaceを実体化したオブジェクトにはCastが必要。
					if ((obj != null && c != null) && c != obj.getClass()) {
						if (!c.isInstance(obj)) {
							//クラス系統が異なるのでエラー
							throw new IllegalAccessException(obj.getClass().getName() + Messages.getString("Fson.1") + c.getName() + "."); //$NON-NLS-1$
						}
						t_cast = "(" + obj.getClass().getName() + ")";
					}
					boolean bskip = false;
					if (!Tool.hasDefaultConstructor(obj.getClass().getName(), true) && !s_defaultParams.containsKey(obj.getClass().getName())) {//属性なのでtrueを指定
						//デフォルトコンストラクタもなく、デフォルトパラメータも指定されていない場合、再現しようがないので警告を発する。
						//実行時にtoJsonが使用されるのはsnapshotの時。デバッグモードでログだけ出力する。
						bskip = true;
						Tool.logForTesting(null, "FSON_WARNING: " + obj.getClass().getName() + " " + Messages.getString("Fson.2"));  //$NON-NLS-2$
					}
					if (!bskip) {
						//jsonにできそうな場合。
						String json = "{";

						HashMap<String, String> f_map = getFields(c);//フィールド名、型名。静的なフィールドはJsonの対象外。インスタンス固有でないため。

						for(Entry<String, String> entry : f_map.entrySet()) {
							String key = entry.getKey();
							Object t_obj = null;

							if (regs != null) {
								Pattern t_pat = Pattern.compile(regs);
								Matcher t_m = t_pat.matcher(key);
								if (!t_m.find()) {
									//正規表現が与えられている場合、マッチしないFieldはJsonにしない。
									continue;
								}
							}

							t_obj = Tool.getFieldValue(obj, key);
							Class<?> t_c = Tool.forName(entry.getValue());

							if (regs != null && (t_obj == null || t_obj.toString().length() == 0)) {
								//何もしない。正規表現が指定されている場合、nullや""をな出力しない。★★★★★★★
							} else if (t_obj == null) {
								json += "\"" + key + "\":null,";
							} else if (t_c == t_obj.getClass()) {
								//クラスが一致していたら、素直に書く。
								json += "\"" + key + "\":" + toJson(t_obj, t_obj.getClass(), regs) + ",";
							} else if (t_c.isArray()) {
								//配列のキャストは要素を見て決める。
								json += "\"" + key + "\":(" + t_obj.getClass().getComponentType().getName() + "[])" + toJson(t_obj, t_obj.getClass(), regs) + ",";
							} else {
								String s_json = toJson(t_obj, t_obj.getClass(), regs);

								Matcher t_m = p_object.matcher(s_json);
								if (t_m.find() && !t_c.equals(t_obj.getClass())) {
									//オブジェクトで、かつ、クラスが異なっていたらキャストする。
									json += "\"" + key + "\":(" + t_obj.getClass().getName() + ")" + s_json + ",";
								} else {
									json += "\"" + key + "\":" + s_json + ",";
								}
							}
						}
						result = t_cast + json.replaceFirst(",\\z", "") + "}";
					}
				}
			} finally {
				//現在のクラスをスタックから外す
				popped(obj);
			}
		}
		return result;
	}

	//①生成済みインスタンスの指定かどうかチェック
	//②キャストが指定されているかチェック。そのキャストが有効なら、クラスを変更して再帰呼び出し。
	//③クラスが指定されていない場合、基本型なら書式でクラスを判定し、再帰呼び出し。
	//④配列ならjsonを配列に変換し、再帰呼び出し。
	//⑤手がかりがインタフェースだけなら、復元は不可能。
	//⑥基本型ならWrapperオブジェクトに変更して再現する。
	//⑦文字列ならダブルクォートを取る。
	//⑧インスタンスを作る。
	@SuppressWarnings("unchecked")
	public static Object fromJson(String json, Class<?> cl) throws ClassNotFoundException, InstantiationException, SecurityException,
					NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, ParseException, NotSupportedClassException {
		if (json == null || "null".equals(json) || (json.length() == 0 && !String.class.equals(cl))) {
			return null;
		} else if (json.matches("^[0-9]+\\$[_0-9]+$")) {
			//直接インスタンスを指定している場合
			Object t_obj = Tool.instance_table.get(json);
			if (cl == null || cl.isInstance(t_obj)) {
				return t_obj;
			}
			//なければ文字列とみなす。
			return json;
		}
		//コメントや両側の空白を削除
		json = removeComments(json);

		Matcher t_m = p_withCast.matcher(json);
		if (t_m.find() && (cl == null || !String.class.equals(cl))) {
			//Stringクラスならcastではない。castがあれば実装クラスが分かる。
			String xcname = t_m.group(1);
			String xjson = t_m.group(2);

			Object t_obj = fromJson(xjson, Tool.forName(xcname));
			if (cl == null) {
				return t_obj;
			} else if (t_obj != null && cl.isArray()) {
				if (Array.getLength(t_obj) > 0) {
					//配列なら要素のクラスを比較する。
					Object x_obj = Array.get(t_obj, 0);

					Class<?> x_cl = cl.getComponentType();
					if (x_cl.isInstance(x_obj)) {
						return t_obj;
					}
				}
			} else if (cl.isInstance(t_obj)) {
				return t_obj;
			}
			//クラス系統が異なるのでエラー
			throw new IllegalAccessException(t_m.group(1) + Messages.getString("Fson.3") + cl.getName() + "."); //$NON-NLS-1$
		} else if ((cl == null || cl.getName().equals("java.lang.Object")) && json.indexOf("\"initialize\"") < 0) {
			//jsonがFQN.classの場合、クラスを返す。
			if (json.endsWith(".class")) {
				return Tool.forName(json.substring(0, json.length() - 6));
			}

			//何も指定されていないか、Objectクラス（そのままではインスタンスが作れない）
			t_m = p_array.matcher(json);
			if (t_m.find()) {
				//クラス指定がないのはMapに内包されている場合。
				//とりあえずリストのインスタンスを作れるようにしてやる。
				return fromJson(json, ArrayList.class);
			}
			t_m = p_int.matcher(json);
			if (t_m.find()) {
				try {
					return Integer.valueOf(json);
				} catch (NumberFormatException e) {
					//Integerに収まらなければlongで試す。
					return Long.valueOf(json);
				}
			}
			t_m = p_float.matcher(json);
			if (t_m.find()) {
				try {
					return Float.valueOf(json);
				} catch (NumberFormatException e) {
					//floatで収まらなければdoubleで試す。
					return Double.valueOf(json);
				}
			}
			t_m = p_bool.matcher(json);
			if (t_m.find()) {
				return Boolean.valueOf(json);
			}
			t_m = p_string.matcher(json);
			if (t_m.find()) {
				//埋め込みコードがある場合、処理してから返す。
				return execCodeInString(restore(t_m.group(1)));
			}
			t_m = p_object.matcher(json);
			if (t_m.find()) {
				return fromJson(json, HashMap.class);
			}
			//★★JsonTemplate再利用による方法
			t_m = p_byJsontemplate.matcher(json);
			if (t_m.find()) {
				//テンプレートからJsonを取得し、Objectを復元する。
				String t_cname = t_m.group(1);
				String t_subname = t_m.group(2);
				String t_json = t_m.group(3);

				JSONRecord j_rec = JSONRecord.getJSONRec(t_cname, t_subname);
				if (j_rec != null) {
					Object t_obj = Fson.fromJson(j_rec.content, Tool.forName(t_cname));
					//追加の情報で更新する。キー：JsonPath、値：属性値
					HashMap<String, String> t_map = getFieldMapOfJson(t_json);

					//JsonPathで更新する。
					for(Entry<String, String> entry : t_map.entrySet()) {
						updateByJsonPath(t_obj, entry.getKey(), entry.getValue());
					}
					return t_obj;
				}
			}
			//分からなかったら文字列として扱う。
			return execCodeInString(restore(json));
		}

		String cname = cl.getSimpleName();

		//以下は、一般的なObjectを復元する。まず、Mapを作る。
		HashMap<String, String> t_map = getFieldMapOfJson(json);//!=nullである。

		Object t_obj = null;
		if (t_map.containsKey("initialize")) {
			//初期化のコードあり。
			try {
				t_obj = newFromJson(cl, t_map);
			} catch (CannotCompileException | NotFoundException e) {
				throw new IllegalArgumentException(Messages.getString("Fson.18") + json + "." + e.getMessage()); //$NON-NLS-1$
			}
		}

		//String以外で、""に囲まれていたら、それを外す。
		if (!cname.equals("String")) {
			t_m = p_string.matcher(json);
			if (t_m.find()) {
				//両側に"があるので外す。
				json = t_m.group(1);
			}
		}

		if (cl.isArray()) {
			t_m = p_array.matcher(json);
			if (t_m.find()) {
				String src = t_m.group(1);
				int t_len;
				ArrayList<String> t_list = escapeBraket(src, null);

				String[] sub_srcs;
				String temp = t_list.get(0);
				if (temp == null || temp.length() == 0) {
					sub_srcs = new String[] {};
				} else {
					sub_srcs = t_list.get(0).split(",", -1);
				}
				t_len = sub_srcs.length;
				if (src.length() == 0) {
					t_len = 0;//[]の中に""しかなかったら要素数は0である。
				}

				Class<?> t_cl = cl.getComponentType();
				if ("java.lang.Class".equals(t_cl.getName())) {
					//Class<?>の配列の場合
					t_cl = null;
				}

				Object t_array = t_obj;
				if (t_obj == null) {
					t_array = Array.newInstance(t_cl, t_len);
					for (int i = 0; i < t_len; i++) {
						//restoreだと\''のまま切り出されることがある。restDQTも実行し"に変える。
						Array.set(t_array, i, fromJson(restoreBraket(sub_srcs[i], t_list), t_cl));
					}
				}
				return t_array;
			} else if (t_obj != null) {
				//initializeで配列ができた。しかし、Jsonの書式が違うので要素は設定できない。
				return t_obj;
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.5") + json + "."); //$NON-NLS-1$
			}
		} else if (cl.isInterface()) {
			//エラー
			throw new InstantiationException(Messages.getString("Fson.4")); //$NON-NLS-1$

		} else if (java.util.List.class.isAssignableFrom(cl)) {
			//List系クラスの場合
			t_m = p_array.matcher(json);
			if (t_m.find()) {
				String src = t_m.group(1);
				ArrayList<String> t_list = escapeBraket(src, null);

				String[] sub_srcs;
				String temp = t_list.get(0);
				if (temp == null || temp.length() == 0) {
					sub_srcs = new String[] {};
				} else {
					sub_srcs = t_list.get(0).split(",", -1);
				}
				@SuppressWarnings("rawtypes")
				java.util.List x_list = (java.util.List)t_obj;
				if (x_list == null) {
					x_list = (java.util.List<Object>)Tool.newObject(cl, new Class<?>[]{},  new Object[]{});
					for (int i = 0; i < sub_srcs.length; i++) {
						String s_json = restoreBraket(sub_srcs[i], t_list);
						Object l_obj = fromJson(s_json, null);
						x_list.add(l_obj);
					}
				}
				return x_list;
			} else if (t_obj != null) {
				//initializeで配列ができた。しかし、Jsonの書式が違うので要素は設定できない。
				return t_obj;
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.6") + json + "."); //$NON-NLS-1$
			}
		} else if (java.util.Collection.class.isAssignableFrom(cl)) {
			throw new NotSupportedClassException(cl.getName() + ">>Fson cuurently not support.");
		} else if (cname.equals("int") || cname.equals("Integer")) {
			t_m = p_int.matcher(json);
			if (t_m.find()) {
				return Integer.valueOf(json);
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.7") + json + "."); //$NON-NLS-1$
			}
		} else if (cname.equals("long") || cname.equals("Long")) {
			t_m = p_int.matcher(json);
			if (t_m.find()) {
				return Long.valueOf(json);
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.8") + json + "."); //$NON-NLS-1$
			}
		} else if (cname.equals("byte") || cname.equals("Byte")) {
			return Byte.valueOf(json);
		} else if (cname.equals("boolean") || cname.equals("Boolean")) {
			t_m = p_bool.matcher(json);
			if (t_m.find()) {
				return Boolean.valueOf(json);
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.9") + json + "."); //$NON-NLS-1$
			}
		} else if (cname.equals("char") || cname.equals("Character")) {
			if (json.length() == 1) {
				return Character.valueOf(json.charAt(0));
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.10") + json + "."); //$NON-NLS-1$
			}
		} else if (cname.equals("float") || cname.equals("Float")) {
			t_m = p_float.matcher(json);
			if (t_m.find()) {
				return Float.valueOf(json);
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.11") + json + "."); //$NON-NLS-1$
			}
		} else if (cname.equals("double") || cname.equals("Double")) {
			t_m = p_float.matcher(json);
			if (t_m.find()) {
				return Double.valueOf(json);
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.12") + json + "."); //$NON-NLS-1$
			}
		} else if (cname.equals("BigDecimal")) {
			t_m = p_float.matcher(json);
			if (t_m.find()) {
				return new BigDecimal(json);
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.13") + json + "."); //$NON-NLS-1$
			}
		} else if (cname.equals("BigInteger")) {
			t_m = p_int.matcher(json);
			if (t_m.find()) {
				return new BigInteger(json);
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.14") + json + "."); //$NON-NLS-1$
			}
		} else if (cname.equals("AtomicInteger")) {
			t_m = p_int.matcher(json);
			if (t_m.find()) {
				return new AtomicInteger(Integer.valueOf(json).intValue());
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.15") + json + "."); //$NON-NLS-1$
			}
		} else if (cname.equals("AtomicLong")) {
			t_m = p_int.matcher(json);
			if (t_m.find()) {
				return new AtomicLong(Long.valueOf(json).longValue());
			} else {
				//エラー
				throw new IllegalArgumentException(Messages.getString("Fson.16") + json + "."); //$NON-NLS-1$
			}
		} else if (cname.equals("String")) {
			if (json.length() == 0) {
				return null;
			}

			t_m = p_string.matcher(json);
			if (t_m.find()) {
				//""で囲まれている場合、外して返す。
				json = t_m.group(1);
			}
			//execCodeInStringは埋め込みコードの実行。
			return execCodeInString(restore(json));
		} else if (cl.isEnum()) {
			//json化はenumの位置で行う。クラスからenum配列を取得し、指定にenumを返す。
			//castしている可能性があるのでとり、enum番号のみにする。
			String t_i = json.replaceFirst("^\\s*\\([^\\)]*?\\)\\s*", "");
			return getEnumByInt(cl, t_i);
		} else if (java.util.Map.class.isAssignableFrom(cl)) {
			//Mapの場合、Map<Object,Object>,Map<Integer,Object>,Map<String,Object>などがある。
			HashMap<String, String> temp_map = getFieldMapOfJson(json);
			HashMap<Object, Object> t_result = (HashMap<Object, Object>)t_obj;
			if (t_result == null) {
				t_result = new HashMap<Object, Object>();
			}
			if (t_result != null) {
				for(Entry<String, String> entry : temp_map.entrySet()) {
					Object t_key = fromJson(entry.getKey(), null);
					Object t_value = fromJson(entry.getValue(), null);
					t_result.put(t_key, t_value);
				}
			}
			return t_result;
		}
		//その他のObjectの場合
		try {
			if (Tool.isFake(cl.getName())) {
				//Fakeである。
				ArrayList<String> vals = new ArrayList<String>();
				vals.add(cl.getName());
				final Pattern fake_mem = Pattern.compile("\\(([^\\)]+?)\\)(.*)");
				for(Entry<String, String> entry : t_map.entrySet()) {
					t_m = fake_mem.matcher(entry.getValue());
					if (t_m.find()) {
						//castつき
						vals.add(entry.getKey() + "=" + entry.getValue());
					} else {
						vals.add(entry.getKey() + "=(java.lang.String)" + entry.getValue());
					}
				}
				t_obj = Tool.getFakeInstance(vals.toArray(new String[vals.size()]));
			} else {
				if (t_obj == null) {
					t_obj = newFromJson(cl, t_map);
				}
				//Fakeではない。
				//無事、インスタンスができたなら、MapかObjectを識別し、ObjectならFieldに値を設定する。
				setAttrFromMap(t_obj, t_map);
			}
		} catch (Exception e) {
			throw new IllegalArgumentException(Messages.getString("Fson.18") + json + "."); //$NON-NLS-1$
		}
		return t_obj;
	}

	//toJsonで"退避処理。\"をすべて\\''にする。
	public static String _escape(String str) {
		str = str.replaceAll(Pattern.quote("\\''"), Matcher.quoteReplacement("\\''''"));
		str = str.replaceAll(Pattern.quote("\""), Matcher.quoteReplacement("\\''"));
		return str;
	}

	//fromJsonで\\''を\"に回復する処理
	public static String _restore(String str) {
		str = str.replaceAll(Pattern.quote("\\''"), Matcher.quoteReplacement("\""));

		//まだ後ろに''がある場合、エスケープを継続
		str = str.replaceAll(Pattern.quote("\"''"), Matcher.quoteReplacement("\\''"));
		return str;
	}

	//toJsonで"退避処理。Jsonのエスケープ文字対応。
	public static String escape(String str) {
		String _bs = "%_@_BS_@_%";//\の一時退避用。
		str = str.replaceAll("\t", _bs + "t");
		str = str.replaceAll("\b", _bs + "b");
		str = str.replaceAll("\f", _bs + "f");
		str = str.replaceAll("\n", _bs + "n");
		str = str.replaceAll("\r", _bs + "r");
		str = str.replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement(_bs + _bs));
		str = str.replaceAll("/", Matcher.quoteReplacement(_bs + "/"));
		str = str.replaceAll("\"", Matcher.quoteReplacement(_bs + "\""));
		str = str.replaceAll(_bs, Matcher.quoteReplacement("\\"));
		return str;
	}

	//fromJsonでの回復する処理
	//同じ文字列に対して、二回行ってはいけない。
	public static String restore(String str) {
		String _bs = "%_@_BS_@_%";//\の一時退避用。

		str = Tool.replaceB(str, "\\\\", _bs);
		str = str.replaceAll(Pattern.quote("\\t"), "\t");
		str = str.replaceAll(Pattern.quote("\\b"), "\b");
		str = str.replaceAll(Pattern.quote("\\f"), "\f");
		str = str.replaceAll(Pattern.quote("\\n"), "\n");
		str = str.replaceAll(Pattern.quote("\\r"), "\r");
		str = str.replaceAll(Pattern.quote("\\/"), Matcher.quoteReplacement("/"));
		str = str.replaceAll(Pattern.quote("\\\""), "\"");
		str = Tool.replaceB(str, _bs, "\\");
		return str;
	}

	//コメントと両端の空白を除去
	//文字列の中の「//」は無視なので、一度エスケープする。
	private static String removeComments(String json) throws ParseException {
		ArrayList<String> t_esqList = escapeBraket(json, "\""); //「"」の中だけエスケープ。
		String t_src = t_esqList.get(0);
		String t_str = t_src;

		Pattern t_pat = Pattern.compile("//(\\s|\\?)[^\n]*");
		Matcher t_m = t_pat.matcher(t_src);
		if (t_m.find()) {
			t_str =t_m.replaceAll("");
		}
		t_str = t_str.replaceAll("^\\s*([\\s\\S]*?)\\s*$", "$1");
		return restoreBraket(t_str.toString(), t_esqList);
	}

	//コンストラクタの引数を抽出するパターン。$n(クラス名):JSON文字列
	static final Pattern p_consArg = Pattern.compile("\"?arg([0-9]+)\\(([\\w\\.\\[\\]]+)\\)\"?");

	//Tool.deserializeObject用
	public static Class<?>[] _c_list;
	public static Object[] _o_list;

	//JSONの中の引数パラメーターを探して、セットする。stackにメソッドがある時。
	public static void setParameters(HashMap<String, String> map) throws ClassNotFoundException, SecurityException, IllegalArgumentException, InstantiationException,
							NoSuchMethodException, IllegalAccessException, InvocationTargetException, ParseException, NotSupportedClassException {
		int n = 0;
		for(Entry<String, String> entry : map.entrySet()) {
			//JSONの中でコンストラクタの引数を指定している箇所を数える。
			Matcher t_m = p_consArg.matcher(entry.getKey());
			if (t_m.find()) {
				n++;
			}
		}
		//Tool.deserializeObjectで使用する。
		_c_list = new Class<?>[n];
		_o_list = new Object[n];

		for(Entry<String, String> entry : map.entrySet()) {
			//JSONの中でコンストラクタの引数を指定している箇所を見つける。
			Matcher t_m = p_consArg.matcher(entry.getKey());
			if (t_m.find()) {
				Integer num = Integer.valueOf(t_m.group(1)) - 1;
				String cname = t_m.group(2);

				if (num >= n) {
					throw new IllegalArgumentException("arg" + t_m.group(1) + Messages.getString("Fson.19"));  //$NON-NLS-2$
				}

				_c_list[num] = Tool.forName(cname);//コンストラクタを見つけるため、そのままのクラスを返す。
				_o_list[num] = fromJson(entry.getValue(), Tool.forName(Tool.primitiveToFQN(cname)));

				if (entry.getValue() != null && _o_list[num] == null) {
					throw new IllegalArgumentException("arg" + t_m.group(1) + "(" + cname + Messages.getString("Fson.20"));   //$NON-NLS-3$
				}
			}
		}
	}


	//JSONにコンストラクタ引数があれば、コンストラクタを検出してインスタンスを作る。
	//$n(コンストラクタの引数の型)
	public static Object newFromJson(Class<?> c, HashMap<String, String> map) throws SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException,
											IllegalAccessException, InvocationTargetException, ClassNotFoundException, ParseException, NotSupportedClassException, CannotCompileException, NotFoundException {
		//jsonにオブジェクトを生成するコードが含まれている場合、直接実行する。
		if (map.containsKey("initialize")) {
			//通常、initializeというメンバを作ることはあり得ない。だから使う。ロジックはJson化された文字列なので元に戻す。
			return Tool.constructObject(c.getName(), fromJson(map.get("initialize").toString(), String.class).toString());
		}

		//配列の場合、fromJsonから入ってこないので考慮外。
		//普通のオブジェクトの場合
		//defaultConstructorで試す。
		_c_list = new Class<?>[]{};
		_o_list = new Object[]{};

		//デフォルトコンストラクタがあるかどうか調べる。
		Object t_obj = Tool.tryDefaultConstructor(c);
		if (t_obj != null) {
			return t_obj;
		} else {
			//デフォルトコンストラクタがない。

			//コンストラクタの引数が指定されている場合、コンストラクタの引数をセットする。
			//最初にmapから引数を取得しようとする。
			setParameters(map);
			if (_c_list.length == 0) {
				//なければDBに登録されていたかを調べる。
				String sname = c.getName();
				String paramsStr = s_defaultParams.get(sname);
				if (paramsStr != null) {
					HashMap<String, String> temp_map = getFieldMapOfJson(paramsStr);

					if (temp_map.containsKey("initialize")) {
						//initializeロジックがあれば使う。ロジックはJson化された文字列なので元に戻す。
						return Tool.constructObject(c.getName(), fromJson(temp_map.get("initialize").toString(), String.class).toString());
					}

					setParameters(temp_map);
				} else {
					//見つからないので、オブジェクト生成はできそうにない。
					throw new NoSuchMethodException("FSON_FAIL: " + sname + Messages.getString("Fson.21"));  //$NON-NLS-2$
				}
			}

		}

		//作成するのがインナークラスのインスタンスの場合、コンストラクタの引数に外部インスタンスが必要。
		if (s_outer != null) {
			ArrayList<Class<?>> tc_list = new ArrayList<Class<?>>();
			ArrayList<Object> to_list = new ArrayList<Object>();

			tc_list.add(s_outer.getClass());
			to_list.add(s_outer);

			//第一引数がinnerClassの場合、OuterClassがコンストラクタの引数になる。
			for (int i = 0; i < _c_list.length; i++) {
				tc_list.add(_c_list[i]);
				to_list.add(_o_list[i]);
			}
			_c_list = tc_list.toArray(new Class<?>[tc_list.size()]);
			_o_list = to_list.toArray(new Object[to_list.size()]);

		}
		return Tool.newObject(c, _c_list, _o_list);
	}


	static final Pattern p_dqt = Pattern.compile("\"([^\"]*)\"");
	static final Pattern p_braket1 = Pattern.compile("\\{([^\\{\\}]*?)\\}");
	static final Pattern p_braket2 = Pattern.compile("\\[([^\\[\\]]*?)\\]");
	static final Pattern p_braket3 = Pattern.compile("\\(([^\\(\\)]*?)\\)");
	static final Pattern p_braket4 = Pattern.compile("'([^']*?)'");

	//①JSON文字列を、キーと値の文字列に変換
	//②値がPrimitiveな場合、配列の場合、Map（{}で囲まれている子JSON）の場合に分ける。
	//解析する上で邪魔になるカッコやダブルクォートで囲まれた部分をエスケープする。
	//filterはエスケープする文字集合を指定する。"{(['のうちから選ぶ。nullの場合、全てエスケープ。
	public static ArrayList<String> escapeBraket(String src, String filter) throws ParseException {
		String str_q = "__%%__";

		final Pattern t_pat = Pattern.compile(Pattern.quote(str_q) + "[0-9]+__");
		Matcher __m = t_pat.matcher(src);
		if (__m.find()) {
			//内部でエスケープ用に使っている文字列が検出されたら警告。
			Tool.logForTesting(null, "WARNING:" +  Messages.getString("Fson.22") + src); //$NON-NLS-1$
		}

		//一旦、ソース中にあるエスケープ対象の文字列をstr_qでエスケープする。
		ArrayList<String> t_list = new ArrayList<String>();
		Integer i = 1;

		//一時エスケープ用
		String _ddbs = "%_@_BSBS_@_%";  // \\:Json中でエスケープされている\
		String _ddq = "%_@_DQ_@_%";  // \"： Json中でエスケープされている"

		//正規の""で囲まれた内部の\"をエスケープする。
		String t_src = src;
		//\\を置換して_ddbsにエスケープ
		t_src = t_src.replaceAll(Pattern.quote("\\\\"), _ddbs);
		//\"を置換して_ddqにエスケープ
		t_src = t_src.replaceAll(Pattern.quote("\\\""), _ddq);

		Matcher t_m = null;
		if (filter == null || filter.contains("\"")) {
			//文字列のエスケープ
			t_m = p_dqt.matcher(t_src);
			while (t_m.find()) {
				String t_str = t_m.group();

				t_src = t_src.replaceFirst(Pattern.quote(t_str), Matcher.quoteReplacement(str_q + i.toString() + "__"));

				//_ddq, _ddbsを元に戻して置き換える。復帰用のリストに登録する。
				t_list.add(t_str);

				t_m = p_dqt.matcher(t_src);
				i++;
			}
		}

		if (filter == null || filter.contains("'")) {
			//''のエスケープ
			t_m = p_braket4.matcher(t_src);
			while (t_m.find()) {
				String t_str = t_m.group();
				t_list.add(t_str);
				t_src = t_src.replaceFirst(Pattern.quote(t_str), Matcher.quoteReplacement(str_q + i.toString() + "__"));
				t_m = p_braket4.matcher(t_src);
				i++;
			}
		}

		if (filter == null || filter.contains("{")) {
			//{}のエスケープ
			t_m = p_braket1.matcher(t_src);
			while (t_m.find()) {
				String t_str = t_m.group();

				if (t_str.matches("^" + Pattern.quote(str_q) + Integer.toString(i - 1) + "__" +  "$")) {
					throw new ParseException(Messages.getString("Fson.23"), i - 1); //$NON-NLS-1$
				}

				t_list.add(t_str);
				t_src = t_src.replaceFirst(Pattern.quote(t_str), Matcher.quoteReplacement(str_q + i.toString() + "__"));
				t_m = p_braket1.matcher(t_src);
				i++;
			}
		}

		if (filter == null || filter.contains("[")) {
			//[]のエスケープ
			t_m = p_braket2.matcher(t_src);
			while (t_m.find()) {
				String t_str = t_m.group();
				t_list.add(t_str);
				t_src = t_src.replaceFirst(Pattern.quote(t_str), Matcher.quoteReplacement(str_q + i.toString() + "__"));
				t_m = p_braket2.matcher(t_src);
				i++;
			}
		}

		if (filter == null || filter.contains("(")) {
			//()のエスケープ
			t_m = p_braket3.matcher(t_src);
			while (t_m.find()) {
				String t_str = t_m.group();
				t_list.add(t_str);
				t_src = t_src.replaceFirst(Pattern.quote(t_str), Matcher.quoteReplacement(str_q + i.toString() + "__"));
				t_m = p_braket3.matcher(t_src);
				i++;
			}
		}

		//エスケープ結果の格納
		t_list.add(0, t_src);
		return t_list;
	}

	//エスケープの復元。第二引数はescapeで返却したArrayList。
	public static String restoreBraket(String str, ArrayList<String> list) {
		if (str == null) {
			return null;
		}

		String str_q = "__%%__";
		String t_src = str;

		for (Integer i = list.size() - 1; i > 0; i--) {
			String d_str = list.get(i);

			//括弧内のエスケープ処理を回復する。
			t_src = t_src.replaceFirst(Pattern.quote(str_q + i.toString() + "__"), Matcher.quoteReplacement(d_str));
		}

		//一時エスケープ用
		String _ddbs = "%_@_BSBS_@_%";  // \\:Json中でエスケープされている\
		String _ddq = "%_@_DQ_@_%";  // \"： Json中でエスケープされている"

		//正規の""で囲まれた内部の\"をエスケープする。
		//_ddbsを\\にもどす。
		t_src = t_src.replaceAll(_ddbs, Matcher.quoteReplacement("\\\\"));
		//_ddqを\"にもどす。
		t_src = t_src.replaceAll(_ddq, Matcher.quoteReplacement("\\\""));

		return t_src;
	}


	//JSONのソースを解析し、フィールド名と値の組のマップを作る。
	//t_m.group(1)がエスケープされている場合も考慮する。★★★
	//Keyはキャストがあればオブジェクト。それ以外はString。従って、""を除去すればよい。
	//Valueは""で囲まれていればString。それ以外はオブジェクトを表した文字列。要するにValueは""の除外処理は不要。
	public static HashMap<String, String> getFieldMapOfJson(String src) throws ParseException {
		HashMap<String, String> t_map = new HashMap<String, String>();

		Matcher t_m = p_object.matcher(src);
		if (t_m.find()) {
			ArrayList<String> t_list = escapeBraket(t_m.group(1), null);//nullは全エスケープ

			String[] t_elms;//文字列内のカンマのために特別処理。[]などの中はエスケープ処理済みなのでsplitでOK.
			String temp = t_list.get(0);
			if (temp == null || temp.length() == 0) {
				t_elms = new String[] {};
			} else {
				t_elms = t_list.get(0).split("\\s*,\\s*", -1);
			}

			final Pattern t_pat = Pattern.compile("^([^:]+?)\\s*:\\s*(.*?)$", Pattern.DOTALL);

			for (int i = 0; i < t_elms.length; i++) {
				//各要素は""の場合がある。その場合、Mapには登録しないが、mapはnullではない。
				if (t_elms[i].length() > 0) {
					t_m = t_pat.matcher(t_elms[i]);
					if (t_m.find()) {
						//エスケープを解除しつつ、両側の""を外す。fromJsonする際にStringになってしまう。キーも""で囲んだままだとヒットしない。
						String key = restoreBraket(t_m.group(1), t_list);
						key = key.replaceFirst("^\\s*([\\s\\S]+?)\\s*$", "$1");
						key = key.replaceFirst("^\"(.*)\"$", "$1");
						String val = restoreBraket(t_m.group(2), t_list);
						val = val.replaceFirst("^\\s*([\\s\\S]+?)\\s*$", "$1");
						t_map.put(key, val);
					} else {
						//error
						return null;
					}
				}
			}
		}
		return t_map;
	}

	//引数のクラスのfieldを調べ、JSONで取り扱えるものをマップにする。
	private static HashMap<String, String> getFields(Class<?> c) {
		if (c == null) {
			return null;
		} else if (c.getName().equals("java.lang.Object")) {
			return new HashMap<String, String>();
		} else {
			HashMap<String, String> t_map = getFields(c.getSuperclass());

			Field[] f_list = c.getDeclaredFields();
			for (int i = 0; i < f_list.length; i++) {
				Class<?> t_c = f_list[i].getType();
				if (!Modifier.isFinal(f_list[i].getModifiers()) || !Modifier.isStatic(f_list[i].getModifiers())) {
					//インスタンスが対象のリフレクションで使うために、finalおよびstaticではないこと。
					//staticやfinalは正常な作りならアーカイブではなく、きちんとした手続きでセットすべき。
					if (t_c.isArray()) {
						t_c = t_c.getComponentType();
						t_map.put(f_list[i].getName(), t_c.getName() + "[]");//メンバ変数名, クラス名
					} else {
						t_map.put(f_list[i].getName(), t_c.getName());//メンバ変数名, クラス名
					}
				}
			}
			return t_map;
		}
	}

	//innerClassを生成するためには外部クラスのインスタンスが必要。
	private static Object s_outer = null;

	//第一引数：Mapもしくはオブジェクト系（基本型、ラッパー、配列やリストは除外）
	//第二引数：Mapにオブジェクトの属性名と対応するJsonがMapに格納されている。
	//※第一引数の各フィールドの値を、第二引数のフィールド名に対応する値を使用して上書きする。
	//※属性がnullであれば、そのまま設定。nullでなければ必要な値のみを変更する。
	private static void setAttrFromMap(Object obj, HashMap<String, String> map) {
		if (obj != null && map != null) {
			try {
				if (obj instanceof Map) {
					//Mapなら、Valueを復元して、putする。

					@SuppressWarnings("unchecked")
					Map<Object,Object> res_map = (Map<Object,Object>)obj;
					for(Entry<String, String> entry : map.entrySet()) {
						Object t_key = fromJson(entry.getKey(), null);  //必要に応じてオブジェクト化
						Object t_obj = res_map.get(t_key);

						String t_restored = entry.getValue();
						if (t_obj == null) {
							//存在しない属性なら追加
							t_obj =	fromJson(t_restored, null);
						} else if (Tool.isPrimitive2(t_obj.getClass()) || t_obj.getClass().isEnum()) {
							//primitiveもしくはenumの場合、置き換える。
							t_obj =	fromJson(t_restored, t_obj.getClass());
						} else {
							//既存の属性なら上書き/追加（再帰呼び出しである）
							updateFromJson(t_obj, t_restored);
						}
						if (t_obj != null || !res_map.containsKey(t_key)) {
							//Jsonでnullに更新できない。Json化できずにロジックで属性を作っている可能性がある。toJsonでnullになったからと言って、上書きすると壊す。
							//元々のMapに値がなければ追加する。
							res_map.put(t_key, t_obj);
						}
					}
				} else {
					//Jsonで指定されている属性につき、オブジェクトのFieldにマップする。
					HashMap<String, String> f_map = getFields(obj.getClass());//フィールド名のマップを取得

					for(Entry<String, String> entry : f_map.entrySet()) {
						String key = entry.getKey();
						Field t_f = Tool.getField(obj.getClass(), key);
						if (t_f != null) {
							//ここに入ってくるためには、mapに値がある時のみ。

							//コンストラクタの引数情報がmapに含まれていても、keyではじかれて、ここには入ってこない。
							Class<?> f_c = t_f.getType();
							String t_val = map.get(key);

							//内部クラス用の処理。オブジェクト指向的ではないので気に入らない!
							if (f_c.isMemberClass()) {
								s_outer = obj;
							}

							Object f_obj = t_f.get(obj);
							if (Modifier.isFinal(t_f.getModifiers())) {
								if (!Tool.isPrimitive2(f_c)) {
									//primitiveなら置き換えられない。そうでないならupdateを試みる。
									updateFromJson(f_obj, t_val);
								}
							} else {
								if (f_obj == null || Tool.isPrimitive2(f_c) || f_c.isEnum()) {
									//値が設定されていない、もしくはprimitiveなら作る。
									f_obj = fromJson(t_val, f_c);
								} else {
									updateFromJson(f_obj, t_val);
								}
							}

							//元に戻すおまじない。
							s_outer = null;

							if (f_obj != null) {
								t_f.setAccessible(true);
								t_f.set(obj, f_obj);
							}
						}
					}
				}
			} catch (Exception e) {
				Tool.logIfDebug(e, "@setAttrFromMap.\n");
			}
		}
	}

	//第一引数：配列もしくはリスト
	//第二引数：JSON
	//※JSONの行頭に配列要素の位置が指定されていたら、その位置の要素のみを変更する。
	@SuppressWarnings("unchecked")
	private static void setArrayElementFromJson(Object obj, String json) {
		if (obj != null && json != null) {
			try {
				Class<?> t_c = obj.getClass();

				//注意１：ここで全ての文字列をrestoreしている!!!!!!!
				//        ★★もし、復元するオブジェクトがStringなら、これ以上復元する必要はない。
				String[] a_jsons = (String[])fromJson(json, String[].class);
				for (int i = 0; i < a_jsons.length; i ++) {
					if (a_jsons[i] != null) {
						//注意２：次のfromJsonでrestoreするので一度escapeして戻す。
						String json2 = a_jsons[i];
						Object obj2 = null;
						if (t_c.isArray()) {
							Class<?> t_cl = t_c.getComponentType();
							obj2 = Array.get(obj, i);

							if (t_cl.isAssignableFrom(String.class)) {
								//一度Stringとして復旧しているので、このまま。
								obj2 = json2;
							} else if (obj2 == null) {
								obj2 = fromJson(json2, null);
							} else if (Tool.isPrimitive2(obj2.getClass()) || obj2.getClass().isEnum()) {
								//primitiveなら作る。
								obj2 = fromJson(json2, obj2.getClass());
							} else {
								updateFromJson(obj2, json2);
							}
							Array.set(obj, i, obj2);
						} else {
							//List系
							@SuppressWarnings("rawtypes")
							List t_list = (List)obj;

							//Stringではないパターン
							final Pattern t_pat = Pattern.compile("^(\\{.*\\}|\\[.*\\]|[0-9\\.\\+\\-]+|true|false|\\([^\\)]+\\).+)$", Pattern.DOTALL);
							Matcher t_m = t_pat.matcher(json2);

							if (t_list.size() > i) {
								obj2 = t_list.get(i);
								if (!t_m.find()) {
									//Stringなので、このまま。
									obj2 = json2;
								} else if (obj2 == null) {
									//値が設定されていないなら作る。
									obj2 = fromJson(json2, null);
								} else if (Tool.isPrimitive2(obj2.getClass()) || obj2.getClass().isEnum()) {
									//primitiveなら作る。
									obj2 = fromJson(json2, obj2.getClass());
								} else {
									updateFromJson(obj2, json2);
								}
								t_list.set(i, obj2);
							} else if (t_list.size() >= i) {
								//元の要素が存在しない。だから追加である。
								if (t_m.find()) {
									obj2 = Fson.fromJson(json2, null);
								} else {
									//Stringなので、このまま。
									obj2 = json2;
								}
								t_list.add(obj2);
							} else {
								//t_listの方が短い場合.Listの実装によっては、不可能。ArrayListなら可能。
								Tool.logIfDebug(null, Messages.getString("Fson.24") + obj.toString() + Messages.getString("Fson.25")); //$NON-NLS-1$ //$NON-NLS-2$
							}
						}
					}
				}
			} catch (Exception e) {
				Tool.logIfDebug(e, "@setArrayElementFromJson.\n");
			}
		}
	}


	//jsonの内容を見て、objの属性をピンポイントで更新する。objはPrimitiveではない。
	public static void updateFromJson(Object obj, String str_json) {
		//どちらかがnullなら何もしない。
		if (obj != null && str_json != null) {
			try {
				String json = Fson.removeComments(str_json);

				Class<?> t_c = obj.getClass();
				if (t_c.isArray() || java.util.List.class.isAssignableFrom(t_c)) {
					setArrayElementFromJson(obj, json);
				} else if (Tool.isPrimitive2(t_c)) {
					//Tool.isPrimitiveは配列も含むが、配列は前段の条件文で補足済み。ここでは置き換え不可能な型のみ。
					Tool.logIfDebug(null, "@updateFromJson.\n");
				} else {
					HashMap<String, String> _map = Fson.getFieldMapOfJson(json);
					Fson.setAttrFromMap(obj, _map);
				}
			} catch (Exception e) {
				Tool.logIfDebug(e, "@updateFromJson.\n");
			}
		}
	}

	//JsonPathで指定した属性の値に、第三引数を適用する。
	//nullを割り当てたければ、非Stringの場合は""、Stringの場合は"null"を第三引数として渡すこと。
	//返却値：true=更新成功。false=JsonPathもしくはjsonが不正。
	public static Boolean updateByJsonPath(Object obj, String jpath, String json) {
		if (obj != null) {
			Class<?> t_c = obj.getClass();
			if (t_c.isArray() || !Tool.isPrimitive2(t_c)) {
				//部分置き換え可能な型のみが対象。それ以外ははじく。

				if (jpath.startsWith("\"") && jpath.endsWith("\"")) {
					jpath = jpath.substring(1, jpath.length() - 1);
				}
				String t_path = esqDot(jpath);//[]の中の「.」を退避する。

				if (Tool.isFake(t_c.getName())) {
					//Fakeなら、先頭の$をとってくっつける。
					if (t_path.equals("$")) {
						t_path = "";
					} else if (!t_path.startsWith(".")) {
						t_path = "." + t_path;
					}
					t_path = "$._impl._table" + t_path;
				}

				String[] t_route = t_path.split("\\.");
				ArrayList<Object> t_list = hitFieldByJsonPaths(0, t_route, obj, json);
				if (t_list != null) {
					return true;
				} else {
					Tool.logForTesting(null, "Failed to update Object <<" + obj.toString() + ">> since not found xpath=" + jpath + "\n");
				}
			}
		}
		return false;
	}

	//JsonPathで指定した属性値を取得する。
	//返却値：nullの場合、見つからなかった。JsonPathが不正の可能性あり。
	public static ArrayList<Object> valueByJsonPath(Object obj, String jpath) {
		String t_path = esqDot(jpath);//[]の中の「.」を退避する。

		Class<?> t_c = obj.getClass();
		if (t_c.getName().startsWith("test.fake.")) {
			//Fakeなら、先頭の$をとってくっつける。
			if (t_path.equals("$")) {
				t_path = "";
			} else if (t_path.startsWith("$.")) {
				t_path = t_path.substring(1);
			} else if (!t_path.startsWith(".")) {
				t_path = "." + t_path;
			}
			t_path = "$._impl._table" + t_path;
		} else if (t_c.getName().startsWith("test.impl.")) {
			if (t_path.equals("$")) {
				t_path = "";
			} else if (t_path.startsWith("$.")) {
				t_path = t_path.substring(1);
			} else if (!t_path.startsWith(".")) {
				t_path = "." + t_path;
			}
			t_path = "$._table" + t_path;
		}
		if (t_path.length() == 0) {
			ArrayList<Object> t_result = new ArrayList<Object>();
			t_result.add(obj);
			return t_result;
		}

		String[] t_rooute = t_path.split("\\.");
		return hitFieldByJsonPaths(0, t_rooute, obj, null);
	}

	//objのfieldを検索し、rooute[n]の名前があれば更新する。nの初期値は１。
	//json=nullは、pathで指定した参照のみ。
	@SuppressWarnings("unchecked")
	private static ArrayList<Object> hitFieldByJsonPaths(int n, String[] route, Object obj, String json) {
		if (n > route.length - 1) {
			//検索範囲外
			return null;
		}
		//現在のJsonPathのキーワードを取得。
		String a_name = route[n];
		if (a_name == null) {
			a_name = "";
		} else if ("$".equals(a_name) && n < route.length - 1) {
			//ルートが$であることはお約束。ルートなら次に進む。
			return hitFieldByJsonPaths(n + 1, route, obj, json);
		}
		ArrayList<Object> t_result = new ArrayList<Object>();
		if (n == 0 && route.length == 1) {
			//更新する。objはprimitiveではないはず。
			Integer ii = null;
			if (a_name.length() > 2 && a_name.substring(1, a_name.length() - 1).matches("^\\d+$")) {
				//a_nameが[\d+]の場合
				ii = Integer.parseInt(a_name.substring(1, a_name.length() - 1));
			}
			if (a_name.equals("-") || a_name.equals("$")) {
				if (json != null) {
					//属性指定がないので、本体の書き換え。
					updateFromJson(obj, json);
				}
				t_result.add(obj);
			} else	if (obj.getClass().isArray()) {
				//配列の要素の置き換え
				try {
					if (json != null) {
						Array.set(obj, ii, fromJson(json, null));
					}
					t_result.add(Array.get(obj, ii));
				} catch (ArrayIndexOutOfBoundsException | IllegalArgumentException | ClassNotFoundException
						| InstantiationException | SecurityException | NoSuchMethodException | IllegalAccessException
						| InvocationTargetException | ParseException | NotSupportedClassException e) {
					return null;
				}
			} else if (obj instanceof List) {
				//Listの要素の置き換え
				try {
					if (json != null) {
						((List<Object>)obj).add(ii, fromJson(json, null));
						((List<Object>)obj).remove(ii + 1);
					}
					t_result.add(((List<Object>)obj).get(ii));
				} catch (ClassNotFoundException | InstantiationException | SecurityException | NoSuchMethodException
						| IllegalArgumentException | IllegalAccessException | InvocationTargetException | ParseException
						| NotSupportedClassException e) {
					return null;
				}
			} else if (obj instanceof Map) {
				try {
					if (json != null) {
						((Map<Object, Object>)obj).put(a_name, fromJson(json, null));
					}
					t_result.add(((Map<Object, Object>)obj).get(a_name));
				} catch (ClassNotFoundException | InstantiationException | SecurityException | NoSuchMethodException
						| IllegalArgumentException | IllegalAccessException | InvocationTargetException | ParseException
						| NotSupportedClassException e) {
					return null;
				}
			} else {
				//上記以外なら、jsonpathを修正して、再試行する。
				return  hitFieldByJsonPaths(0, new String[] {"$", a_name}, obj, json);
			}
			return t_result;
		}

		if (a_name.length() == 0) {
			//「..」でつながっている場合である。
			if (obj instanceof Map) {
				Map<String, Object> t_map = (Map<String, Object>)obj;
				for(Entry<String, Object> entry : t_map.entrySet()) {
					t_result = hitFieldByJsonPaths(n, route, entry.getValue(), json);
				}
			} else {
				//「..」で該当のFieldが見つからないとき、全てのFieldを探索。
				ArrayList<Field> t_list = new ArrayList<Field>();
				Tool.getAllFields(obj.getClass(), t_list);
				for (int i = 0; i < t_list.size(); i++) {
					Object n_obj;
					try {
						n_obj = Tool.getFieldValue(obj, t_list.get(i).getName());
						if (n_obj != null) {
							t_result = hitFieldByJsonPaths(n, route, n_obj, json);
						}
					} catch (NoSuchFieldException e) {
						//何もしない。この枝に何もないというのが結論。エラーかどうかは最後まで分からない。
					}
				}
			}
		} else {
			//[]があれば、配列/ListもしくはMap/Objectのフィールドである。[]を除去して、純粋なフィールド名を得る。
			String f_name = a_name.replaceFirst("^([\\w\\$]*)\\[.*\\]$", "$1");
			//[]の中。配列もしくはListであった場合は位置、それ以外ならフィールドが満たすべき条件。
			String f_cond = a_name.replaceFirst("^[\\w\\$]*\\[(.*)\\]$", "$1");

			if (a_name.endsWith("]")) {
				Object f_obj = null;
				if (obj instanceof Map) {
					Map<Object, Object> t_map = (Map<Object, Object>)obj;
					f_obj = t_map.get(Tool.getObjectfromJSON(null, f_name));//キーがString以外もありうる。
				} else if (f_name.length() == 0 || f_name.equals("$")) {
					//f_nameが$もしくは""のとき、f_objは自分自身
					f_obj = obj;
				} else {
					try {
						f_obj = Tool.getFieldValue(obj, f_name);

						if (f_obj == null) {
							//まだ値が設定されていない。とりあえず、入れ物(配列もしくはリスト)を作ろうとする。
							Field t_fld = Tool.getField(obj.getClass(), f_name);
							if (f_cond.matches("^(0|\\*)$")) {
								//指定されているのが、最初の値もしくは任意であるなら、作れるか試みる。
								Class<?> f_class = t_fld.getType();
								Class<?> g_class = null;
								if (f_class.isArray()) {
									//配列である。
									g_class = f_class.getComponentType();
								} else {
									//Listである。クラスでない場合もあるので、要注意。
									g_class = (Class<?>)t_fld.getGenericType();
								}

								String t_json = "";
								if (g_class.isArray() || java.util.List.class.isAssignableFrom(g_class)) {
									//配列もしくはList系クラスの場合
									t_json = "[]";
								} else if (Tool.isPrimitive2(g_class)) {
									//これ以上細かくならないのでjsonを指定する。
									t_json = json;
								} else {
									t_json= "{}";
								}
								f_obj = fromJson("[" + t_json + "]", t_fld.getType());
							}
						}
					} catch (NoSuchFieldException | ClassNotFoundException | InstantiationException | SecurityException
							| NoSuchMethodException | IllegalArgumentException | IllegalAccessException | InvocationTargetException
							| ParseException | NotSupportedClassException e1) {
						return null;
					}
				}
				if (f_obj != null) {
					String[] f_conds = restDot(f_cond).split("\\]\\[");//条件は複数ある場合がある。

					if (n == route.length - 1) {
						//末端である。次の「.」はない。
						if (json != null && f_cond.matches("^[0-9,:\\[\\]]+$")) {
							//リストか配列の位置指定である。jsonを指定して更新する。
							f_obj = resolveNext(f_obj, 0, f_conds, t_result, json);
						} else if (json == null) {
							//参照である。結果はt_resultに追加される。
							f_obj = resolveNext(f_obj, 0, f_conds, t_result, null);
						} else {
							//末端なのに配列要素の条件指定ではないので、更新しない。何もしない。
						}
					} else {
						//末端ではない。
						ArrayList<Object> next_objs = new ArrayList<Object>();

						//json = nullを措定するのは、次の行では更新せず、対象を収集するのみだから。
						//末端ではないから、必然的に収集したオブジェクトは属性を持つので基本型ではないObjectである。
						//従って、そのオブジェクトを更新すればよい。
						f_obj = resolveNext(f_obj, 0, f_conds, next_objs, null);

						//next_objsには[]で指定された条件に適合したオブジェクトが格納されている。
						for (int i = 0; i < next_objs.size(); i++) {

							ArrayList<Object> t_list = hitFieldByJsonPaths(n + 1, route, next_objs.get(i), json);
							if (t_list != null) {
								//t_list!=nullということは、必然的にjson==null。収集する。
								t_result.addAll(t_list); //t_listをマージする。
							}
						}
					}
				}
			} else if ("*".equals(a_name)) {
				//同一階層の属性の全てが対象。但し、ArrayやListでないこと。
				if (!(obj instanceof List) && !(obj.getClass().isArray())) {
					if (obj instanceof Map) {
						Map<String, Object> t_map = (Map<String, Object>)obj;
						for(Entry<String, Object> entry : t_map.entrySet()) {
							//nullもある。
							if (n == route.length - 1) {
								//末端である。
								Object t_val = entry.getValue();
								if (json != null) {
									//必要な属性だけ上書きする。
									if (t_val == null || Tool.isPrimitive2(t_val.getClass()) || t_val.getClass().isEnum() || json.indexOf("\"initialize\"") > 0) {
										//置き換える。
										t_val = Tool.getObjectfromJSON(entry.getValue().getClass(), json);
									} else {
										//更新する。
										updateFromJson(t_val, json);
									}
									t_map.put(entry.getKey(), t_val);
								} else {
									//json==nullなので収集する。
									t_result.add(t_map.get(entry.getKey()));
								}
							} else {
								if (entry.getValue() != null) {
									t_result =hitFieldByJsonPaths(n + 1, route, entry.getValue(), json);
								}
							}
						}
					} else {
						ArrayList<Field> f_list = new ArrayList<Field>();
						Tool.getAllFields(obj.getClass(), f_list);
						for (int i = 0; i < f_list.size(); i++) {
							Object n_obj;
							if (n == route.length - 1) {
								//末端である。
								f_list.get(i).setAccessible(true);
								try {
									n_obj = Tool.getFieldValue(obj, f_list.get(i).getName());
									if (json != null) {
										if (n_obj == null || Tool.isPrimitive2(n_obj.getClass()) || n_obj.getClass().isEnum() || json.indexOf("\"initialize\"") > 0) {
											//置き換える。
											n_obj = Tool.getObjectfromJSON(f_list.get(i).getType(), json);
										} else {
											//更新する。
											updateFromJson(n_obj, json);
										}
										f_list.get(i).set(obj, n_obj);
									} else {
										//json==nullなので収集する。
										t_result.add(f_list.get(i).get(obj));//現在の状態を返す。
									}
								} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
									//何もしない。この枝に何もないというのが結論。エラーかどうかは最後まで分からない。
								}
							} else {
								try {
									n_obj = Tool.getFieldValue(obj, f_list.get(i).getName());
									if (n_obj != null) {
										t_result = hitFieldByJsonPaths(n + 1, route, n_obj, json);
									}
								} catch (NoSuchFieldException e) {
									//何もしない。この枝に何もないというのが結論。エラーかどうかは最後まで分からない。
								}
							}
						}
					}
				}
			} else if (n == route.length - 2 && json != null) {
				//.でつないだJsonPathの最後の一歩手前.設定の場合、ここで行う。
				String f_name2 = route[n + 1].replaceFirst("^([\\w\\$]*)\\[.*\\]$", "$1");

				Object target = null;//末端の親オブジェクト
				if (obj instanceof Map) {
					//Mapの場合、上書きもしくは追加（!!）する。
					Map<Object, Object> t_map = (Map<Object, Object>)obj;
					target = t_map.get(f_name);
				} else {
					try {
						//注意：fakeであっても、f_nameが存在する属性ならオブジェクトを返す。
						target = Tool.getFieldValue(obj, f_name);
					} catch (NoSuchFieldException e) {
						//スルーする。
					}
				}
				if (target == null) {
					//途切れたので、そのまま抜ける。
				} else if (target instanceof Map) {
					//末端の親がMapである。
					//Mapの場合、上書きもしくは追加（!!）する。
					Map<Object, Object> t_map = (Map<Object, Object>)target;
					Object prev_obj = t_map.get(f_name2);
					Class<?> t_c = null;
					if (prev_obj != null) {
						t_c = prev_obj.getClass();
					}
					if (prev_obj == null || (json != null && (Tool.isPrimitive2(prev_obj.getClass()) || prev_obj.getClass().isEnum() || json.indexOf("\"initialize\"") > 0))) {
						//末端がnull,Primitive,それに類するもの、もしくはinitializeが指定されているものは置き換える。
						//json!=nullなので更新する。
						t_map.put(Tool.getObjectfromJSON(null,f_name2), Tool.getObjectfromJSON(t_c, json));
					} else {
						//更新する。
						updateFromJson(prev_obj, json);
					}
					t_result.add(prev_obj);
				} else if (Tool.isFake(target.getClass().getName())) {
					//fakeの場合、そのまま更新参照ができないので先に進む。
					t_result = hitFieldByJsonPaths(n + 1, route, target, json);
				} else {
					//fakeでないObjectの場合、次が末端である。追加はしない。
					//t_fの指しているオブジェクトが末端である。
					Field t_f = Tool.getField(target.getClass(), f_name2);
					try {
						if (json != null) {
							Object n_obj = Tool.getFieldValue(target, t_f.getName());
							if (n_obj == null || Tool.isPrimitive2(n_obj.getClass()) || n_obj.getClass().isEnum() || json.indexOf("\"initialize\"") > 0) {
								//末端がnull,Primitive,それに類するもの、もしくはinitializeが指定されているものは置き換える。
								n_obj = Tool.getObjectfromJSON(t_f.getType(), json);
							} else {
								//更新する。fakeには次の処理は対象外。
								updateFromJson(n_obj, json);
							}
							//json!=nullなので更新する。
							t_f.set(target, n_obj);
						}
						t_result.add(t_f.get(target));
					} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
						//何もしない。この枝に何もないというのが結論。エラーかどうかは最後まで分からない。
					}
				}
			} else if (n == route.length - 1) {
				//.でつないだJsonPathの最後。
				Object target = null;  //objが親なので末端を取得する。
				if (obj instanceof Map) {
					//Mapの場合、上書きもしくは追加（!!）する。
					Map<Object, Object> t_map = (Map<Object, Object>)obj;
					target = t_map.get(f_name);

					Class<?> t_c = null;
					if (target != null) {
						t_c = target.getClass();
					}
					if (target == null || (json != null && (Tool.isPrimitive2(target.getClass()) || target.getClass().isEnum() || json.indexOf("\"initialize\"") > 0))) {
						//末端がnull,Primitive,それに類するもの、もしくはinitializeが指定されているものは置き換える。
						//json!=nullなので更新する。
						t_map.put(f_name, Tool.getObjectfromJSON(t_c, json));
					} else {
						//更新する。
						updateFromJson(target, json);
					}
				} else {
					try {
						//注意：fakeであっても、f_nameが存在する属性ならオブジェクトを返す。
						target = Tool.getFieldValue(obj, f_name);
						if (json != null) {
							Field t_fld = Tool.getField(obj.getClass(), f_name);

							//指定されているのが、最初の値もしくは任意であるなら、作れるか試みる。
							Class<?> f_class = t_fld.getType();
							if (target == null || json.matches("^\\([\\.\\w]+\\).+$") || Tool.isPrimitive2(f_class)) {
								//(1)まだ値が設定されていない。とりあえず、中身が空のオブジェクトを作ろうとする。
								//(2)明にcastされている。サブクラスなどの可能性あり。
								//(3)上書きするしかない基本型とその類型
								try {
									target = fromJson(json, f_class);

									//生成した値をセットする。
									t_fld.set(obj, target);
								} catch (ClassNotFoundException | InstantiationException | SecurityException | NoSuchMethodException
										| IllegalArgumentException | IllegalAccessException | InvocationTargetException
										| ParseException | NotSupportedClassException e) {
									return null;
								}
							} else {
								updateFromJson(target, json);
							}
						}
					} catch (NoSuchFieldException e) {
						//スルーする。
					}
				}
				t_result.add(target);
			} else {
				//.でつないだJsonPathの途中
				if (obj instanceof Map) {
					Map<Object, Object> t_map = (Map<Object, Object>)obj;
					Object f_obj = t_map.get(Tool.getObjectfromJSON(null, f_name));
					t_result = hitFieldByJsonPaths(n + 1, route, f_obj, json);
				} else {
					try {
						Object f_obj = Tool.getFieldValue(obj, f_name);

						if (f_obj == null) {
							//まだ値が設定されていない。とりあえず、中身が空のオブジェクトを作ろうとする。
							Field t_fld = Tool.getField(obj.getClass(), f_name);

							//指定されているのが、最初の値もしくは任意であるなら、作れるか試みる。
							Class<?> f_class = t_fld.getType();
							Class<?> g_class = null;

							String f_json = "{@}";
							if (f_class.isArray()) {
								//配列である。
								g_class = f_class.getComponentType();
							} else if (java.util.List.class.isAssignableFrom(f_class)) {
								//Listである。クラスでない場合もあるので、要注意。
								g_class = (Class<?>)t_fld.getGenericType();
							} else if (Tool.isPrimitive2(f_class)) {
								f_json = json;
							}

							String t_json = "{}";
							if (g_class != null) {
								if (g_class.isArray() || java.util.List.class.isAssignableFrom(g_class)) {
									//配列もしくはList系クラスの場合
									t_json = "[]";
								} else if (Tool.isPrimitive2(g_class)) {
									//これ以上細かくならないのでjsonを指定する。
									t_json = json;
								}
							}
							f_obj = fromJson(f_json.replaceFirst("@", Matcher.quoteReplacement(t_json)), t_fld.getType());
							t_fld.set(obj, f_obj);
						}

						t_result = hitFieldByJsonPaths(n + 1, route, f_obj, json);
					} catch (NoSuchFieldException | ClassNotFoundException | InstantiationException | SecurityException | NoSuchMethodException
							| IllegalArgumentException | IllegalAccessException | InvocationTargetException | ParseException
							| NotSupportedClassException e1) {
						return null;
					}
				}
			}
		}
		if (t_result.size() == 0) {
			return null;
		}
		return t_result;
	}


	//objは配列,List,Map,Objectである。
	//iはconditionsのうち、今回処理すべき位置。
	@SuppressWarnings("unchecked")
	private static Object resolveNext(Object obj, int i, String[] conditions, ArrayList<Object> list, String json) {
		//現在の要素指定条件
		String cond = conditions[i];

		if ("*".equals(cond)) {
			//配列かListの全ての要素。*は配列かListのみに使う。
			int n = -1;
			if (obj.getClass().isArray()) {
				n = Array.getLength(obj);
			} else if (obj instanceof List) {
				n = ((List<Object>)obj).size();
			}
			for (int j = 0; j < n; j++) {
				//j：リストもしくは配列の位置、i+1：次に処理すべき条件の位置
				obj = recursiveResolve(obj, j, i + 1, conditions, list, json);
			}
		} else if (cond.matches("^[0-9]+:[0-9]+$")) {
			//配列の範囲を指定している。
			final Pattern range1 = Pattern.compile("^([\\-0-9]*):([0-9]+)$");
			Matcher t_m = range1.matcher(cond);
			if (t_m.find()) {
				String str_from = t_m.group(1);
				String str_to = t_m.group(2);
				Integer ifrom = 0;
				Integer ito = 0;
				if (str_from.length() > 0) {
					ifrom = Integer.valueOf(str_from);
					if (str_to.length() > 0) {
						ito = Integer.valueOf(str_to);
					}
				}
				if (ifrom < 0) {
					//JsonPathではマイナスは最後尾というルールらしい。
					ifrom = Array.getLength(obj) - 1;
					ito = ifrom;
				}

				for (int j = ifrom; ito >= i; i++) {
					obj = recursiveResolve(obj, j, i + 1, conditions, list, json);
				}
			}
		} else if (cond.matches("^[\\-0-9,]+$")) {
			//配列の位置を個別指定。1個以上の位置がある。
			String[] str_nums = cond.split(",");
			for (int j = 0; j < str_nums.length; j++) {
				Integer t_n = Integer.valueOf(str_nums[j]);
				obj = recursiveResolve(obj, t_n, i + 1, conditions, list, json);
			}
		} else if (cond.matches("^\\(.*\\)$")) {
			//評価式。最後の条件でない場合に更新可能。最後の条件は位置である必要がある。
			String exps = cond.replaceFirst("^\\?\\((.+)\\)$", "$1");
			String num_exps = evalFieldsOfNumber(obj, exps);
			Integer il = numberByExpression(num_exps);
			if (il != null) {
				obj = recursiveResolve(obj, il, i + 1, conditions, list, json);
			}
		} else if (cond.matches("^\\?\\(@\\.\\w+\\)$")) {
			//属性の存在判定
			String f_name = cond.replaceFirst("^\\?\\(@\\.(\\w+)\\)$", "$1");
			try {
				Tool.getFieldValue(obj, f_name);

				//Tool.getFieldValueを通過したので、属性は存在することが確定。
				//配列、リストの位置指定ではないので更新しない。
				obj = resolveNext(obj, i + 1, conditions, list, null);
			} catch (NoSuchFieldException e) {
				//存在しないで、何もしない。というのも正常な判定処理。
			}
		} else if (cond.matches("^\\?\\(.+\\)$")) {
			//Boolean判定(属性の存在判定は上記で除外されているので)
			String exps = cond.replaceFirst("^\\?\\((.+)\\)$", "$1");
			String num_exps = evalFieldsOfNumber(obj, exps);
			if (evalIfBoolean(num_exps)) {
				//配列、リストの位置指定ではないので更新しない。
				obj = resolveNext(obj, i + 1, conditions, list, null);
			}
		} else if (obj instanceof Map) {
			//condは文字列
			Map<Object, Object> t_obj = (Map<Object, Object>)obj;
			Object key = Tool.getObjectfromJSON(null, cond);
			Object n_obj = t_obj.get(key);
			if (i == conditions.length) {
				//最後の条件を通過したので、これ以上は判定できない。
				if (json == null) {
					list.add(t_obj.get(key));
				} else {
					//json!=nullということは、更新対象である。
					//更新目的なので値をセットする。

					if (n_obj == null || Tool.isPrimitive2(n_obj.getClass()) || n_obj.getClass().isEnum()) {
						n_obj = Tool.getObjectfromJSON(null, json);
					} else {
						updateFromJson(n_obj, json);
					}
					t_obj.put(key, n_obj);
				}
			} else {
				n_obj = resolveNext(n_obj, i + 1, conditions, list, json);
				t_obj.put(key, n_obj);
			}
		}
		return obj;
	}


	//resolveNextから呼ばれる再帰処理用のメソッド。ここでは更新せずに、resolveNextで更新する。
	//objが配列もしくはListであった場合、次元を落としていく。
	//pos:objが配列もしくはListの時の現在の位置。Listの場合、最後尾+1を指定すると追加できる。	i：条件配列の位置
	//    言い換えると、pos：リストもしくは配列の位置、i：次に処理すべき条件の位置
	//条件絞り込みを続けて行うために、次のオブジェクトを確定し、resolveNextを呼ぶ。
	private static Object recursiveResolve(Object obj, Integer pos, int i, String[] conditions, ArrayList<Object> list, String json) {
		if (obj.getClass().isArray()) {
			Class<?> a_c = obj.getClass().getComponentType();
			Object n_obj = null;
			if (Array.getLength(obj) > pos) {
				n_obj = Array.get(obj, pos);
				if (i == conditions.length) {
					//最後の条件を通過したので、これ以上は判定できない。
					if (json == null) {
						list.add(n_obj);
					} else {
						//json!=nullということは、更新対象である。
						//更新目的なので値をセットする。
						if (n_obj == null || Tool.isPrimitive2(a_c) || a_c.isEnum()) {
							n_obj = Tool.getObjectfromJSON(a_c, json);
						} else {
							updateFromJson(n_obj, json);
						}
					}
				} else {
					//リストもしくは配列の次の次元に移る。
					n_obj = resolveNext(n_obj, i, conditions, list, json);
				}
				Array.set(obj, pos, n_obj);
			}
		} else if (obj instanceof Map) {
			//数字オブジェクトをキーにしたマップ
			@SuppressWarnings("unchecked")
			Map<Object, Object> t_obj = (Map<Object, Object>)obj;
			if (i == conditions.length) {
				//最後の条件を通過したので、これ以上は判定できない。
				if (json == null) {
					list.add(t_obj.get(pos));
				} else {
					//json!=nullということは、更新対象である。
					//更新目的なので値をセットする。

					Object n_obj = t_obj.get(pos);
					if (n_obj == null || Tool.isPrimitive2(n_obj.getClass()) || n_obj.getClass().isEnum()) {
						n_obj = Tool.getObjectfromJSON(null, json);
					} else {
						updateFromJson(n_obj, json);
					}
					t_obj.put(pos, n_obj);
				}
			} else {
				//扱えない。
				Tool.logIfDebug(null, "json=" + json + "\ncan not be applied to " + obj.toString() + " with conditions " + conditions[i] + ".");
				obj = null;
			}
		} else if (obj instanceof List) {
			@SuppressWarnings("unchecked")
			List<Object> t_obj = (List<Object>)obj;
			if (i == conditions.length) {
				//最後の条件を通過したので、これ以上は判定できない。
				if (json == null) {
					list.add(t_obj.get(pos));
				} else {
					//json!=nullということは、更新対象である。
					//更新目的なので値をセットする。

					Object n_obj = t_obj.get(pos);
					if (n_obj == null || Tool.isPrimitive2(n_obj.getClass()) || n_obj.getClass().isEnum()) {
						n_obj = Tool.getObjectfromJSON(null, json);
					} else {
						updateFromJson(n_obj, json);
					}
					if (pos < t_obj.size()) {
						t_obj.set(pos, n_obj);
					} else if (pos == t_obj.size()) {
						//最後尾だけ追加を許す。
						t_obj.add(n_obj);
					}
				}
			} else {
				//リストもしくは配列の次の次元に移る。
				obj = resolveNext(t_obj.get(pos), i, conditions, list, json);
			}
		}
		return obj;
	}


	//JsonPathの条件節の中（[]で囲まれた文字列)の「.」を退避する。JsonPathの条件節中の「.」はルートに直接関わらないため。
	private static String esqDot(String str) {
		String t_str = str;
		ArrayList<String> t_list = new ArrayList<String>();
		Integer i = 0;

		final Pattern t_pat = Pattern.compile("\\([^\\(\\)]+\\)");
		Matcher t_m = t_pat.matcher(t_str);
		while (t_m.find()) {
			String w_str = t_m.group();
			if (w_str.contains(".")) {
				t_str = t_str.replaceFirst(Pattern.quote(w_str), "__ESCAPED_STRING__" + i.toString());

				w_str = w_str.replaceAll(Pattern.quote("."), "__ESCAPED_DOT__");
				t_list.add(w_str);
				i++;

				t_m = t_pat.matcher(t_str);;
			}
		}
		for (Integer j = 0; j < t_list.size(); j++) {
			t_str = t_str.replaceFirst("__ESCAPED_STRING__" + j.toString(), Matcher.quoteReplacement(t_list.get(j)));
		}
		return t_str;
	}

	//esqDotで退避した「.」を復元する。
	private static String restDot(String str) {
		str = str.replaceAll("__ESCAPED_DOT__", Matcher.quoteReplacement("."));
		return str;
	}



	//不等式を評価する。
	private static boolean evalIfBoolean(String exps) {
		final Pattern t_pat = Pattern.compile("^(.+)([<>]=*)(.+)$");
		Matcher t_m = t_pat.matcher(exps);
		if (t_m.find()) {
			String ex1 = t_m.group(1);
			String op = t_m.group(2);
			String ex2 = t_m.group(3);
			Integer x1 = numberByExpression(ex1);
			Integer x2 = numberByExpression(ex2);
			if (x1 != null && x2 != null) {
				if (">=".equals(op)) {
					return (x1 >= x2);
				} else if (">".equals(op)) {
					return (x1 > x2);
				} else if ("<=".equals(op)) {
					return (x1 <= x2);
				} else if ("<".equals(op)) {
					return (x1 < x2);
				} else if ("==".equals(op)) {
					return (x1.equals(x2));
				}
			}
		}
		return false;
	}

	//数字の演算式を評価する。不正ならnullを返す。
	public static Integer numberByExpression(String exps) {
		exps = exps.replaceAll("\\s", "");
		final Pattern t_pat = Pattern.compile("^(\\d+)(\\+|\\-)(.+)$");
		Matcher t_m = t_pat.matcher(exps);
		if (t_m.find()) {
			String num = t_m.group(1);
			String op = t_m.group(2);
			String nextexp = t_m.group(3);
			if ("+".equals(op)) {
				return Integer.valueOf(num) + numberByExpression(nextexp);
			} else if ("-".equals(op)) {
				return Integer.valueOf(num) - numberByExpression(nextexp);
			}
		} else if (exps.matches("^[0-9]$")) {
			return Integer.valueOf(exps);
		}
		return null;
	}

	//第二引数の@.fieldsnameを評価して、数字のみの式に戻す。
	@SuppressWarnings("rawtypes")
	private static String evalFieldsOfNumber(Object obj, String exps) {
		final Pattern t_pat = Pattern.compile("@\\.(\\w+)");
		Matcher t_m = t_pat.matcher(exps);

		String t_result = exps;
		while (t_m.find()) {
			String t_target = t_m.group();
			String f_name = t_m.group();

			if (obj.getClass().isArray() && "length".equals(f_name)) {
				t_result = Integer.toString(Array.getLength(obj));
			} else if (obj instanceof List && "length".equals(f_name)) {
				t_result = Integer.toString(((List)obj).size());
			} else {
				try {
					Object f_obj = Tool.getFieldValue(obj, f_name);
					if (f_obj != null && f_obj.toString().matches("^[0-9]+$")) {
						t_result = t_result.replaceFirst(Pattern.quote(t_target), Matcher.quoteReplacement(f_obj.toString()));
					}
				} catch (NoSuchFieldException e) {
					//何もしない。エラーになったら、次が手がかりになる。
					Tool.logIfDebug(e, "FSON_FAIL: evalFieldsOfNumber>>" + f_name + " not found in " + obj.getClass().getName());
				}
			}
		}
		return t_result;
	}

	///////////////////////////////////////////////////////
	//ClassからJsonのひな型を作る。
	public static String toDefaultJson(Class<?> c) {
		String t_result = null;
		String cname = c.getSimpleName();

		if ("String".equals(cname)) {
			t_result = "\"\"";
		} else if (Modifier.isAbstract(c.getModifiers()) || Modifier.isInterface(c.getModifiers())) {
			t_result = "(Class Name){}"; //キャスト付にする。
		} else if (Tool.isPrimitive2(c)) {
			t_result = "";
		} else if (c.isEnum()) {
			t_result = "(" + c.getName() + ")Number";
		} else if (c.isArray() || java.util.List.class.isAssignableFrom(c)) {
			t_result = "[]";
		} else if (java.util.Map.class.isAssignableFrom(c)) {
			t_result = "{}";
		} else {
			t_result = "{\n";
			Field[] f_list = c.getDeclaredFields();
			for (int i = 0; i < f_list.length; i++) {
				if (t_result.length() > 0) {
					t_result += ",\n";
				}
				t_result += "\"" + f_list[i].getName() + "\":";

				Class<?> t_c = f_list[i].getType();
				t_result += toDefaultJson(t_c);
			}
			t_result += "\n}";
		}
		return t_result;
	}


	//文字列中の($className#method($1,$2,...))を実行する。
	//※　引数の制限。文字列内といえども「))」は使用禁止。
	private static String execCodeInString(String str) {
		String t_src = str;
		if (Tool.curCase != null) {
			//実行時に解釈する。

			//引数の中に入れ子の実行可能文字列がないパターン。
			final Pattern t_pat1 = Pattern.compile("\\(\\$(\\w[\\w\\.]+)\\.([\\w]+)\\(([^\\(\\)]*)\\)\\)");
			Matcher t_m = t_pat1.matcher(t_src);
			while (t_m.find()) {
				String cname = t_m.group(1);
				String mname = t_m.group(2);
				String temp = t_m.group(3);

				String[] targs = new String[] {};

				if (Tool.existClass(cname)) {
					if (temp != null && temp.length() > 0) {
						//
						try {
							ArrayList<String> t_escs = escapeBraket(temp, "\""); //文字列をエスケープする。""の中に,がある場合を避けるため。
							targs = t_escs.get(0).split(",");
							for (int i = 0; i < targs.length; i++) {
								targs[i] = restoreBraket(targs[i], t_escs).trim();  //エスケープから回復する。
								targs[i] = targs[i].replaceFirst("^\"?(.*)\"?$", "$1"); //両側に""があったら外す。
							}

						} catch (ParseException e) {
							//失敗したらエラーメッセージを挿入する。
							t_src = t_m.replaceFirst("(ERROR:msg=" + e.getMessage() + ")");
							Tool.logIfDebug(e, "FSON_FAIL: execCodeInString>>" + str);
						}
					}
					try {

						Class<?> x_c = Tool.forName(cname);
						Method x_m = x_c.getMethod(mname, new Class<?>[]{(new String[]{}).getClass()});

						//対象はstaticメソッドに限られる。
						//Object t_arry = Array.newInstance(String[].class, 1);
						//Array.set(t_arry, 0, targs);
						Object[] t_arry = new Object[]{targs};
						Object t_ret = x_m.invoke(null, t_arry);

						if (t_ret != null) {
							//実行結果があれば埋め込む。
							t_src = t_m.replaceFirst(Matcher.quoteReplacement(t_ret.toString()));
						} else {
							//なければnullにする。
							t_src = t_m.replaceFirst("null");
						}
					} catch (NoSuchMethodException | SecurityException | ClassNotFoundException | IllegalAccessException
							| IllegalArgumentException | InvocationTargetException e) {
						//なければエラーメッセージを埋め込む。
						t_src = t_m.replaceFirst("(ERROR:msg=" + e.getMessage() + ")");
						Tool.logIfDebug(e, "FSON_FAIL: execCodeInString>>" + str);
					}
					t_m = t_pat1.matcher(t_src);
				}
			}
			//引数の中に大域変数が埋め込まれているパターン。
			final Pattern t_pat2 = Pattern.compile("\\(\\$\\.([\\w\\.]+)\\)");
			t_m = t_pat2.matcher(t_src);
			while (t_m.find()) {
				String key = t_m.group(1);
				Object t_obj = VCentral.getValue(key);
				if (t_obj != null) {
					//指定の大域変数を埋め込む。
					t_src = t_m.replaceFirst(Matcher.quoteReplacement(t_obj.toString()));
				} else {
					//なければnullにする。
					t_src = t_m.replaceFirst("null");
				}
				t_m = t_pat2.matcher(t_src);
			}
		}
		return t_src;
	}


	//enumのobjectを返す。
	private static Object getEnumByInt(Class<?> c, String i) {
		Object[] t_objs = c.getEnumConstants();
		return t_objs[Integer.valueOf(i)];
	}

	//ObjectをXML化する。
	public static String toXML(Object obj, Class<?> c, Integer depth) throws ClassNotFoundException, SecurityException,
												NoSuchMethodException, IllegalAccessException, NoSuchFieldException, NotSupportedClassException {
		if (obj == null || isLooped(obj)) {
			//isLoopedはリンクが無限ループになっているかをどうかをチェックする。
			return "";
		}
		String result = "";
		String head_str = "";
		if (o_stack.size() == 0) {
			head_str = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><root>";
		} else if (depth != null && o_stack.size() > depth) {
			return "";
		}

		if (c == null && obj != null) {
			result = toXML(obj, obj.getClass(), depth);
		} else if (c != null) {
			pushed(c);//クラスがある状態では、objが同一引数で再帰呼び出しはしないので、この位置に置く。

			try {
				String cname = c.getSimpleName();

				if (cname.equals("int") || cname.equals("Integer")) {
					if (obj != null) {
						result = Integer.toString((Integer)obj);
					}
				} else if (cname.equals("long") || cname.equals("Long")) {
					if (obj != null) {
						result = Long.toString((Long)obj);
					}
				} else if (cname.equals("boolean") || cname.equals("Boolean")) {
					if (obj != null) {
						result = Boolean.toString((Boolean)obj);
					}
				} else if (cname.equals("char") || cname.equals("Character")) {
					if (obj != null) {
						Character ch = (Character)obj;
						int ic = Character.getNumericValue(ch);
						if (ic > 0) {
							result = Character.toString((Character)obj);
						} else {
							result = "";
						}
					}
				} else if (cname.equals("float") || cname.equals("Float")) {
					if (obj != null) {
						result = Float.toString((Float)obj);
					}
				} else if (cname.equals("byte") || cname.equals("Byte")) {
					if (obj != null) {
						result = Byte.toString((Byte)obj);
					}
				} else if (cname.equals("double") || cname.equals("Double")) {
					if (obj != null) {
						result = Double.toString((Double)obj);
					}
				} else if (cname.equals("AtomicInteger")) {
					if (obj != null) {
						result = obj.toString();
					}
				} else if (cname.equals("AtomicLong")) {
					if (obj != null) {
						result = obj.toString();
					}
				} else if (cname.equals("BigDecimal")) {
					if (obj != null) {
						result = obj.toString();
					}
				} else if (cname.equals("BigInteger")) {
					if (obj != null) {
						result = obj.toString();
					}
				} else if (cname.equals("String")) {
					if (obj != null) {
						result = obj.toString();
					}
				} else if (c.isArray()) {
					Class<?> t_c = c.getComponentType();
					String xml ="";
					if (obj != null) {
						for (int i = 0; i < Array.getLength(obj); i++) {
							//xmlの要素は文字か_から始まる。
							xml += "<_" + Integer.toString(i) + " name=\"" + t_c.getName() + "\">" + toXML(Array.get(obj, i), t_c, depth) + "</_" + Integer.toString(i) + ">" ;
						}
					}
					result = xml;
				} else if (c.isEnum()) {
					if (obj != null) {
						Object[] en_list = c.getEnumConstants();
						String t_xml = null;
						for (int i = 0; i < en_list.length; i++) {
							if (obj.equals(en_list[i])) {
								t_xml = Integer.toString(i);
							}
						}
						if (t_xml != null) {
							result = t_xml;
						} else {
							//不正なenumでエラー
							throw new IllegalAccessException(c.getName() + "has not " + obj.toString() + ".");
						}
					}
				} else if (java.util.Map.class.isAssignableFrom(c)) {
					String xml = "";
					if (obj != null) {
						@SuppressWarnings("unchecked")
						Map<Object, Object> t_map = (Map<Object, Object>)obj;
						for(Entry<Object, Object> entry : t_map.entrySet()) {
							String t_key = entry.getKey().toString();
							if (t_key != null && !t_key.equals("null") && !t_key.endsWith("_class")) {
								//keyはnullであってはならない。
								//3番目の条件はFakeの属性テーブルの可能性を考慮。クラス名はここには要らない。
								String tc_name = "unknown";
								if (entry.getValue() != null) {
									tc_name = entry.getValue().getClass().getName();
								} else {
									//Fakeの属性テーブルの可能性あり。
									if (t_map.containsKey(entry.getKey() + "_class")) {
										tc_name = t_map.get(entry.getKey() + "_class").toString();
									}
								}
								if (xml.length() > 1) {
									xml += ",";
								}
								xml += "<" + t_key + " name=\"" + tc_name + "\">" + toXML(entry.getValue(), null, depth) + "</" + t_key + ">";
							}
						}
					}
					result = xml;
				} else if (java.util.List.class.isAssignableFrom(c)) {
					//List系クラスの場合
					String xml ="";
					if (obj != null) {
						@SuppressWarnings("rawtypes")
						Object[] t_array = ((java.util.List)obj).toArray();
						for (int i = 0; i < t_array.length; i++) {
							Object x_obj = t_array[i];
							String s_xml = "null";
							if (x_obj != null) {
								//xmlの要素は文字か_から始まる。
								//List系にはCastが必要。

								s_xml += "<_" + Integer.toString(i) + " name=\"" + x_obj.getClass().getName() + "\">" + toXML(x_obj, null, depth) + "</_" + x_obj.getClass().getName() + ">" ;
							}
							xml += s_xml;
						}
					}
					result = xml;
				} else if (java.util.Collection.class.isAssignableFrom(c)) {
					throw new NotSupportedClassException(c.getName() + ">>Fson cuurently not support.");
				} else if (Tool.isFake(cname)) {
					//Fakeなら$._impl._tableをJsonにする。
					ArrayList<Object> t_fakes = valueByJsonPath(obj, "$");
					if (t_fakes.size() > 0) {
						result = toXML(t_fakes.get(0), HashMap.class, depth);
					}
				} else {
					//一般的なオブジェクトの場合
					String xml = "";

					HashMap<String, String> f_map = getFields(c);//フィールド名、型名。静的なフィールドはxmlの対象外。インスタンス固有でないため。

					for(Entry<String, String> entry : f_map.entrySet()) {
						String key = entry.getKey();
						Object t_obj = null;

						Field t_f = Tool.getField(c, key);
						t_obj = Tool.getFieldValue(obj, key);
						Class<?> t_c = t_f.getType();
						if (t_c.isArray()) {
							Class<?> comp_class = t_c.getComponentType();
							xml += "<" + entry.getKey() + " name=\"" + comp_class.getName() + "[]\">";

							if (t_obj != null && Array.getLength(t_obj) > 0 && Array.get(t_obj,0) != null) {
								xml += toXML(Array.get(t_obj,0), comp_class, depth);
							}
							xml += "</" + entry.getKey() + ">";
						} else {
							xml += "<" + entry.getKey() + " name=\"" + t_c.getName() + "\">";
							if (t_obj != null) {
								xml += toXML(t_obj, t_c, depth);
							}
							xml += "</" + entry.getKey() + ">";
						}
					}
					result = xml;
				}
			} finally {
				//現在のクラスをスタックから外す
				popped(c);
			}
		}
		//xmlのお約束を補足する。
		if (head_str.length() > 0) {
			result = head_str + result + "</root>";
		}
		return result;
	}

}
