org.eclipse.jetty.util.ajax.JSONPojoConvertor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache Show documentation
Show all versions of ehcache Show documentation
Ehcache is an open source, standards-based cache used to boost performance,
offload the database and simplify scalability. Ehcache is robust, proven and full-featured and
this has made it the most widely-used Java-based cache.
//
// ========================================================================
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util.ajax;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.eclipse.jetty.util.ajax.JSON.Output;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* Converts POJOs to JSON and vice versa.
* The key difference:
* - returns the actual object from Convertor.fromJSON (JSONObjectConverter returns a Map)
* - the getters/setters are resolved at initialization (JSONObjectConverter resolves it at runtime)
* - correctly sets the number fields
*
*/
public class JSONPojoConvertor implements JSON.Convertor
{
private static final Logger LOG = Log.getLogger(JSONPojoConvertor.class);
public static final Object[] GETTER_ARG = new Object[]{}, NULL_ARG = new Object[]{null};
private static final Map, NumberType> __numberTypes = new HashMap, NumberType>();
public static NumberType getNumberType(Class> clazz)
{
return __numberTypes.get(clazz);
}
protected boolean _fromJSON;
protected Class> _pojoClass;
protected Map _getters = new HashMap();
protected Map _setters = new HashMap();
protected Set _excluded;
/**
* @param pojoClass The class to convert
*/
public JSONPojoConvertor(Class> pojoClass)
{
this(pojoClass, (Set)null, true);
}
/**
* @param pojoClass The class to convert
* @param excluded The fields to exclude
*/
public JSONPojoConvertor(Class> pojoClass, String[] excluded)
{
this(pojoClass, new HashSet(Arrays.asList(excluded)), true);
}
/**
* @param pojoClass The class to convert
* @param excluded The fields to exclude
*/
public JSONPojoConvertor(Class> pojoClass, Set excluded)
{
this(pojoClass, excluded, true);
}
/**
* @param pojoClass The class to convert
* @param excluded The fields to exclude
* @param fromJSON If true, add a class field to the JSON
*/
public JSONPojoConvertor(Class> pojoClass, Set excluded, boolean fromJSON)
{
_pojoClass = pojoClass;
_excluded = excluded;
_fromJSON = fromJSON;
init();
}
/**
* @param pojoClass The class to convert
* @param fromJSON If true, add a class field to the JSON
*/
public JSONPojoConvertor(Class> pojoClass, boolean fromJSON)
{
this(pojoClass, (Set)null, fromJSON);
}
/* ------------------------------------------------------------ */
protected void init()
{
Method[] methods = _pojoClass.getMethods();
for (int i=0;i2)
name=name.substring(2,3).toLowerCase(Locale.ENGLISH)+name.substring(3);
else if (name.startsWith("get") && name.length()>3)
name=name.substring(3,4).toLowerCase(Locale.ENGLISH)+name.substring(4);
else
break;
if(includeField(name, m))
addGetter(name, m);
}
break;
case 1:
if (name.startsWith("set") && name.length()>3)
{
name=name.substring(3,4).toLowerCase(Locale.ENGLISH)+name.substring(4);
if(includeField(name, m))
addSetter(name, m);
}
break;
}
}
}
}
/* ------------------------------------------------------------ */
protected void addGetter(String name, Method method)
{
_getters.put(name, method);
}
/* ------------------------------------------------------------ */
protected void addSetter(String name, Method method)
{
_setters.put(name, new Setter(name, method));
}
/* ------------------------------------------------------------ */
protected Setter getSetter(String name)
{
return _setters.get(name);
}
/* ------------------------------------------------------------ */
protected boolean includeField(String name, Method m)
{
return _excluded==null || !_excluded.contains(name);
}
/* ------------------------------------------------------------ */
protected int getExcludedCount()
{
return _excluded==null ? 0 : _excluded.size();
}
/* ------------------------------------------------------------ */
public Object fromJSON(Map object)
{
Object obj = null;
try
{
obj = _pojoClass.newInstance();
}
catch(Exception e)
{
// TODO return Map instead?
throw new RuntimeException(e);
}
setProps(obj, object);
return obj;
}
/* ------------------------------------------------------------ */
public int setProps(Object obj, Map,?> props)
{
int count = 0;
for(Iterator> iterator = props.entrySet().iterator(); iterator.hasNext();)
{
Map.Entry, ?> entry = (Map.Entry,?>) iterator.next();
Setter setter = getSetter((String)entry.getKey());
if(setter!=null)
{
try
{
setter.invoke(obj, entry.getValue());
count++;
}
catch(Exception e)
{
// TODO throw exception?
LOG.warn(_pojoClass.getName()+"#"+setter.getPropertyName()+" not set from "+
(entry.getValue().getClass().getName())+"="+entry.getValue().toString());
log(e);
}
}
}
return count;
}
/* ------------------------------------------------------------ */
public void toJSON(Object obj, Output out)
{
if(_fromJSON)
out.addClass(_pojoClass);
for(Map.Entry entry : _getters.entrySet())
{
try
{
out.add(entry.getKey(), entry.getValue().invoke(obj, GETTER_ARG));
}
catch(Exception e)
{
// TODO throw exception?
LOG.warn("{} property '{}' excluded. (errors)", _pojoClass.getName(),
entry.getKey());
log(e);
}
}
}
/* ------------------------------------------------------------ */
protected void log(Throwable t)
{
LOG.ignore(t);
}
/* ------------------------------------------------------------ */
public static class Setter
{
protected String _propertyName;
protected Method _setter;
protected NumberType _numberType;
protected Class> _type;
protected Class> _componentType;
public Setter(String propertyName, Method method)
{
_propertyName = propertyName;
_setter = method;
_type = method.getParameterTypes()[0];
_numberType = __numberTypes.get(_type);
if(_numberType==null && _type.isArray())
{
_componentType = _type.getComponentType();
_numberType = __numberTypes.get(_componentType);
}
}
public String getPropertyName()
{
return _propertyName;
}
public Method getMethod()
{
return _setter;
}
public NumberType getNumberType()
{
return _numberType;
}
public Class> getType()
{
return _type;
}
public Class> getComponentType()
{
return _componentType;
}
public boolean isPropertyNumber()
{
return _numberType!=null;
}
public void invoke(Object obj, Object value) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException
{
if(value==null)
_setter.invoke(obj, NULL_ARG);
else
invokeObject(obj, value);
}
protected void invokeObject(Object obj, Object value) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException
{
if (_type.isEnum())
{
if (value instanceof Enum)
_setter.invoke(obj, new Object[]{value});
else
_setter.invoke(obj, new Object[]{Enum.valueOf((Class extends Enum>)_type,value.toString())});
}
else if(_numberType!=null && value instanceof Number)
{
_setter.invoke(obj, new Object[]{_numberType.getActualValue((Number)value)});
}
else if (Character.TYPE.equals(_type) || Character.class.equals(_type))
{
_setter.invoke(obj, new Object[]{String.valueOf(value).charAt(0)});
}
else if(_componentType!=null && value.getClass().isArray())
{
if(_numberType==null)
{
int len = Array.getLength(value);
Object array = Array.newInstance(_componentType, len);
try
{
System.arraycopy(value, 0, array, 0, len);
}
catch(Exception e)
{
// unusual array with multiple types
LOG.ignore(e);
_setter.invoke(obj, new Object[]{value});
return;
}
_setter.invoke(obj, new Object[]{array});
}
else
{
Object[] old = (Object[])value;
Object array = Array.newInstance(_componentType, old.length);
try
{
for(int i=0; i