| /*
|
| * 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 com.alibaba.dubbo.common.bytecode.Wrapper; |
| import 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<Class<?>, Encoder> GlobalEncoderMap = new HashMap<Class<?>, Encoder>(); |
| |
| private static final Map<Class<?>, Decoder> GlobalDecoderMap = new HashMap<Class<?>, 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<Object, Object> entry : ((Map<Object, Object>)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<Object>)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) |
| || "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<Enum>)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); |
| } |
| } |