All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider Maven / Gradle / Ivy

Go to download

Functionality to handle JSON input/output for JAX-RS implementations (like Jersey and RESTeasy) using standard Jackson data binding.

There is a newer version: 2.18.1
Show newest version
package com.fasterxml.jackson.jaxrs.json;

import java.lang.annotation.Annotation;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.ext.*;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.jaxrs.base.ProviderBase;
import com.fasterxml.jackson.jaxrs.cfg.Annotations;


/**
 * Basic implementation of JAX-RS abstractions ({@link MessageBodyReader},
 * {@link MessageBodyWriter}) needed for binding
 * JSON ("application/json") content to and from Java Objects ("POJO"s).
 *

* Actual data binding functionality is implemented by {@link ObjectMapper}: * mapper to use can be configured in multiple ways: *

    *
  • By explicitly passing mapper to use in constructor *
  • By explictly setting mapper to use by {@link #setMapper} *
  • By defining JAX-RS Provider that returns {@link ObjectMapper}s. *
  • By doing none of above, in which case a default mapper instance is * constructed (and configured if configuration methods are called) *
* 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 {@link #configure}) * 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 ({@link 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 Tatu Saloranta */ @Provider @Consumes(MediaType.WILDCARD) // NOTE: required to support "non-standard" JSON variants @Produces({MediaType.APPLICATION_JSON, "text/json", MediaType.WILDCARD}) public class JacksonJsonProvider extends ProviderBase { public final static String MIME_JAVASCRIPT = "application/javascript"; public final static String MIME_JAVASCRIPT_MS = "application/x-javascript"; /** * 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 = { Annotations.JACKSON }; /* /********************************************************** /* General configuration /********************************************************** */ /** * 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 {@link ObjectMapper} to use for actual * serialization. */ @Context protected Providers _providers; /* /********************************************************** /* Construction /********************************************************** */ /** * Default constructor, usually used when provider is automatically * configured to be used with JAX-RS implementation. */ public JacksonJsonProvider() { this(null, BASIC_ANNOTATIONS); } /** * @param annotationsToUse Annotation set(s) to use for configuring * data binding */ public JacksonJsonProvider(Annotations... annotationsToUse) { this(null, annotationsToUse); } public JacksonJsonProvider(ObjectMapper mapper) { this(mapper, BASIC_ANNOTATIONS); } /** * Constructor to use when a custom mapper (usually components * like serializer/deserializer factories that have been configured) * is to be used. * * @param annotationsToUse Sets of annotations (Jackson, JAXB) that provider should * support */ public JacksonJsonProvider(ObjectMapper mapper, Annotations[] annotationsToUse) { super(new JsonMapperConfigurator(mapper, annotationsToUse)); } /** * Method that will return version information stored in and read from jar * that contains this class. */ @Override public Version version() { return PackageVersion.VERSION; } /* /********************************************************** /* JSON-specific configuration /********************************************************** */ public void setJSONPFunctionName(String fname) { _jsonpFunctionName = fname; } /* /********************************************************** /* Abstract method impls /********************************************************** */ /** * Helper method used to check whether given media type * is supported by this provider. * Current implementation essentially checks to see whether * {@link MediaType#getSubtype} returns "json" or something * ending with "+json". * Or "text/x-json" (since 2.3) * * @since 2.2 */ @Override protected boolean hasMatchingMediaType(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(); // [Issue#14]: also allow 'application/javascript' return "json".equalsIgnoreCase(subtype) || subtype.endsWith("+json") || "javascript".equals(subtype) // apparently Microsoft once again has interesting alternative types? || "x-javascript".equals(subtype) || "x-json".equals(subtype) // [Issue#40] ; } /* Not sure if this can happen; but it seems reasonable * that we can at least produce JSON without media type? */ return true; } @Override protected ObjectMapper _locateMapperViaProvider(Class type, MediaType mediaType) { if (_providers != null) { ContextResolver resolver = _providers.getContextResolver(ObjectMapper.class, mediaType); /* 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 = _providers.getContextResolver(ObjectMapper.class, null); } if (resolver != null) { return resolver.getContext(type); } } return null; } @Override protected JsonEndpointConfig _configForReading(ObjectReader reader, Annotation[] annotations) { return JsonEndpointConfig.forReading(reader, annotations); } @Override protected JsonEndpointConfig _configForWriting(ObjectWriter writer, Annotation[] annotations) { return JsonEndpointConfig.forWriting(writer, annotations, _jsonpFunctionName); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy