package org.json.simple.serialization; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import org.json.simple.parser.BufferedJSONStreamReader; import org.json.simple.parser.ParseException; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * @author karl.wettin@kodapan.se * @since 2009-jul-03 14:39:23 */ public abstract class Codec<T> { /** json field name for java class names. "class" is a reserved name in json! */ public static String classIdentifierFieldName = "_class"; public T getDefaultInstance() { return null; } /** * Returns the "primitive" string representation for a given value. * Output often same as String.valueOf(object); * This does not include JSON value syntax such as "", ["",""] and { ... }. * <p/> * Used mostly to marshal primary key values, but all primitives also implement this method. * * @param object instance to be marshaled * @return marshaled valued of parameter object * @throws UnsupportedOperationException if the generic type for this codec can not be serialized to a single primitive value. */ public String marshal(T object) throws UnsupportedOperationException, IllegalAccessException, InstantiationException { throw new UnsupportedOperationException("Not implemented"); } /** * @see #marshal(Object) */ public T unmarshal(String stringValue) throws UnsupportedOperationException, InstantiationException, IllegalAccessException { throw new UnsupportedOperationException("Not implemented"); } public T unmarshal(Reader reader) throws ParseException, IOException, IllegalAccessException, InstantiationException { BufferedJSONStreamReader jsr = new BufferedJSONStreamReader(reader); jsr.expectNext(BufferedJSONStreamReader.Event.START_DOCUMENT); T t = unmarshal(jsr); if (jsr.getEvent() != BufferedJSONStreamReader.Event.END_DOCUMENT) { jsr.expectNext(BufferedJSONStreamReader.Event.END_DOCUMENT); } return t; } /** * Appends the JSON value for a given object to a StringBuffer. * Output should include JSON synxtax such as "", ["",""], { ... }, etc * * @param object object to be marshaled * @param definedType * @param json json string factory * @param path current path in object graph from root * @param indentation */ public abstract void marshal(T object, Class definedType, PrintWriter json, String path, int indentation) throws IllegalAccessException, InstantiationException; /** * @param jsr * @return */ public abstract T unmarshal(BufferedJSONStreamReader jsr) throws ParseException, IOException, InstantiationException, IllegalAccessException; // note for self: no Field here, raw object only. private Map<Field, Method> getters = new HashMap<Field, Method>(); private Map<Field, Method> setters = new HashMap<Field, Method>(); /** @return bean field value via getter */ public Object get(Object bean, Field field) { try { return getGetter(field).invoke(bean); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (NullPointerException e) { throw new RuntimeException(e); } } public void set(Object bean, Field field, Object value) { try { getSetter(field).invoke(bean, value); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } private Method getGetter(Field field) { Method getter = getters.get(field); if (getter == null) { Class declaringClass = field.getDeclaringClass(); StringBuilder getterName = new StringBuilder(field.getName().length() + 3); if (field.getType() == boolean.class || Boolean.class.equals(field.getType())) { getterName.append("is"); getterName.append(field.getName()); getterName.setCharAt(2, Character.toUpperCase(getterName.charAt(2))); } else { getterName.append("get"); getterName.append(field.getName()); getterName.setCharAt(3, Character.toUpperCase(getterName.charAt(3))); } try { getter = declaringClass.getMethod(getterName.toString()); } catch (NoSuchMethodException e) { throw new RuntimeException("Field " + field.getName() + " of class " + declaringClass.getName() + " does not have a getter method named " + getterName); } getters.put(field, getter); } return getter; } private Method getSetter(Field field) { Method setter = setters.get(field); if (setter == null) { Class declaringClass = field.getDeclaringClass(); StringBuffer name = new StringBuffer(field.getName()); name.setCharAt(0, Character.toUpperCase(name.charAt(0))); String setterName = "set" + name.toString(); try { setter = declaringClass.getMethod(setterName, field.getType()); } catch (NoSuchMethodException e) { throw new RuntimeException("Field " + field.getName() + " of class " + declaringClass.getName() + " does not have a setter method named " + setterName); } setters.put(field, setter); } return setter; } /** * Returns true if the field should not be marshaled to json. A list with size 0 for instance. * * @param value * @return */ public boolean isNull(T value) { return value == null; } public void addIndentation(PrintWriter json, int indentations) { for (int i = 0; i < indentations; i++) { json.append('\t'); } } }