[Json-rpc-java] Support for enum

Connor Barry connor at slickapps.com
Thu Jan 25 00:55:42 SGT 2007


Jeff,

I had to write my own. It's pretty much a quick hack solution but works 
OK for me - I assume the next version will supported enums explicitly.

There's two catches:

1 - The enum's actual name will be assigned to the "_name" attribute, to 
allow you to have another field in the enum called "name". So out in 
your javascript, refer to the actual name with "theObj._name"
2 - You have to explicitly populate an array of all the possible 
enumerated type classes

---------------------------------------------------------------------------------------

package com.yourcompany.web.jsonrpc;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.log4j.Logger;
import org.json.JSONObject;

import com.metaparadigm.jsonrpc.AbstractSerializer;
import com.metaparadigm.jsonrpc.MarshallException;
import com.metaparadigm.jsonrpc.ObjectMatch;
import com.metaparadigm.jsonrpc.SerializerState;
import com.metaparadigm.jsonrpc.UnmarshallException;

public class EnumSerializer extends AbstractSerializer {
    private final static Logger log = 
Logger.getLogger(EnumSerializer.class);
    private static final long serialVersionUID = 1L;

    private static Class[] _JSONClasses = new Class[] { JSONObject.class };

    private Class[] serializableClasses;

    public Class[] getJSONClasses() {
        return _JSONClasses;
    }

    public Object marshall(SerializerState state, Object o) throws 
MarshallException {
        try {
            for (Class<? extends Enum> clazz : getSerializableClasses()) {
                if (!clazz.isInstance(o)) continue;
                Enum theEnum = clazz.cast(o);
                JSONObject jso = new JSONObject();
                jso.put("_name", theEnum.name());

                if (ser.getMarshallClassHints()) jso.put("javaClass", 
theEnum.getClass().getName());

                BeanInfo info = Introspector.getBeanInfo(clazz);
                PropertyDescriptor props[] = info.getPropertyDescriptors();

                for (PropertyDescriptor prop : props) {
                    if ("declaringClass".equals(prop.getName()) || 
"class".equals(prop.getName()))
                        continue;

                    Method readMethod = prop.getReadMethod();
                    if (readMethod == null) continue;

                    if (ser.isDebug()) log.debug("invoking " + 
readMethod.getName() + "()");

                    Object result;
                    try {
                        result = readMethod.invoke(o, (Object[]) null);
                    } catch (Throwable e) {
                        if (e instanceof InvocationTargetException)
                            e = ((InvocationTargetException) 
e).getTargetException();
                        throw new MarshallException("bean " + 
o.getClass().getName() + " can't invoke "
                                + readMethod.getName() + ": " + 
e.getMessage());
                    }

                    try {
                        if (result != null || 
ser.getMarshallNullAttributes())
                            jso.put(prop.getName(), ser.marshall(state, 
result));
                    } catch (MarshallException e) {
                        throw new MarshallException("bean " + 
o.getClass().getName() + " "
                                + e.getMessage());
                    }
                }

                return jso;
            }
        } catch (IntrospectionException e) {
            e.printStackTrace();
            throw new MarshallException("There was an exception while 
inspecting the class "
                    + o.getClass().getName() + ", see stdout");
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            throw new MarshallException("There was an exception while 
inspecting the class "
                    + o.getClass().getName() + ", see stdout");
        }
        throw new MarshallException("The specified object (" + 
o.getClass().getName()
                + ") was not an instance of any of the serializable 
classes");
    }

    @SuppressWarnings("unchecked")
    public Object unmarshall(SerializerState state, Class clazz, Object o)
            throws UnmarshallException {
        JSONObject jso = (JSONObject) o;
        String name = jso.getString("_name");
        if (name == null)
            throw new UnmarshallException("The specified JSONObject of 
type " + clazz.getName()
                    + " didn't contain a _name attribute");
        return Enum.valueOf(clazz, name);
    }

    public ObjectMatch tryUnmarshall(SerializerState arg0, Class arg1, 
Object arg2) {
        return null;
    }

    /**
     * @return the serializableClasses
     */
    public Class[] getSerializableClasses() {
        return serializableClasses;
    }

    /**
     * @param serializableClasses the serializableClasses to set
     */
    public void setSerializableClasses(Class[] serializableClasses) {
        this.serializableClasses = serializableClasses;
    }

}
------------------------------------------------------------------------

You also need to register this serializer with the bridge, either the 
global bridge once in a static block, or every time a new 
HTTPSession-specific bridge gets created and put in the user's HTTP Session:

EnumSerializer enumSerializer = new EnumSerializer();
enumSerializer.setSerializableClasses(new Class[] {MyEnumeratedType.class});
bridge.registerSerializer(enumSerializer);

I might have forgotten something, send questions to the list.

Connor

Jeff Moody wrote:
> I was wondering if there are any plans to support enum types.
> E.g. I have a class with a property that is a defined enum type, where the
> enum has declared  constants of that type.
> I have a method that returns one of these objects, but when calling the
> method through the bridge, it gives me a Javascript error of an unhandled
> JSONRpc exception, indicating the error is due to a circular reference.
>
> For example, say the following declaration is in foo.java:
> public enum Foo {
>     VALUE1
>   , VALUE2
> }
>
>
> Returning an object with a Foo property causes an error.
>
> Are there any workarounds to this?
>
> Thanks,
> -Jeff
>
>
> _______________________________________________
> Json-rpc-java mailing list
> Json-rpc-java at oss.metaparadigm.com
> http://oss.metaparadigm.com/mailman/listinfo/json-rpc-java
>   



More information about the Json-rpc-java mailing list