package jp.sourceforge.reflex;
import java.io.Reader;
import java.io.Writer;
public interface EntityMapper {
// BeanからJSONへのシリアライズ(マーシャル)メソッド
public void toJSON(Object entity, Writer writer);
public String toJSON(Object entity);
// JSONからBeanへのデシリアライズ(アンマーシャル)メソッド
public Object fromJSON(String json) throws JSONException;
public Object fromJSON(Reader json) throws JSONException;
}
package jp.sourceforge.reflex.core;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.List;
import jp.sourceforge.reflex.IResourceMapper;
/**
* JSONSerializerクラス
*
* @author Takezaki
*
*/
public class JSONSerializer implements IResourceMapper {
public String Q = "\""; // Quote (シングルクォートにしたい場合はここを変更)
/**
* @param entity
* Object @return writer.toString();
*/
public String toJSON(Object entity) {
Writer writer = new StringWriter();
marshal(entity, writer);
return writer.toString();
}
/**
* @param entity
* Object
* @param writer
* Writer
*/
public void toJSON(Object entity, Writer writer) {
marshal(entity, writer);
}
public Object fromJSON(String json) {
// please use ResourceMapper
throw new UnsupportedOperationException();
}
public Object fromJSON(Reader json) {
// please use ResourceMapper
throw new UnsupportedOperationException();
}
/**
* @param xml
* String
* @return nothing nothing
*/
public Object fromXML(String xml) {
throw new UnsupportedOperationException();
}
/**
* @param xml
* Reader
* @return nothing nothing
*/
public Object fromXML(Reader xml) {
throw new UnsupportedOperationException();
}
/**
* @param entity
*
* @return nothing nothing
*/
public String toXML(Object entity) {
throw new UnsupportedOperationException();
}
/**
* @param entity
* Object
* @param writer
* Writer
*/
public void toXML(Object entity, Writer writer) {
throw new UnsupportedOperationException();
}
/**
* @param source
* Object
* @param out
* Writer marshal
*/
public void marshal(Object source, Writer out) {
try {
// out.append('{');
out.write(new char[] { '{' });
JSONContext context = new JSONContext(out, this.Q);
context.push(context.HASH);
marshal(context, source);
// out.append('}');
out.write(new char[] { '}' });
out.flush();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* @param field
*
* @return boolean
*/
private boolean isList(Field field) {
if (Modifier.isFinal(field.getModifiers()))
return false;
return (field.getType().getName().equals("java.util.List"));
}
/**
* @param field
* Field
* @return boolean
*/
private boolean isString(Field field) {
if (Modifier.isFinal(field.getModifiers()))
return false;
return (field.getType().getName().equals("java.lang.String"));
}
/**
* @param field
* Field
* @return boolean
*/
private boolean isInt(Field field) {
if (Modifier.isFinal(field.getModifiers()))
return false;
return (field.getType().getName().equals("int") || field.getType().getName().equals("java.lang.Integer"));
}
/**
* @param field
* Field
* @return boolean
*/
private boolean isLong(Field field) {
if (Modifier.isFinal(field.getModifiers()))
return false;
return (field.getType().getName().equals("long") || field.getType().getName().equals("java.lang.Long"));
}
/**
* @param field
* Field
* @return boolean
*/
private boolean isFloat(Field field) {
if (Modifier.isFinal(field.getModifiers()))
return false;
return (field.getType().getName().equals("float") || field.getType().getName().equals("java.lang.Float"));
}
/**
* @param field
* Field
* @return boolean
*/
private boolean isDouble(Field field) {
if (Modifier.isFinal(field.getModifiers()))
return false;
return (field.getType().getName().equals("double") || field.getType().getName().equals("java.lang.Double"));
}
/**
* @param field
* Field
* @return boolean
*/
private boolean isDate(Field field) {
if (Modifier.isFinal(field.getModifiers()))
return false;
return (field.getType().getName().equals("java.util.Date"));
}
/**
* @param field
* Field
* @return boolean
*/
private boolean isRealClass(Field field) {
if (Modifier.isFinal(field.getModifiers()))
return false;
String validname = field.getType().getName();
Object obj;
try {
obj = Class.forName(validname).newInstance();
return (obj != null);
} catch (Exception e) {
}
return false;
}
/**
* @param context
* JSONContext
* @param source
* Object
* @throws IOException
* exception
* @throws IllegalArgumentException
* exception
* @throws IllegalAccessException
* exception
*/
public void marshal(JSONContext context, Object source) throws IOException,
IllegalArgumentException, IllegalAccessException {
this.marshal(context, source, false);
}
/**
* @param context
* JSONContext
* @param source
* Object
* @param flgArray
* 配列かどうか
* @throws IOException
* exception
* @throws IllegalArgumentException
* exception
* @throws IllegalAccessException
* exception
*/
public void marshal(JSONContext context, Object source, boolean flgArray) throws IOException,
IllegalArgumentException, IllegalAccessException {
RXUtil rxUtil = new RXUtil();
int mode;
Field[] fields = source.getClass().getFields();
context.printClassName(source);
context.pushout();
for (int fn = 0; fn < fields.length; fn++) {
if (fields[fn].get(source) == null)
continue;
if (isList(fields[fn])) {
List list = (List) fields[fn].get(source);
boolean isArray = false;
int arrayCol = 0;
if (list != null) {
// 配列かどうかのチェック
if (list.size() > 0) {
Object objTmp = list.get(0);
Field[] fldTmp = objTmp.getClass().getFields();
for (int t = 0; t < fldTmp.length; t++) {
if ("_$$col".equals(fldTmp[t].getName())) {
// 配列
isArray = true;
arrayCol = ((Integer) fldTmp[t].get(objTmp))
.intValue();
}
}
}
for (int ln = 0; ln < list.size(); ln++) {
if (list.get(ln) instanceof String) {
context.outcomma();
context.outprint(this.Q + list.get(ln) + this.Q);
} else {
context.outcomma();
if ((list.size() > 0)) {
if (isArray) {
if (ln > 0) {
if (ln == list.size() - 1) {
if (arrayCol == 0) {
mode = context.ARRAY2E0;
} else if (ln % arrayCol == 0) {
mode = context.ARRAY2CE;
} else {
mode = context.ARRAY2E;
}
} else {
if (arrayCol == 0) {
mode = context.ARRAY2;
} else if (arrayCol == 1) {
mode = context.ARRAY2CSE;
} else if (ln % arrayCol == 0) {
mode = context.ARRAY2SC;
} else if (ln % arrayCol == arrayCol - 1) {
mode = context.ARRAY2EC;
} else {
mode = context.ARRAY2;
}
}
} else {
if (list.size() == 1) {
if (arrayCol == 0) {
mode = context.ARRAY2SE0;
} else {
mode = context.ARRAY2SE;
}
} else if (arrayCol == 0) {
mode = context.ARRAY2S0;
} else if (arrayCol == 1) {
mode = context.ARRAY2CS;
} else {
mode = context.ARRAY2S;
}
}
} else {
if (ln > 0) {
if (ln == list.size() - 1) {
mode = context.ARRAYE;
} else {
mode = context.ARRAY;
}
} else {
if (list.size() == 1) {
mode = context.ARRAYSE;
} else {
mode = context.ARRAYS;
}
}
}
} else {
mode = context.HASH;
}
context.push(mode);
this.marshal(context, list.get(ln), isArray);
}
}
}
} else if (isString(fields[fn])) {
String string = (String) fields[fn].get(source);
context.outcomma();
if (flgArray) {
if ("_$$text".equals(fields[fn].getName())) {
context.outprint(this.Q + string + this.Q);
} else {
context.out(fields[fn].getName(), string);
}
} else {
context.out(fields[fn].getName(), string);
}
} else if (isInt(fields[fn])) {
int i = ((Integer) fields[fn].get(source)).intValue();
context.outcomma();
context.out(fields[fn].getName(), i);
} else if (isLong(fields[fn])) {
long i = ((Long) fields[fn].get(source)).longValue();
context.outcomma();
context.out(fields[fn].getName(), i);
} else if (isFloat(fields[fn])) {
float i = ((Float) fields[fn].get(source)).floatValue();
context.outcomma();
context.out(fields[fn].getName(), i);
} else if (isDouble(fields[fn])) {
double i = ((Double) fields[fn].get(source)).doubleValue();
context.outcomma();
context.out(fields[fn].getName(), i);
} else if (rxUtil.isText(fields[fn].getType())) {
String textStr = rxUtil.getTextValue(fields[fn].get(source));
context.outcomma();
context.out(fields[fn].getName(), textStr);
} else if (isDate(fields[fn])) {
Date date = (Date) fields[fn].get(source);
String string = context.dateformat(date);
context.outcomma();
context.out(fields[fn].getName(), string);
} else if (isRealClass(fields[fn])) {
Object child = fields[fn].get(source);
if (child != null) {
mode = context.HASH;
context.push(mode);
context.outcomma();
this.marshal(context, child);
}
}
}
context.popout();
}
}
package jp.sourceforge.reflex.core;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.EmptyStackException;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Takezaki
*
*/
public class JSONContext {
/**
* bit1 is on
*/
public final int STARTMARK = 0x02;
/**
* bit2 is on
*/
public final int ENDMARK = 0x04;
/**
* bit0 is on
*/
public final int HASKEY = 0x01;
/**
* bit0 is off
*/
public final int ARRAY = 0; // [
/**
* bit0 is on (it means 'has key')
*/
public final int HASH = 1; // {
/**
* bit1 is on (it also has a key)
*/
public final int ARRAYS = 3;
/**
* bit2 is on
*/
public final int ARRAYE = 4;
/**
* bit0,1,2 is on(it also has a key)
*/
public final int ARRAYSE = 7;
/**
* bit0 is off (Two-dimensional array)
*/
public final int ARRAY2 = 96;
/**
* bit1 is on (it also has a key) (Two-dimensional array)
*/
public final int ARRAY2S = 107;
/**
* bit0,1,2 is on(it also has a key) (Two-dimensional array)
*/
public final int ARRAY2SE = 103;
/**
* bit0,1,2 is on(it also has a key) (One-dimensional array)
*/
public final int ARRAY2SE0 = 111;
/**
* bit0,1,2 is on(it also has a key) (Two-dimensional array)
*/
public final int ARRAY2CS = 119;
/**
* bit1 is on (it also has a key) (One-dimensional array)
*/
public final int ARRAY2S0 = 115;
/**
* bit1,2 is on (Two-dimensional array)
*/
public final int ARRAY2CE = 102;
/**
* bit1,2 is on bit1,2 is on (Two-dimensional array)
*/
public final int ARRAY2CSE = 110;
/**
* bit1 is on (Two-dimensional array)
*/
public final int ARRAY2SC = 106;
/**
* bit2 is on (Two-dimensional array)
*/
public final int ARRAY2E = 108;
/**
* bit2 is on (Two-dimensional array)
*/
public final int ARRAY2EC = 116;
/**
* bit2 is on (One-dimensional array)
*/
public final int ARRAY2E0 = 124;
/**
* separator = { "[", "]", "{", "}" }; String
*/
private final String[] separator = { "[", "]", "{", "}" };
/**
* stack = new Stack(); Stack
*/
private Stack stack = new Stack();
/**
* out; Writer
*/
private Writer out;
/**
* lastout; String
*/
private String lastout;
// Date/Time ISO8601 TIME ZONE FORMAT 2006-02-10T10:00Z.
// for use: String string = XX.isoformat.format(date);
private SimpleDateFormat isoformat = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZ");
/**
* @return int
*/
public int mode() {
try {
return ((Integer) this.stack.peek()).intValue();
} catch (EmptyStackException e) {
return -1;
}
}
/**
* Quoate
*
*/
public String Q;
/**
* @param out
* Write
*/
public JSONContext(Writer out, String quate) {
this.out = out;
this.Q = quate;
}
/**
* @return String
*/
public String getLastout() {
return lastout;
}
/**
* @return boolean
*/
public boolean hasKey() {
return (this.mode() & HASKEY) > 0;
}
/**
* @param value
* int
* @return String
*/
public String getSeparator(int value) {
return separator[(value & 0x01) * 2 + 1];
}
/**
* @return boolean
*/
public boolean isHash() {
return (this.mode() & 0x01) == 1;
}
/**
* @param mode
* int
*/
public void push(int mode) {
this.stack.push(new Integer(mode));
}
/**
* @throws IOException
* pushout
*/
public void pushout() throws IOException {
if ((this.mode() & STARTMARK) > 0)
this.outprint(separator[ARRAY]);
if (this.mode() == ARRAY2S || this.mode() == ARRAY2SE
|| this.mode() == ARRAY2CS)
this.outprint(separator[ARRAY]);
if (this.mode() < ARRAY2)
this.outprint(separator[HASH * 2]);
}
/**
* @throws IOException
* popout
*/
public void popout() throws IOException {
int lastmode = ((Integer) this.stack.pop()).intValue();
if (lastmode < ARRAY2)
this.outprint(separator[HASH * 2 + 1]);
if ((lastmode & ENDMARK) > 0)
this.outprint(separator[ARRAY + 1]);
if (lastmode == ARRAY2E || lastmode == ARRAY2CE || lastmode == ARRAY2SE)
this.outprint(separator[ARRAY + 1]);
}
/**
* @param source
* Object
* @throws IOException
* printClassName
*/
public void printClassName(Object source) throws IOException {
if (hasKey()) {
String classname = fld2node(source.getClass().getName());
// .toLowerCase());
classname = classname.substring(classname.lastIndexOf(".") + 1);
classname = classname.substring(0, 1).toLowerCase()
+ classname.substring(1);
this.outprint(this.Q + classname + this.Q + " : ");
}
}
/**
* @param value
* Object
* @throws IOException
* exception
*/
private void outprint(Object value) throws IOException {
lastout = "" + value;
out.write("" + value);
}
/**
* @throws IOException
* exception outcomma
*/
public void outcomma() throws IOException {
// if (!lastout.equals("[") && !lastout.equals("{"))
if (!lastout.equals("[") && !lastout.equals("{")
&& !lastout.equals(","))
this.outprint(",");
}
/**
* @param key
* String
* @param value
* String
* @throws IOException
* exception
*/
public void out(String key, String value) throws IOException {
if (value != null) {
this.outprint(this.Q + fld2node(key) + this.Q + " : " + this.Q
+ escape(value) + this.Q);
}
}
/**
* @param key
* String
* @param value
* String
* @throws IOException
* exception
*/
public void out(String value) throws IOException {
if (value != null) {
this.outprint(this.Q + escape(value) + this.Q);
}
}
/**
* @param key
* String
* @param value
* int
* @throws IOException
* exception
*/
public void out(String key, int value) throws IOException {
this.outprint(this.Q + fld2node(key) + this.Q + " : " + value);
}
/**
* @param key
* String
* @param value
* long
* @throws IOException
* exception
*/
public void out(String key, long value) throws IOException {
this.outprint(this.Q + fld2node(key) + this.Q + " : " + value);
}
/**
* @param key
* String
* @param value
* float
* @throws IOException
* exception
*/
public void out(String key, float value) throws IOException {
this.outprint(this.Q + fld2node(key) + this.Q + " : " + value);
}
/**
* @param key
* String
* @param value
* double
* @throws IOException
* exception
*/
public void out(String key, double value) throws IOException {
this.outprint(this.Q + fld2node(key) + this.Q + " : " + value);
}
/**
* xorPlural() {
*/
public void xorPlural() {
int mode = ((Integer) this.stack.pop()).intValue();
mode = mode ^ 0x2;
this.stack.push(new Integer(mode));
}
private static final String[] CNTLCHRS = {
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007",
"\\b", "\\t", "\\n", "\\u000B", "\\f","\\r", "\\u000E", "\\u000F",
"\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017",
"\\u0018", "\\u0019", "\\u001A", "\\u001B", "\\u001C", "\\u001D", "\\u001E", "\\u001F"
};
private String escape(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '"':
sb.append("\\\"");
break;
case '\'':
sb.append("\\'");
break;
case '\\':
sb.append("\\\\");
break;
case '\u007F':
sb.append("\\u007F");
break;
case '<':
sb.append("\\u003C");
break;
case '>':
sb.append("\\u003E");
break;
case '\u2028':
sb.append("\\u2028");
break;
case '\u2029':
sb.append("\\u2029");
break;
default:
if (c < CNTLCHRS.length) {
sb.append(CNTLCHRS[c]);
} else {
sb.append(c);
}
}
}
return sb.toString();
}
/**
* @param date
* Date
* @return String
*/
public String dateformat(Date date) {
return isoformat.format(date);
}
/**
* @param fld
* String
* @return String
*/
public String fld2node(String fld) {
String node = fld.replace("$", "___");
return node;
}
// for Java 1.4 users
/**
* @param org
* String
* @param src
* String
* @param tgt
* String
* @return String
*/
public String replace(String org, String src, String tgt) {
if (org == null)
return null;
Pattern pattern = Pattern.compile(src);
Matcher matcher = pattern.matcher(org);
return matcher.replaceAll(tgt);
}
}