6

Id like to represent a Class object as JSON. For example, if I have the class defintions as follows:

public class MyClass {
    String myName;
    int myAge;
    MyOtherClass other;
}

public class MyOtherClass {
    double myDouble;
}

I'd like to get the following nested JSON from a Class object of type MyClass:

{
   myName: String,
   myAge: int,
   other: {
      myDouble: double;
   }
}

EDIT:

I don't want to serialize instances of these classes, I understand how to do that with GSON. I want to serialize the structure of the class itself, so that given a proprietary class Object I can generate JSON that breaks down the fields of the class recursively into standard objects like String, Double, etc.

Sam Stern
  • 24,624
  • 13
  • 93
  • 124

3 Answers3

3

With Jettison, you can roll your own mappings from Java to JSON. So in this case, you could get the Class object of the class you want, then map the Java returned by the getFields, getConstructors, getMethods etc. methods to JSON using Jettison.

smcg
  • 3,195
  • 2
  • 30
  • 40
1

I would recommend to use Jackson. You can also take a look at the JSonObjectSerializer class based on Jackson which can be found at oVirt under engine/backend/manager/module/utils (you can git clone the code) and see how we used Jackson there.

Yair Zaslavsky
  • 4,091
  • 4
  • 20
  • 27
  • The issue with all of these is that I can't get the field type, which to me is the most important part. – Sam Stern Jun 20 '12 at 18:47
  • 1
    @hatboysam - Jackson let's you serialize/deserialize also field types. See the work we did at www.ovirt.org (get the code, look at engine/backend/manager/modules/utils - you will see some code we wrote for JSon serializing and deserializing). – Yair Zaslavsky Jun 21 '12 at 19:15
0

Looking to do the same thing, in the end I wound up writing my own method, this does not handle all cases e.g. if one of the declared fields is a Map this will break, but this seems to be alright for most common objects:

@Override
public Map reflectModelAsMap(Class classType) {
    List<Class> mappedTracker = new LinkedList<Class>();

    return reflectModelAsMap(classType, mappedTracker);
}

private Map reflectModelAsMap(Class classType, List mappedTracker) {
    Map<String, Object> mapModel = new LinkedHashMap<String, Object>();

    mappedTracker.add(classType);

    Field[] fields = classType.getDeclaredFields();

    for (Field field : fields) {
        if (mappedTracker.contains(field.getType()))
            continue;

        if (BeanUtils.isSimpleValueType(field.getType())) {
            mapModel.put(field.getName(), field.getType().toString());
        } else if (Collection.class.isAssignableFrom(field.getType())) {
            Class actualType = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
            mapModel.put("Collection", reflectModelAsMap(actualType, mappedTracker));
        } else {
            mapModel.put(field.getName(), reflectModelAsMap(field.getType(), mappedTracker));
        }
    }

    return mapModel;
}

The mapped tracker there because of how I handle relationships in Hibernate; without it there is an endlessly recursive relationship between parent and child e.g. child.getFather().getFirstChild().getFather().getFirstChild().getFather()...

mike
  • 1,318
  • 3
  • 21
  • 41