Java tutorial
/* * Copyright 2007 Christian Grobmeier * * 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 de.grobmeier.jjson.convert; import de.grobmeier.jjson.JSONException; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringEscapeUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * */ public class JSONAnnotationEncoder { // Key signs // TODO: use already defined Openener/Closer Enums from basic decoder private static final String QUOTE = "\""; private static final String PRIMITIVE_BOOLEAN = "boolean"; private static final String ARRAY_RIGHT = "]"; private static final String ARRAY_LEFT = "["; private static final String BRACKET_RIGHT = "}"; private static final String COLON = ":"; private static final String COMMA = ","; private static final String EMTPY_STRING = ""; private static final String BRACKET_LEFT = "{"; private final String CARRIAGE_RETURN = new String(new char[] { '\\', 'r' }); private final String LINE_FEED = new String(new char[] { '\\', '\\', 'n' }); /** Default format for dates */ private final static SimpleDateFormat DEFAULT_FORMAT = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); private Map<String, SimpleDateFormat> formatterPool = new HashMap<String, SimpleDateFormat>(); // Special values private final static String NULL = "null"; public String encode(Object result) throws JSONException { StringBuilder builder = new StringBuilder(); encode(result, builder, null); return builder.toString(); } /** * @param builder * @param result * @throws JSONException */ @SuppressWarnings("unchecked") public void encode(Object result, StringBuilder builder, JSON annotation) throws JSONException { if (result == null) { builder.append(NULL); } else if (result.getClass().isAssignableFrom(String.class)) { encodeString(((String) result), builder, annotation); } else if (result.getClass().isAssignableFrom(Integer.class)) { encodeInteger((Integer) result, builder); } else if (result.getClass().isAssignableFrom(Long.class)) { encodeLong((Long) result, builder); } else if (result.getClass().isAssignableFrom(Double.class)) { encodeDouble((Double) result, builder); } else if (result.getClass().isAssignableFrom(Float.class)) { encodeFloat((Float) result, builder); } else if (result.getClass().isAssignableFrom(Short.class)) { encodeShort((Short) result, builder); } else if (result.getClass().isAssignableFrom(Byte.class)) { encodeByte((Byte) result, builder); } else if (result.getClass().isAssignableFrom(Boolean.class)) { encodeBoolean((Boolean) result, builder); } else if (hasInterface(result, Collection.class)) { encodeCollection((Collection<Object>) result, builder); } else if (hasInterface(result, Map.class)) { encodeMap((Map<Object, Object>) result, builder, annotation); } else if (result.getClass().isAssignableFrom(Date.class)) { encodeDate((Date) result, builder, annotation); } else if (result.getClass().isArray()) { encodeArray(result, builder); } else { encodeObject(result, builder); } } private void encodeArray(Object result, StringBuilder builder) throws JSONException { builder.append(ARRAY_LEFT); int length = Array.getLength(result); for (int i = 0; i < length; i++) { if (i > 0) { builder.append(COMMA); } encode(Array.get(result, i), builder, null); } builder.append(ARRAY_RIGHT); } private void encodeDate(Date result, StringBuilder builder, JSON annotation) throws JSONException { String customFormat = annotation.dateFormat(); if (customFormat != null && !"".equals(customFormat)) { SimpleDateFormat format = formatterPool.get(customFormat); if (format == null) { format = new SimpleDateFormat(customFormat); formatterPool.put(customFormat, format); } encodeString(format.format(result), builder, annotation); } else { encodeString(DEFAULT_FORMAT.format(result), builder, annotation); } } private void encodeMap(Map<Object, Object> result, StringBuilder builder, JSON annotation) throws JSONException { boolean first = true; builder.append(BRACKET_LEFT); Set<Entry<Object, Object>> entries = result.entrySet(); for (Iterator<Entry<Object, Object>> iterator = entries.iterator(); iterator.hasNext();) { if (!first) { builder.append(COMMA); } else { first = false; } Entry<Object, Object> entry = (Entry<Object, Object>) iterator.next(); encodeString(entry.getKey().toString(), builder, annotation); builder.append(COLON); encode(entry.getValue(), builder, null); } builder.append(BRACKET_RIGHT); } private void encodeCollection(Collection<Object> result, StringBuilder builder) throws JSONException { boolean first = true; builder.append(ARRAY_LEFT); for (Iterator<Object> iterator = result.iterator(); iterator.hasNext();) { if (!first) { builder.append(COMMA); } else { first = false; } Object object = iterator.next(); encode(object, builder, null); } builder.append(ARRAY_RIGHT); } private String encodeObject(Object c, StringBuilder builder) throws JSONException { if (c == null) { return NULL; } if (c.getClass().getAnnotation(JSON.class) == null) { return null; } builder.append(BRACKET_LEFT); int count = serializeFields(c, builder); serializeMethods(c, builder, count); builder.append(BRACKET_RIGHT); return builder.toString(); } private int serializeFields(Object c, StringBuilder builder) throws JSONException { Field[] fields = ArrayUtils.addAll(c.getClass().getDeclaredFields(), c.getClass().getFields()); int count = 0; boolean first = true; for (Field field : fields) { Annotation[] anons = field.getAnnotations(); for (Annotation annotation : anons) { if (annotation.annotationType().isAssignableFrom(JSON.class)) { if (!first) { builder.append(COMMA); } else { first = false; } String methodName = null; // primitive boolean getters have is as prefix // Use class.getComponentType instead of this if (PRIMITIVE_BOOLEAN.equals(field.getType().toString())) { methodName = JSONReflectionUtils.createGetter(field.getName(), JSONReflectionUtils.IS); } else { methodName = JSONReflectionUtils.createGetter(field.getName(), JSONReflectionUtils.GET); } try { Method method = c.getClass().getMethod(methodName, (Class[]) null); Object result = method.invoke(c, (Object[]) null); encodeString(field.getName(), builder, (JSON) annotation); builder.append(COLON); encode(result, builder, (JSON) annotation); count++; } catch (SecurityException e) { throw new JSONException(e); } catch (NoSuchMethodException e) { throw new JSONException("No appropriate getter found: " + methodName, e); } catch (IllegalArgumentException e) { throw new JSONException(e); } catch (IllegalAccessException e) { throw new JSONException(e); } catch (InvocationTargetException e) { throw new JSONException(e); } } } } return count; } private void serializeMethods(Object c, StringBuilder builder, int count) throws JSONException { boolean first = (count == 0); Method[] methods = ArrayUtils.addAll(c.getClass().getDeclaredMethods(), c.getClass().getMethods()); for (Method method : methods) { Annotation[] anons = method.getAnnotations(); for (Annotation annotation : anons) { if (annotation.annotationType().isAssignableFrom(JSON.class)) { if (!first) { builder.append(COMMA); } else { first = false; } try { Object result = method.invoke(c, (Object[]) null); String name = method.getName(); if (name.startsWith("is")) { name = name.replaceFirst("is", ""); name = name.substring(0, 1).toLowerCase() + name.substring(1); } if (name.startsWith("get")) { name = name.replaceFirst("get", ""); name = name.substring(0, 1).toLowerCase() + name.substring(1); } encodeString(name, builder, (JSON) annotation); builder.append(COLON); encode(result, builder, (JSON) annotation); } catch (SecurityException e) { throw new JSONException(e); } catch (IllegalArgumentException e) { throw new JSONException(e); } catch (IllegalAccessException e) { throw new JSONException(e); } catch (InvocationTargetException e) { throw new JSONException(e); } } } } } private void encodeString(String string, StringBuilder result, JSON annotation) { if (string == null) { result.append(NULL); } else { result.append(QUOTE); result.append(StringEscapeUtils.escapeJava(string)); result.append(QUOTE); } } private void encodeInteger(Integer integer, StringBuilder result) { if (integer == null) { result.append(NULL); } else { result.append(EMTPY_STRING); result.append(integer); result.append(EMTPY_STRING); } } private void encodeByte(Byte value, StringBuilder result) { if (value == null) { result.append(NULL); } else { result.append(EMTPY_STRING); result.append(value); result.append(EMTPY_STRING); } } private void encodeDouble(Double value, StringBuilder result) { if (value == null) { result.append(NULL); } else { result.append(EMTPY_STRING); result.append(value); result.append(EMTPY_STRING); } } private void encodeShort(Short value, StringBuilder result) { if (value == null) { result.append(NULL); } else { result.append(EMTPY_STRING); result.append(value); result.append(EMTPY_STRING); } } private void encodeFloat(Float value, StringBuilder result) { if (value == null) { result.append(NULL); } else { result.append(EMTPY_STRING); result.append(value); result.append(EMTPY_STRING); } } private void encodeLong(Long longValue, StringBuilder result) { if (longValue == null) { result.append(NULL); } else { result.append(EMTPY_STRING); result.append(longValue); result.append(EMTPY_STRING); } } private void encodeBoolean(Boolean b, StringBuilder result) { if (b == null) { result.append(NULL); } else { result.append(EMTPY_STRING); result.append(Boolean.toString(b)); result.append(EMTPY_STRING); } } private boolean hasInterface(Object target, Class<?> interfaceClass) { return interfaceClass.isInstance(target); } }