Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.fasterxml.jackson.jaxrs.json;
  
  import java.io.*;
  import java.util.*;
  
  import javax.ws.rs.*;
 
Basic implementation of JAX-RS abstractions (javax.ws.rs.ext.MessageBodyReader, javax.ws.rs.ext.MessageBodyWriter) needed for binding JSON ("application/json") content to and from Java Objects ("POJO"s).

Actual data binding functionality is implemented by com.fasterxml.jackson.databind.ObjectMapper: mapper to use can be configured in multiple ways:

The last method ("do nothing specific") is often good enough; explicit passing of Mapper is simple and explicit; and Provider-based method may make sense with Depedency Injection frameworks, or if Mapper has to be configured differently for different media types.

Note that the default mapper instance will be automatically created if one of explicit configuration methods (like configure(com.fasterxml.jackson.databind.DeserializationFeature,boolean)) is called: if so, Provider-based introspection is NOT used, but the resulting Mapper is used as configured.

Note: version 1.3 added a sub-class (JacksonJaxbJsonProvider) which is configured by default to use both Jackson and JAXB annotations for configuration (base class when used as-is defaults to using just Jackson annotations)

Author(s):
Tatu Saloranta
 
 @Consumes(.// NOTE: required to support "non-standard" JSON variants
 public class JacksonJsonProvider
     implements
         MessageBodyReader<Object>,
         MessageBodyWriter<Object>,
         Versioned
 {
    
Default annotation sets to use, if not explicitly defined during construction: only Jackson annotations are used for the base class. Sub-classes can use other settings.
 
     public final static Annotations[] BASIC_ANNOTATIONS = {
         .
     };

    
Looks like we need to worry about accidental data binding for types we shouldn't be handling. This is probably not a very good way to do it, but let's start by blacklisting things we are not to handle.

(why ClassKey? since plain old Class has no hashCode() defined, lookups are painfully slow)

 
     public final static HashSet<ClassKey_untouchables = new HashSet<ClassKey>();
     static {
         // First, I/O things (direct matches)
         .add(new ClassKey(java.io.InputStream.class));
         .add(new ClassKey(java.io.Reader.class));
         .add(new ClassKey(java.io.OutputStream.class));
         .add(new ClassKey(java.io.Writer.class));
 
         // then some primitive types
         .add(new ClassKey(char[].class));
 
         /* 28-Jan-2012, tatu: 1.x excluded some additional types;
          *   but let's relax these a bit:
          */
         /* 27-Apr-2012, tatu: Ugh. As per
          *   [https://github.com/FasterXML/jackson-jaxrs-json-provider/issues/12]
          *  better revert this back, to make them untouchable again.
          */
         .add(new ClassKey(String.class));
        .add(new ClassKey(byte[].class));
    }

    
These are classes that we never use for reading (never try to deserialize instances of these types).
    public final static Class<?>[] _unreadableClasses = new Class<?>[] {
        InputStream.classReader.class
    };

    
These are classes that we never use for writing (never try to serialize instances of these types).
    public final static Class<?>[] _unwritableClasses = new Class<?>[] {
        OutputStream.classWriter.class,
        StreamingOutput.classResponse.class
    };
    /*
    /**********************************************************
    /* Bit of caching
    /**********************************************************
     */

    
Cache for resolved endpoint configurations when reading JSON data
        = new LRUMap<AnnotationBundleKeyEndpointConfig>(16, 120);

    
Cache for resolved endpoint configurations when writing JSON data
        = new LRUMap<AnnotationBundleKeyEndpointConfig>(16, 120);
    
    /*
    /**********************************************************
    /* General configuration
    /**********************************************************
     */
    
    
Helper object used for encapsulating configuration aspects of com.fasterxml.jackson.databind.ObjectMapper
    protected final MapperConfigurator _mapperConfig;

    
Set of types (classes) that provider should ignore for data binding
    protected HashSet<ClassKey_cfgCustomUntouchables;

    
JSONP function name to use for automatic JSONP wrapping, if any; if null, no JSONP wrapping is done. Note that this is the default value that can be overridden on per-endpoint basis.
    protected String _jsonpFunctionName;
    
    /*
    /**********************************************************
    /* Context configuration
    /**********************************************************
     */

    
Injectable context object used to locate configured instance of com.fasterxml.jackson.databind.ObjectMapper to use for actual serialization.
    @Context
    protected Providers _providers;
    /*
    /**********************************************************
    /* Configuration
    /**********************************************************
     */

    
Whether we want to actually check that Jackson has a serializer for given type. Since this should generally be the case (due to auto-discovery) and since the call to check availability can be bit expensive, defaults to false.
    protected boolean _cfgCheckCanSerialize = false;

    
Whether we want to actually check that Jackson has a deserializer for given type. Since this should generally be the case (due to auto-discovery) and since the call to check availability can be bit expensive, defaults to false.
    protected boolean _cfgCheckCanDeserialize = false;
    /*
    /**********************************************************
    /* Construction
    /**********************************************************
     */

    
Default constructor, usually used when provider is automatically configured to be used with JAX-RS implementation.
    public JacksonJsonProvider()
    {
        this(null);
    }

    

Parameters:
annotationsToUse Annotation set(s) to use for configuring data binding
    public JacksonJsonProvider(Annotations... annotationsToUse)
    {
        this(nullannotationsToUse);
    }
    public JacksonJsonProvider(ObjectMapper mapper)
    {
        this(mapper);
    }
    
    
Constructor to use when a custom mapper (usually components like serializer/deserializer factories that have been configured) is to be used.

Parameters:
annotationsToUse Sets of annotations (Jackson, JAXB) that provider should support
    public JacksonJsonProvider(ObjectMapper mapperAnnotations[] annotationsToUse)
    {
         = new MapperConfigurator(mapperannotationsToUse);
    }

    
Method that will return version information stored in and read from jar that contains this class.
    public Version version() {
        return ..version();
    }
    
    /*
    /**********************************************************
    /* Configuring
    /**********************************************************
     */

    
Method for defining whether actual detection for existence of a deserializer for type should be done when isReadable(java.lang.Class,java.lang.reflect.Type,java.lang.annotation.Annotation[],javax.ws.rs.core.MediaType) is called.
    public void checkCanDeserialize(boolean state) {  = state; }

    
Method for defining whether actual detection for existence of a serializer for type should be done when isWriteable(java.lang.Class,java.lang.reflect.Type,java.lang.annotation.Annotation[],javax.ws.rs.core.MediaType) is called.
    public void checkCanSerialize(boolean state) {  = state; }

    
Method for configuring which annotation sets to use (including none). Annotation sets are defined in order decreasing precedence; that is, first one has the priority over following ones.

Parameters:
annotationsToUse Ordered list of annotation sets to use; if null, default
    public void setAnnotationsToUse(Annotations[] annotationsToUse) {
        .setAnnotationsToUse(annotationsToUse);
    }
    
    
Method that can be used to directly define com.fasterxml.jackson.databind.ObjectMapper to use for serialization and deserialization; if null, will use the standard provider discovery from context instead. Default setting is null.
    public void setMapper(ObjectMapper m) {
        .setMapper(m);
    }
    public JacksonJsonProvider configure(DeserializationFeature fboolean state) {
        .configure(fstate);
        return this;
    }
    public JacksonJsonProvider configure(SerializationFeature fboolean state) {
        .configure(fstate);
        return this;
    }
    public JacksonJsonProvider configure(JsonParser.Feature fboolean state) {
        .configure(fstate);
        return this;
    }
    public JacksonJsonProvider configure(JsonGenerator.Feature fboolean state) {
        .configure(fstate);
        return this;
    }
    public JacksonJsonProvider enable(DeserializationFeature fboolean state) {
        .configure(ftrue);
        return this;
    }
    public JacksonJsonProvider enable(SerializationFeature fboolean state) {
        .configure(ftrue);
        return this;
    }
    public JacksonJsonProvider enable(JsonParser.Feature fboolean state) {
        .configure(ftrue);
        return this;
    }
    public JacksonJsonProvider enable(JsonGenerator.Feature fboolean state) {
        .configure(ftrue);
        return this;
    }
    public JacksonJsonProvider disable(DeserializationFeature fboolean state) {
        .configure(ffalse);
        return this;
    }
    public JacksonJsonProvider disable(SerializationFeature fboolean state) {
        .configure(ffalse);
        return this;
    }
    public JacksonJsonProvider disable(JsonParser.Feature fboolean state) {
        .configure(ffalse);
        return this;
    }
    public JacksonJsonProvider disable(JsonGenerator.Feature fboolean state) {
        .configure(ffalse);
        return this;
    }

    
Method for marking specified type as "untouchable", meaning that provider will not try to read or write values of this type (or its subtypes).

Parameters:
type Type to consider untouchable; can be any kind of class, including abstract class or interface. No instance of this type (including subtypes, i.e. types assignable to this type) will be read or written by provider
    public void addUntouchable(Class<?> type)
    {
        if ( == null) {
             = new HashSet<ClassKey>();
        }
        .add(new ClassKey(type));
    }
    public void setJSONPFunctionName(String fname) {
    	this. = fname;
    }
    
    /*
    /**********************************************************
    /* MessageBodyReader impl
    /**********************************************************
     */

    
Method that JAX-RS container calls to try to check whether values of given type (and media type) can be deserialized by this provider. Implementation will first check that expected media type is a JSON type (via call to isJsonType(javax.ws.rs.core.MediaType); then verify that type is not one of "untouchable" types (types we will never automatically handle), and finally that there is a deserializer for type (iff checkCanDeserialize(boolean) has been called with true argument -- otherwise assumption is there will be a handler)
    public boolean isReadable(Class<?> typeType genericTypeAnnotation[] annotationsMediaType mediaType)
    {
        if (!isJsonType(mediaType)) {
            return false;
        }
        /* Ok: looks like we must weed out some core types here; ones that
         * make no sense to try to bind from JSON:
         */
        if (.contains(new ClassKey(type))) {
            return false;
        }
        // and there are some other abstract/interface types to exclude too:
        for (Class<?> cls : ) {
            if (cls.isAssignableFrom(type)) {
                return false;
            }
        }
        // as well as possible custom exclusions
        if (_containedIn(type)) {
            return false;
        }
        // Finally: if we really want to verify that we can serialize, we'll check:
        if () {
            ObjectMapper mapper = locateMapper(typemediaType);
            if (!mapper.canDeserialize(mapper.constructType(type))) {
                return false;
            }
        }
        return true;
    }
    
    
Method that JAX-RS container calls to deserialize given value.
    public Object readFrom(Class<ObjecttypeType genericTypeAnnotation[] annotationsMediaType mediaTypeMultivaluedMap<String,StringhttpHeadersInputStream entityStream
        throws IOException
    {
        AnnotationBundleKey key = new AnnotationBundleKey(annotations);
        EndpointConfig endpoint;
        synchronized () {
            endpoint = .get(key);
        }
        // not yet resolved (or not cached any more)? Resolve!
        if (endpoint == null) {
            ObjectMapper mapper = locateMapper(typemediaType);
            endpoint = EndpointConfig.forReading(mapperannotations);
            // and cache for future reuse
            synchronized () {
                .put(key.immutableKey(), endpoint);
            }
        }
        ObjectReader reader = endpoint.getReader();
        
        JsonParser jp = reader.getJsonFactory().createJsonParser(entityStream);
        if (jp.nextToken() == null) {
           return null;
        }
        return reader.withType(genericType).readValue(jp);
    }
    /*
    /**********************************************************
    /* MessageBodyWriter impl
    /**********************************************************
     */

    
Method that JAX-RS container calls to try to figure out serialized length of given value. Since computation of this length is about as expensive as serialization itself, implementation will return -1 to denote "not known", so that container will determine length from actual serialized output (if needed).
    public long getSize(Object valueClass<?> typeType genericTypeAnnotation[] annotationsMediaType mediaType)
    {
        /* In general figuring output size requires actual writing; usually not
         * worth it to write everything twice.
         */
        return -1;
    }

    
Method that JAX-RS container calls to try to check whether given value (of specified type) can be serialized by this provider. Implementation will first check that expected media type is a JSON type (via call to isJsonType(javax.ws.rs.core.MediaType); then verify that type is not one of "untouchable" types (types we will never automatically handle), and finally that there is a serializer for type (iff checkCanSerialize(boolean) has been called with true argument -- otherwise assumption is there will be a handler)
    public boolean isWriteable(Class<?> typeType genericTypeAnnotation[] annotationsMediaType mediaType)
    {
        if (!isJsonType(mediaType)) {
            return false;
        }
        /* Ok: looks like we must weed out some core types here; ones that
         * make no sense to try to bind from JSON:
         */
        if (.contains(new ClassKey(type))) {
            return false;
        }
        // but some are interface/abstract classes, so
        for (Class<?> cls : ) {
            if (cls.isAssignableFrom(type)) {
                return false;
            }
        }
        // and finally, may have additional custom types to exclude
        if (_containedIn(type)) {
            return false;
        }
        // Also: if we really want to verify that we can deserialize, we'll check:
        if () {
            if (!locateMapper(typemediaType).canSerialize(type)) {
                return false;
            }
        }
        return true;
    }

    
Method that JAX-RS container calls to serialize given value.
    public void writeTo(Object valueClass<?> typeType genericTypeAnnotation[] annotationsMediaType mediaType,
            MultivaluedMap<String,ObjecthttpHeadersOutputStream entityStream
        throws IOException
    {
        AnnotationBundleKey key = new AnnotationBundleKey(annotations);
        EndpointConfig endpoint;
        synchronized () {
            endpoint = .get(key);
        }
        // not yet resolved (or not cached any more)? Resolve!
        if (endpoint == null) {
            ObjectMapper mapper = locateMapper(typemediaType);
            endpoint = EndpointConfig.forWriting(mapperannotations,
                    this.);
            // and cache for future reuse
            synchronized () {
                .put(key.immutableKey(), endpoint);
            }
        }
        ObjectWriter writer = endpoint.getWriter();
        
        /* 27-Feb-2009, tatu: Where can we find desired encoding? Within
         *   HTTP headers?
         */
        JsonEncoding enc = findEncoding(mediaTypehttpHeaders);
        JsonGenerator jg = writer.getJsonFactory().createJsonGenerator(entityStreamenc);
        // Want indentation?
        if (writer.isEnabled(.)) {
            jg.useDefaultPrettyPrinter();
        }
        // 04-Mar-2010, tatu: How about type we were given? (if any)
        JavaType rootType = null;
        
        if (genericType != null && value != null) {
            /* 10-Jan-2011, tatu: as per [JACKSON-456], it's not safe to just force root
             *    type since it prevents polymorphic type serialization. Since we really
             *    just need this for generics, let's only use generic type if it's truly
             *    generic.
             */
            if (genericType.getClass() != Class.class) { // generic types are other impls of 'java.lang.reflect.Type'
                /* This is still not exactly right; should root type be further
                 * specialized with 'value.getClass()'? Let's see how well this works before
                 * trying to come up with more complete solution.
                 */
                rootType = writer.getTypeFactory().constructType(genericType);
                /* 26-Feb-2011, tatu: To help with [JACKSON-518], we better recognize cases where
                 *    type degenerates back into "Object.class" (as is the case with plain TypeVariable,
                 *    for example), and not use that.
                 */
                if (rootType.getRawClass() == Object.class) {
                    rootType = null;
                }
            }
        }
        // Most of the configuration now handled through EndpointConfig, ObjectWriter
        // but we may need to force root type:
        if (rootType != null) {
            writer = writer.withType(rootType);
        }
        // and finally, JSONP wrapping, if any:
        value = endpoint.applyJSONP(value);
        
        writer.writeValue(jgvalue);
    }

    
Helper method to use for determining desired output encoding. For now, will always just use UTF-8...
    protected JsonEncoding findEncoding(MediaType mediaTypeMultivaluedMap<String,ObjecthttpHeaders)
    {
        return .;
    }
    
    /*
    /**********************************************************
    /* Public helper methods
    /**********************************************************
     */

    
Helper method used to check whether given media type is JSON type or sub type. Current implementation essentially checks to see whether javax.ws.rs.core.MediaType.getSubtype() returns "json" or something ending with "+json".
    protected boolean isJsonType(MediaType mediaType)
    {
        /* As suggested by Stephen D, there are 2 ways to check: either
         * being as inclusive as possible (if subtype is "json"), or
         * exclusive (major type "application", minor type "json").
         * Let's start with inclusive one, hard to know which major
         * types we should cover aside from "application".
         */
        if (mediaType != null) {
            // Ok: there are also "xxx+json" subtypes, which count as well
            String subtype = mediaType.getSubtype();
            return "json".equalsIgnoreCase(subtype) || subtype.endsWith("+json");
        }
        /* Not sure if this can happen; but it seems reasonable
         * that we can at least produce json without media type?
         */
        return true;
    }

    
Method called to locate com.fasterxml.jackson.databind.ObjectMapper to use for serialization and deserialization. If an instance has been explicitly defined by setMapper(com.fasterxml.jackson.databind.ObjectMapper) (or non-null instance passed in constructor), that will be used. If not, will try to locate it using standard JAX-RS javax.ws.rs.ext.ContextResolver mechanism, if it has been properly configured to access it (by JAX-RS runtime). Finally, if no mapper is found, will return a default unconfigured com.fasterxml.jackson.databind.ObjectMapper instance (one constructed with default constructor and not modified in any way)

Parameters:
type Class of object being serialized or deserialized; not checked at this point, since it is assumed that unprocessable classes have been already weeded out, but will be passed to javax.ws.rs.ext.ContextResolver as is.
mediaType Declared media type for the instance to process: not used by this method, but will be passed to javax.ws.rs.ext.ContextResolver as is.
    public ObjectMapper locateMapper(Class<?> typeMediaType mediaType)
    {
        // First: were we configured with a specific instance?
        if (m == null) {
            // If not, maybe we can get one configured via context?
            if ( != null) {
                ContextResolver<ObjectMapperresolver = .getContextResolver(ObjectMapper.classmediaType);
                /* Above should work as is, but due to this bug
                 *   [https://jersey.dev.java.net/issues/show_bug.cgi?id=288]
                 * in Jersey, it doesn't. But this works until resolution of
                 * the issue:
                 */
                if (resolver == null) {
                    resolver = .getContextResolver(ObjectMapper.classnull);
                }
                if (resolver != null) {
                    m = resolver.getContext(type);
                }
            }
            if (m == null) {
                // If not, let's get the fallback default instance
                m = .getDefaultMapper();
            }
        }
        return m;
    }
    /*
    /**********************************************************
    /* Private/sub-class helper methods
    /**********************************************************
     */
    protected static boolean _containedIn(Class<?> mainTypeHashSet<ClassKeyset)
    {
        if (set != null) {
            ClassKey key = new ClassKey(mainType);
            // First: type itself?
            if (set.contains(key)) return true;
            // Then supertypes (note: will not contain Object.class)
            for (Class<?> cls : findSuperTypes(mainTypenull)) {
                key.reset(cls);
                if (set.contains(key)) return true;
            }
        }
        return false;
    }
    private static List<Class<?>> findSuperTypes(Class<?> clsClass<?> endBefore)
    {
        return findSuperTypes(clsendBeforenew ArrayList<Class<?>>(8));
    }
    private static List<Class<?>> findSuperTypes(Class<?> clsClass<?> endBeforeList<Class<?>> result)
    {
        _addSuperTypes(clsendBeforeresultfalse);
        return result;
    }
    
    private static void _addSuperTypes(Class<?> clsClass<?> endBeforeCollection<Class<?>> resultboolean addClassItself)
    {
        if (cls == endBefore || cls == null || cls == Object.class) {
            return;
        }
        if (addClassItself) {
            if (result.contains(cls)) { // already added, no need to check supers
                return;
            }
            result.add(cls);
        }
        for (Class<?> intCls : cls.getInterfaces()) {
            _addSuperTypes(intClsendBeforeresulttrue);
        }
        _addSuperTypes(cls.getSuperclass(), endBeforeresulttrue);
    }
New to GrepCode? Check out our FAQ X