Skip to content

Commit

Permalink
Support GSON media
Browse files Browse the repository at this point in the history
Signed-off-by: Jorge Bescos Gascon <[email protected]>
  • Loading branch information
jbescos committed Jun 21, 2022
1 parent e114d5e commit 3aaad44
Show file tree
Hide file tree
Showing 14 changed files with 643 additions and 0 deletions.
5 changes: 5 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,11 @@
<artifactId>jersey-media-json-processing</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-gson</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-binding</artifactId>
Expand Down
81 changes: 81 additions & 0 deletions media/json-gson/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the
Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
version 2 with the GNU Classpath Exception, which is available at
https://www.gnu.org/software/classpath/license.html.
SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>project</artifactId>
<version>2.37-SNAPSHOT</version>
</parent>

<artifactId>jersey-media-json-gson</artifactId>
<packaging>jar</packaging>
<name>jersey-media-json-gson</name>

<description>
Jersey GSON support module.
</description>

<build>
<plugins>
<plugin>
<groupId>com.sun.istack</groupId>
<artifactId>istack-commons-maven-plugin</artifactId>
<inherited>true</inherited>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<inherited>true</inherited>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<inherited>true</inherited>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>org.glassfish.jersey.gson.*</Export-Package>
<Import-Package>${javax.annotation.osgi.version},*</Import-Package>
</instructions>
<unpackBundle>true</unpackBundle>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.jersey.gson;

import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;

import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.gson.internal.JsonGsonAutoDiscoverable;
import org.glassfish.jersey.gson.internal.JsonGsonProvider;
import org.glassfish.jersey.internal.InternalProperties;
import org.glassfish.jersey.internal.util.PropertiesHelper;
/**
* Feature used to register Gson providers.
* <p>
* The Feature is automatically enabled when {@link JsonGsonAutoDiscoverable} is on classpath.
* Default GSON configuration obtained by calling {@code GsonBuilder.create()} is used.
* <p>
* Custom configuration, if required, can be achieved by implementing custom {@link javax.ws.rs.ext.ContextResolver} and
* registering it as a provider into JAX-RS runtime:
* <pre>
* &#64;Provider
* &#64;class GsonContextResolver implements ContextResolver&lt;Gson&gt; {
* &#64;Override
* public Gson getContext(Class<?> type) {
* GsonBuilder builder = new GsonBuilder();
* // add custom configuration
* return builder.create();
* }
* }
* </pre>
*
*/
public class JsonGsonFeature implements Feature {

private static final String JSON_FEATURE = JsonGsonFeature.class.getSimpleName();

@Override
public boolean configure(final FeatureContext context) {
final Configuration config = context.getConfiguration();

final String jsonFeature = CommonProperties.getValue(
config.getProperties(),
config.getRuntimeType(),
InternalProperties.JSON_FEATURE, JSON_FEATURE, String.class);

// Other JSON providers registered.
if (!JSON_FEATURE.equalsIgnoreCase(jsonFeature)) {
return false;
}

// Disable other JSON providers.
context.property(PropertiesHelper.getPropertyNameForRuntime(
InternalProperties.JSON_FEATURE, config.getRuntimeType()), JSON_FEATURE);

context.register(JsonGsonProvider.class);

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.jersey.gson.internal;

import javax.annotation.Priority;
import javax.ws.rs.core.FeatureContext;

import org.glassfish.jersey.gson.JsonGsonFeature;
import org.glassfish.jersey.internal.spi.AutoDiscoverable;
import org.glassfish.jersey.internal.spi.ForcedAutoDiscoverable;

/**
* {@link ForcedAutoDiscoverable} registering {@link JsonGsonFeature} if the feature is not already registered.
* <p>
*
* @see JsonGsonFeature
*/
@Priority(AutoDiscoverable.DEFAULT_PRIORITY - 210)
public class JsonGsonAutoDiscoverable implements ForcedAutoDiscoverable {

@Override
public void configure(FeatureContext context) {
if (!context.getConfiguration().isRegistered(JsonGsonFeature.class)) {
context.register(JsonGsonFeature.class);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.jersey.gson.internal;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import javax.ws.rs.Consumes;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.NoContentException;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.Providers;

import org.glassfish.jersey.gson.LocalizationMessages;
import org.glassfish.jersey.message.internal.AbstractMessageReaderWriterProvider;
import org.glassfish.jersey.message.internal.EntityInputStream;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
* Entity provider (reader and writer) for Gson.
*
*/
@Provider
@Produces({"application/json", "text/json", "*/*"})
@Consumes({"application/json", "text/json", "*/*"})
public class JsonGsonProvider extends AbstractMessageReaderWriterProvider<Object> {

private static final String JSON = "json";
private static final String PLUS_JSON = "+json";

private Providers providers;

public JsonGsonProvider(@Context Providers providers) {
this.providers = providers;
}

@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return supportsMediaType(mediaType);
}

@Override
public Object readFrom(Class<Object> type, Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, String> httpHeaders,
InputStream entityStream) throws IOException, WebApplicationException {
EntityInputStream entityInputStream = new EntityInputStream(entityStream);
entityStream = entityInputStream;
if (entityInputStream.isEmpty()) {
throw new NoContentException(LocalizationMessages.ERROR_GSON_EMPTYSTREAM());
}
Gson gson = getGson(type);
try {
return gson.fromJson(new InputStreamReader(entityInputStream,
AbstractMessageReaderWriterProvider.getCharset(mediaType)), genericType);
} catch (Exception e) {
throw new ProcessingException(LocalizationMessages.ERROR_GSON_DESERIALIZATION(), e);
}
}

@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return supportsMediaType(mediaType);
}

@Override
public void writeTo(Object o, Class<?> type, Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException, WebApplicationException {
Gson gson = getGson(type);
try {
entityStream.write(gson.toJson(o).getBytes(AbstractMessageReaderWriterProvider.getCharset(mediaType)));
entityStream.flush();
} catch (Exception e) {
throw new ProcessingException(LocalizationMessages.ERROR_GSON_SERIALIZATION(), e);
}
}

private Gson getGson(Class<?> type) {
final ContextResolver<Gson> contextResolver = providers.getContextResolver(Gson.class, MediaType.APPLICATION_JSON_TYPE);
if (contextResolver != null) {
return contextResolver.getContext(type);
} else {
return GsonSingleton.INSTANCE.getInstance();
}
}

/**
* @return true for all media types of the pattern *&#47;json and
* *&#47;*+json.
*/
private static boolean supportsMediaType(final MediaType mediaType) {
return mediaType.getSubtype().equals(JSON) || mediaType.getSubtype().endsWith(PLUS_JSON);
}

private enum GsonSingleton {
INSTANCE;

// Thread-safe
private Gson gsonInstance;

Gson getInstance() {
return gsonInstance;
}

GsonSingleton() {
this.gsonInstance = new GsonBuilder().create();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

/**
* Jersey classes supporting JSON marshalling and unmarshalling using GSON.
*/
package org.glassfish.jersey.gson;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.glassfish.jersey.gson.internal.JsonGsonAutoDiscoverable
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#
# Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0, which is available at
# http://www.eclipse.org/legal/epl-2.0.
#
# This Source Code may also be made available under the following Secondary
# Licenses when the conditions for such availability set forth in the
# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
# version 2 with the GNU Classpath Exception, which is available at
# https://www.gnu.org/software/classpath/license.html.
#
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
#

error.gson.serialization=Error writing GSON serialized object.
error.gson.deserialization=Error deserializing object from entity stream.
error.gson.emptystream=GSON cannot parse empty input stream.
Loading

0 comments on commit 3aaad44

Please sign in to comment.