package com.yunkapay.push.mobile.parcelable; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; import com.yunkapay.push.mobile.util.Logger; import java.lang.reflect.*; import java.util.*; public abstract class GlobalParcelable<T extends GlobalParcelable> implements Parcelable { public GlobalParcelable() { // TODO Auto-generated constructor stub } public GlobalParcelable(Parcel in) { String className = in.readString(); Log.i("GlobalParcelable", "Constructor: " + ((Object) this).getClass().getSimpleName() + "; In parcel: " + className); readFromParcel(in); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(((Object) this).getClass().getName()); try { dehydrate(this, dest); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void readFromParcel(Parcel in) { try { rehydrate(this, in); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public int describeContents() { // TODO Auto-generated method stub return 0; } // writes fields of a GlobalParcelable to a parcel // does not include the first parcelled item -- the class name protected void dehydrate(GlobalParcelable model, Parcel out) throws IllegalArgumentException, IllegalAccessException { Class<?> cla = ((Object) model).getClass(); Log.i("GlobalParcelable", "dehydrating... " + cla.toString()); // get the fields Field[] fields=getFields(cla); // sort the fields so it is in deterministic order Arrays.sort(fields, compareMemberByName); // populate the fields for (Field field : fields) { field.setAccessible(true); int modifier = field.getModifiers(); Log.i("GlobalParcelable", "Field:" + field.getName() + " " + Modifier.isStatic(modifier) + " " + Modifier.isFinal(modifier)); if (field.getType().equals(int.class)) { out.writeInt(field.getInt(model)); } else if (field.getType().equals(double.class)) { out.writeDouble(field.getDouble(model)); } else if (field.getType().equals(float.class)) { out.writeFloat(field.getFloat(model)); } else if (field.getType().equals(long.class)) { out.writeLong(field.getLong(model)); } else if (field.getType().equals(String.class)) { out.writeString((String) field.get(model)); } else if (field.getType().equals(boolean.class)) { out.writeByte(field.getBoolean(model) ? (byte) 1 : (byte) 0); } else if (field.getType().equals(Date.class)) { Date date = (Date) field.get(model); if (date != null) { out.writeLong(date.getTime()); } else { out.writeLong(0); } } else if (GlobalParcelable.class.isAssignableFrom(field.getType())) { // why did this happen? Log.e("GlobalParcelable", "GlobalParcelable F*ck up: " + " (" + field.getType().toString() + ")"); out.writeParcelable((GlobalParcelable) field.get(model), 0); } else { // wtf Log.e("GlobalParcelable", "Could not write field to parcel: " + " (" + field.getType().toString() + ")"); } } } protected static Field[] getFields(Class<?> cla) { List<Field> fieldList = new ArrayList<Field>(); do { Logger.d("Class "+cla.toString()); Field[] fields = cla.getDeclaredFields(); for (Field f : fields) { int modifier = f.getModifiers(); if (Modifier.isStatic(modifier) && Modifier.isFinal(modifier)) { Logger.d("final static value "+f.getName()); } else { fieldList.add(f); } } cla = cla.getSuperclass(); } while (cla != null && !GlobalParcelable.class.equals(cla)); return fieldList.toArray(new Field[fieldList.size()]); } // reads the parcelled items and put them into this object's fields // must be run after getting the first parcelled item -- the class name protected static void rehydrate(GlobalParcelable model, Parcel in) throws IllegalArgumentException, IllegalAccessException { Class<?> cla = ((Object) model).getClass(); Log.i("GlobalParcelable", "rehydrating... " + cla.toString()); // get the fields Field[] fields =getFields(cla); // sort the fields so it is in deterministic order Arrays.sort(fields, compareMemberByName); // populate the fields for (Field field : fields) { field.setAccessible(true); if (field.getType().equals(int.class)) { field.set(model, in.readInt()); } else if (field.getType().equals(double.class)) { field.set(model, in.readDouble()); } else if (field.getType().equals(float.class)) { field.set(model, in.readFloat()); } else if (field.getType().equals(long.class)) { field.set(model, in.readLong()); } else if (field.getType().equals(String.class)) { field.set(model, in.readString()); } else if (field.getType().equals(boolean.class)) { field.set(model, in.readByte() == 1); } else if (field.getType().equals(Date.class)) { Date date = new Date(in.readLong()); field.set(model, date); } else if (GlobalParcelable.class.isAssignableFrom(field.getType())) { Log.e("GlobalParcelable", "read GlobalParcelable: " + " (" + field.getType().toString() + ")"); field.set(model, in.readParcelable(field.getType().getClassLoader())); } else { // wtf Log.e("GlobalParcelable", "Could not read field from parcel: " + field.getName() + " (" + field.getType().toString() + ")"); } } } /* * Comparator object for Members, Fields, and Methods */ private static Comparator<Field> compareMemberByName = new CompareMemberByName(); private static class CompareMemberByName implements Comparator { public int compare(Object o1, Object o2) { String s1 = ((Member) o1).getName(); String s2 = ((Member) o2).getName(); if (o1 instanceof Method) { s1 += getSignature((Method) o1); s2 += getSignature((Method) o2); } else if (o1 instanceof Constructor) { s1 += getSignature((Constructor) o1); s2 += getSignature((Constructor) o2); } return s1.compareTo(s2); } } /** * Compute the JVM signature for the class. */ private static String getSignature(Class clazz) { String type = null; if (clazz.isArray()) { Class cl = clazz; int dimensions = 0; while (cl.isArray()) { dimensions++; cl = cl.getComponentType(); } StringBuffer sb = new StringBuffer(); for (int i = 0; i < dimensions; i++) { sb.append("["); } sb.append(getSignature(cl)); type = sb.toString(); } else if (clazz.isPrimitive()) { if (clazz == Integer.TYPE) { type = "I"; } else if (clazz == Byte.TYPE) { type = "B"; } else if (clazz == Long.TYPE) { type = "J"; } else if (clazz == Float.TYPE) { type = "F"; } else if (clazz == Double.TYPE) { type = "D"; } else if (clazz == Short.TYPE) { type = "S"; } else if (clazz == Character.TYPE) { type = "C"; } else if (clazz == Boolean.TYPE) { type = "Z"; } else if (clazz == Void.TYPE) { type = "V"; } } else { type = "L" + clazz.getName().replace('.', '/') + ";"; } return type; } /* * Compute the JVM method descriptor for the method. */ private static String getSignature(Method meth) { StringBuffer sb = new StringBuffer(); sb.append("("); Class[] params = meth.getParameterTypes(); // avoid clone for (int j = 0; j < params.length; j++) { sb.append(getSignature(params[j])); } sb.append(")"); sb.append(getSignature(meth.getReturnType())); return sb.toString(); } /* * Compute the JVM constructor descriptor for the constructor. */ private static String getSignature(Constructor cons) { StringBuffer sb = new StringBuffer(); sb.append("("); Class[] params = cons.getParameterTypes(); // avoid clone for (int j = 0; j < params.length; j++) { sb.append(getSignature(params[j])); } sb.append(")V"); return sb.toString(); } }
package com.yunkapay.push.mobile.notification; import android.os.Parcel; import android.os.Parcelable; import com.yunkapay.push.mobile.parcelable.GlobalParcelable; import com.yunkapay.push.mobile.util.Logger; import org.json.JSONObject; /** * Created with IntelliJ IDEA. * User: zac * Date: 12/2/13 * Time: 2:26 PM * To change this template use File | Settings | File Templates. */ public class XJNotification extends GlobalParcelable { public static final String ELEMENT_NAME = "notification"; public static final String NAMESPACE = "pubsub:message:notification"; public static final String NOTIFICATION_NODE = "node"; public static final String NOTIFICATION_ID = "id"; public static final String NOTIFICATION_TITLE = "title"; public static final String NOTIFICATION_CONTENT = "content"; public static final String NOTIFICATION_TYPE = "type"; public static final String NOTIFICATION_IMAGE_URL = "image_url"; public static final String NOTIFICATION_LINK = "link"; public static final String NOTIFICATION_TIME = "time"; public static final String NOTIFICATION_TIME_TO_LIVE = "time_to_live"; public String mNotificationID; public String mNode; public String mTitle; public String mContent; public long mTime; public int mTimeToLive; public XJNotification(JSONObject jsonObject) { } public XJNotification() { super(); } public static final Parcelable.Creator<XJNotification> CREATOR = new Parcelable.Creator<XJNotification>() { public XJNotification createFromParcel(Parcel in) { // get class from first parcelled item Class<?> parceledClass; try { parceledClass = Class.forName(in.readString()); Logger.i("Creator: " + parceledClass.getSimpleName()); // create instance of that class XJNotification model = (XJNotification) parceledClass.newInstance(); rehydrate(model, in); return model; } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } public XJNotification[] newArray(int size) { return new XJNotification[size]; } }; public String getNotificationID() { return this.mNotificationID; } public String getNode() { return this.mNode; } public String getTitle() { return this.mTitle; } public String getContent() { return this.mContent; } public static String getElementName() { return ELEMENT_NAME; } public long getTime() { return this.mTime; } public int getTimeToLive() { return this.mTimeToLive; } public void setNotificationID(String notificationID) { this.mNotificationID = notificationID; } public void setNode(String node) { this.mNode = node; } public void setTitle(String title) { this.mTitle = title; } public void setContent(String content) { this.mContent = content; } public void setTime(long time) { this.mTime = time; } public void setTimeToLive(int timeToLive) { this.mTimeToLive = timeToLive; } public NotificationType getType() { return NotificationType.UNKNOWN; } }