users@jersey.java.net

JSON Arrays

From: Gabriel Klein _at_ Poken <gabriel_at_doyoupoken.com>
Date: Mon, 17 Aug 2009 19:35:02 +0200

At poken, we use jaxb to generate java classes for xsd.

I have coded a @Provider

This code is
- incomplete: Many cases are missing. (Like get functions with
annotations).
- totally free to use: Do what you want with it.
- Not really tested but it works great for us.
- Works with jersey 1.1.2, doesn't work with jersey 1.1.1, not tested on
other versions.
- Based on annotation in Java domain objects

Check in you logs that you have something similar to
INFO: Provider classes found:
  class ch.poken.api.rest.v081.resources.server.JAXBFixJSONArrayProvider

--
package ch.poken.api.rest.v081.resources.server;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.annotation.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.api.json.JSONJAXBContext;
@Provider
public class JAXBFixJSONArrayProvider implements
ContextResolver<JAXBContext> {
        // Logs
	static final Logger logger = LoggerFactory
			.getLogger(JAXBContextResolver.class);
	/**
	 * This map store all jaxb context once processed by the parser.
	 */
	private static Map<Class<? extends Object>, JAXBContext> jaxbContexts =
Collections
			.synchronizedMap(new HashMap<Class<? extends Object>,
JAXBContext>());
	/**
	 * Get the jaxb context, generate this context if it doesn't exists
yet.
	 * 
	 * @param the
	 *            class used to generate the JAXB context
	 * @return JAXB context
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws NoSuchMethodException
	 * @throws IllegalArgumentException
	 * @throws SecurityException
	 */
	private static JAXBContext getJAXBContext(Class<? extends Object>
class1)
			throws Exception {
		// Get from cache
		JAXBContext context = jaxbContexts.get(class1);
		if (context != null) {
			return context;
		}
		// Parse all jaxb nodes
		Map<Class<? extends Object>, Object> mapClassIterated = new
HashMap<Class<? extends Object>, Object>();
		Map<String, Object> mapFieldsList = new HashMap<String, Object>();
		parseJAXBContext(class1, mapClassIterated, mapFieldsList);
		String[] fields = mapFieldsList.keySet().toArray(new String[0]);
		// Create the JAXB Context
		context = new JSONJAXBContext(JSONConfiguration.mapped()
				.rootUnwrapping(true).arrays(fields).build(), class1);
		// Add this context to cache.
		jaxbContexts.put(class1, context);
		return context;
	}
	/**
	 * Parse a jaxb context, add the element in mapFields.
	 * 
	 * @param class1
	 *            is the name of the class to be parser
	 * @param mapClassIterated
	 *            is the map of iterated classes
	 * @param mapFieldsList
	 *            is the map of fields that have been extracted
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	private static void parseJAXBContext(Class<? extends Object> class1,
			Map<Class<? extends Object>, Object> mapClassIterated,
			Map<String, Object> mapFieldsList) throws SecurityException,
			NoSuchMethodException, IllegalArgumentException,
			IllegalAccessException, InvocationTargetException {
		// We have already processed this class
		if (mapClassIterated.containsKey(class1)) {
			return;
		}
		mapClassIterated.put(class1, Boolean.TRUE);
		// Extract from parameters
		for (Field f : class1.getDeclaredFields()) {
			Annotation a = f.getAnnotation(XmlElement.class);
			String name = null;
			if (a != null) {
				Method m = a.getClass().getMethod("name");
				name = (String) m.invoke(a);
			}
			if (name == null || "##default".equals(name)) {
				name = f.getName();
			}
			{
				// Is it a list
				if (f.getType() == List.class) {
					mapFieldsList.put(name, Boolean.TRUE);
					ParameterizedType aType = (ParameterizedType) f
							.getGenericType();
					Type[] fieldArgTypes = aType.getActualTypeArguments();
					for (Type fieldArgType : fieldArgTypes) {
						parseJAXBContext((Class<?>) fieldArgType,
								mapClassIterated, mapFieldsList);
					}
				} else {
					parseJAXBContext(f.getType(), mapClassIterated,
							mapFieldsList);
				}
			}
		}
		// TODO: Extract from methods
		// for (Method m : class1.getMethods()) {
		// }
	}
	/**
	 * Get the JAXB context
	 */
	public JAXBContext getContext(Class<?> objectType) {
		try {
			return getJAXBContext(objectType);
		} catch (Throwable t) {
			throw new RuntimeException(t);
		}
	}
}
###**###**###**###**###**###**###**###**###
Gabriel Klein
CSA / Poken SA
Please Poken with me for more information.