All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.dubbo.common.json.GenericJSONConverter Maven / Gradle / Ivy

/*
 * Copyright 1999-2011 Alibaba Group.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.dubbo.common.json;

import java.io.IOException;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import net.jahhan.com.alibaba.dubbo.common.bytecode.Wrapper;
import net.jahhan.com.alibaba.dubbo.common.io.Bytes;

public class GenericJSONConverter implements JSONConverter {
	private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

	protected interface Encoder {
		void encode(Object obj, JSONWriter jb) throws IOException;
	}

	protected interface Decoder {
		Object decode(Object jv) throws IOException;
	}

	private static final Map, Encoder> GlobalEncoderMap = new HashMap, Encoder>();

	private static final Map, Decoder> GlobalDecoderMap = new HashMap, Decoder>();

	@SuppressWarnings("unchecked")
	public void writeValue(Object obj, JSONWriter jb, boolean writeClass) throws IOException {
		if (obj == null) {
			jb.valueNull();
			return;
		}
		Class c = obj.getClass();
		Encoder encoder = GlobalEncoderMap.get(c);

		if (encoder != null) {
			encoder.encode(obj, jb);
		} else if (obj instanceof JSONNode) {
			((JSONNode) obj).writeJSON(this, jb, writeClass);
		} else if (c.isEnum()) {
			jb.valueString(((Enum) obj).name());
		} else if (c.isArray()) {
			int len = Array.getLength(obj);
			jb.arrayBegin();
			for (int i = 0; i < len; i++)
				writeValue(Array.get(obj, i), jb, writeClass);
			jb.arrayEnd();
		} else if (Map.class.isAssignableFrom(c)) {
			Object key, value;
			jb.objectBegin();
			for (Map.Entry entry : ((Map) obj).entrySet()) {
				key = entry.getKey();
				if (key == null)
					continue;
				jb.objectItem(key.toString());

				value = entry.getValue();
				if (value == null)
					jb.valueNull();
				else
					writeValue(value, jb, writeClass);
			}
			jb.objectEnd();
		} else if (Collection.class.isAssignableFrom(c)) {
			jb.arrayBegin();
			for (Object item : (Collection) obj) {
				if (item == null)
					jb.valueNull();
				else
					writeValue(item, jb, writeClass);
			}
			jb.arrayEnd();
		} else {
			jb.objectBegin();

			Wrapper w = Wrapper.getWrapper(c);
			String pns[] = w.getPropertyNames();

			for (String pn : pns) {
				if ((obj instanceof Throwable) && ("localizedMessage".equals(pn) || "cause".equals(pn)
						|| "suppressed".equals(pn) || "stackTrace".equals(pn))) {
					continue;
				}

				jb.objectItem(pn);

				Object value = w.getPropertyValue(obj, pn);
				if (value == null || value == obj)
					jb.valueNull();
				else
					writeValue(value, jb, writeClass);
			}
			if (writeClass) {
				jb.objectItem(JSONVisitor.CLASS_PROPERTY);
				writeValue(obj.getClass().getName(), jb, writeClass);
			}
			jb.objectEnd();
		}
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Object readValue(Class c, Object jv) throws IOException {
		if (jv == null) {
			return null;
		}
		Decoder decoder = GlobalDecoderMap.get(c);
		if (decoder != null) {
			return decoder.decode(jv);
		}
		if (c.isEnum()) {
			return Enum.valueOf((Class) c, String.valueOf(jv));
		}
		return jv;
	}

	static {
		// init encoder map.
		Encoder e = new Encoder() {
			public void encode(Object obj, JSONWriter jb) throws IOException {
				jb.valueBoolean((Boolean) obj);
			}
		};
		GlobalEncoderMap.put(boolean.class, e);
		GlobalEncoderMap.put(Boolean.class, e);

		e = new Encoder() {
			public void encode(Object obj, JSONWriter jb) throws IOException {
				jb.valueInt(((Number) obj).intValue());
			}
		};
		GlobalEncoderMap.put(int.class, e);
		GlobalEncoderMap.put(Integer.class, e);
		GlobalEncoderMap.put(short.class, e);
		GlobalEncoderMap.put(Short.class, e);
		GlobalEncoderMap.put(byte.class, e);
		GlobalEncoderMap.put(Byte.class, e);
		GlobalEncoderMap.put(AtomicInteger.class, e);

		e = new Encoder() {
			public void encode(Object obj, JSONWriter jb) throws IOException {
				jb.valueString(Character.toString((Character) obj));
			}
		};
		GlobalEncoderMap.put(char.class, e);
		GlobalEncoderMap.put(Character.class, e);

		e = new Encoder() {
			public void encode(Object obj, JSONWriter jb) throws IOException {
				jb.valueLong(((Number) obj).longValue());
			}
		};
		GlobalEncoderMap.put(long.class, e);
		GlobalEncoderMap.put(Long.class, e);
		GlobalEncoderMap.put(AtomicLong.class, e);
		GlobalEncoderMap.put(BigInteger.class, e);

		e = new Encoder() {
			public void encode(Object obj, JSONWriter jb) throws IOException {
				jb.valueFloat(((Number) obj).floatValue());
			}
		};
		GlobalEncoderMap.put(float.class, e);
		GlobalEncoderMap.put(Float.class, e);

		e = new Encoder() {
			public void encode(Object obj, JSONWriter jb) throws IOException {
				jb.valueDouble(((Number) obj).doubleValue());
			}
		};
		GlobalEncoderMap.put(double.class, e);
		GlobalEncoderMap.put(Double.class, e);
		GlobalEncoderMap.put(BigDecimal.class, e);

		e = new Encoder() {
			public void encode(Object obj, JSONWriter jb) throws IOException {
				jb.valueString(obj.toString());
			}
		};
		GlobalEncoderMap.put(String.class, e);
		GlobalEncoderMap.put(StringBuilder.class, e);
		GlobalEncoderMap.put(StringBuffer.class, e);

		e = new Encoder() {
			public void encode(Object obj, JSONWriter jb) throws IOException {
				jb.valueString(Bytes.bytes2base64((byte[]) obj));
			}
		};
		GlobalEncoderMap.put(byte[].class, e);

		e = new Encoder() {
			public void encode(Object obj, JSONWriter jb) throws IOException {
				jb.valueString(new SimpleDateFormat(DATE_FORMAT).format((Date) obj));
			}
		};
		GlobalEncoderMap.put(Date.class, e);

		// init decoder map.
		Decoder d = new Decoder() {
			public Object decode(Object jv) {
				return jv.toString();
			}
		};
		GlobalDecoderMap.put(String.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Boolean)
					return ((Boolean) jv).booleanValue();
				return false;
			}
		};
		GlobalDecoderMap.put(boolean.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Boolean)
					return (Boolean) jv;
				return (Boolean) null;
			}
		};
		GlobalDecoderMap.put(Boolean.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof String && ((String) jv).length() > 0)
					return ((String) jv).charAt(0);
				return (char) 0;
			}
		};
		GlobalDecoderMap.put(char.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof String && ((String) jv).length() > 0)
					return ((String) jv).charAt(0);
				return (Character) null;
			}
		};
		GlobalDecoderMap.put(Character.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return ((Number) jv).intValue();
				return 0;
			}
		};
		GlobalDecoderMap.put(int.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return Integer.valueOf(((Number) jv).intValue());
				return (Integer) null;
			}
		};
		GlobalDecoderMap.put(Integer.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return ((Number) jv).shortValue();
				return (short) 0;
			}
		};
		GlobalDecoderMap.put(short.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return Short.valueOf(((Number) jv).shortValue());
				return (Short) null;
			}
		};
		GlobalDecoderMap.put(Short.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return ((Number) jv).longValue();
				return (long) 0;
			}
		};
		GlobalDecoderMap.put(long.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return Long.valueOf(((Number) jv).longValue());
				return (Long) null;
			}
		};
		GlobalDecoderMap.put(Long.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return ((Number) jv).floatValue();
				return (float) 0;
			}
		};
		GlobalDecoderMap.put(float.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return new Float(((Number) jv).floatValue());
				return (Float) null;
			}
		};
		GlobalDecoderMap.put(Float.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return ((Number) jv).doubleValue();
				return (double) 0;
			}
		};
		GlobalDecoderMap.put(double.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return new Double(((Number) jv).doubleValue());
				return (Double) null;
			}
		};
		GlobalDecoderMap.put(Double.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return ((Number) jv).byteValue();
				return (byte) 0;
			}
		};
		GlobalDecoderMap.put(byte.class, d);

		d = new Decoder() {
			public Object decode(Object jv) {
				if (jv instanceof Number)
					return Byte.valueOf(((Number) jv).byteValue());
				return (Byte) null;
			}
		};
		GlobalDecoderMap.put(Byte.class, d);

		d = new Decoder() {
			public Object decode(Object jv) throws IOException {
				if (jv instanceof String)
					return Bytes.base642bytes((String) jv);
				return (byte[]) null;
			}
		};
		GlobalDecoderMap.put(byte[].class, d);

		d = new Decoder() {
			public Object decode(Object jv) throws IOException {
				return new StringBuilder(jv.toString());
			}
		};
		GlobalDecoderMap.put(StringBuilder.class, d);

		d = new Decoder() {
			public Object decode(Object jv) throws IOException {
				return new StringBuffer(jv.toString());
			}
		};
		GlobalDecoderMap.put(StringBuffer.class, d);

		d = new Decoder() {
			public Object decode(Object jv) throws IOException {
				if (jv instanceof Number)
					return BigInteger.valueOf(((Number) jv).longValue());
				return (BigInteger) null;
			}
		};
		GlobalDecoderMap.put(BigInteger.class, d);

		d = new Decoder() {
			public Object decode(Object jv) throws IOException {
				if (jv instanceof Number)
					return BigDecimal.valueOf(((Number) jv).doubleValue());
				return (BigDecimal) null;
			}
		};
		GlobalDecoderMap.put(BigDecimal.class, d);

		d = new Decoder() {
			public Object decode(Object jv) throws IOException {
				if (jv instanceof Number)
					return new AtomicInteger(((Number) jv).intValue());
				return (AtomicInteger) null;
			}
		};
		GlobalDecoderMap.put(AtomicInteger.class, d);

		d = new Decoder() {
			public Object decode(Object jv) throws IOException {
				if (jv instanceof Number)
					return new AtomicLong(((Number) jv).longValue());
				return (AtomicLong) null;
			}
		};
		GlobalDecoderMap.put(AtomicLong.class, d);

		d = new Decoder() {
			public Object decode(Object jv) throws IOException {
				if (jv instanceof String) {
					try {
						return new SimpleDateFormat(DATE_FORMAT).parse((String) jv);
					} catch (ParseException e) {
						throw new IllegalArgumentException(e.getMessage(), e);
					}
				}
				if (jv instanceof Number)
					return new Date(((Number) jv).longValue());
				return (Date) null;
			}
		};
		GlobalDecoderMap.put(Date.class, d);
	}
}