Skip to content

Commit

Permalink
Make JacksonFeature configurable (#5074)
Browse files Browse the repository at this point in the history
Signed-off-by: Maxim Nesen <[email protected]>
  • Loading branch information
senivam committed Jun 9, 2022
1 parent 6abd64c commit 78ea6dc
Show file tree
Hide file tree
Showing 11 changed files with 358 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
Expand Down Expand Up @@ -255,6 +255,55 @@ public final class CommonProperties {
*/
public static final String JAXRS_SERVICE_LOADING_ENABLE = "jakarta.ws.rs.loadServices";

/**
* Comma separated list of jackson modules which are only enabled (only those modules will be used)
* for json-jackson processing
*
* @since 2.36
*/
public static final String JSON_JACKSON_ENABLED_MODULES = "jersey.config.json.jackson.enabled.modules";

/**
* Client-specific version of {@link CommonProperties#JSON_JACKSON_ENABLED_MODULES}.
*
* If present, it overrides the generic one for the client environment.
* @since 2.36
*/
public static final String JSON_JACKSON_ENABLED_MODULES_CLIENT = "jersey.config.client.json.jackson.enabled.modules";

/**
* Server-specific version of {@link CommonProperties#JSON_JACKSON_ENABLED_MODULES}.
*
* If present, it overrides the generic one for the server environment.
* @since 2.36
*/
public static final String JSON_JACKSON_ENABLED_MODULES_SERVER = "jersey.config.server.json.jackson.enabled.modules";

/**
* Comma separated list of jackson modules which shall be excluded from json-jackson processing.
* the JaxbAnnotationModule is always excluded (cannot be configured).
*
* @since 2.36
*/

public static final String JSON_JACKSON_DISABLED_MODULES = "jersey.config.json.jackson.disabled.modules";

/**
* Client-specific version of {@link CommonProperties#JSON_JACKSON_DISABLED_MODULES}.
*
* If present, it overrides the generic one for the client environment.
* @since 2.36
*/
public static final String JSON_JACKSON_DISABLED_MODULES_CLIENT = "jersey.config.client.json.jackson.disabled.modules";

/**
* Server-specific version of {@link CommonProperties#JSON_JACKSON_DISABLED_MODULES}.
*
* If present, it overrides the generic one for the client environment.
* @since 2.36
*/
public static final String JSON_JACKSON_DISABLED_MODULES_SERVER = "jersey.config.server.json.jackson.disabled.modules";

/**
* Prevent instantiation.
*/
Expand All @@ -274,7 +323,7 @@ private CommonProperties() {
*
* @since 2.8
*/
public static Object getValue(final Map<String, ?> properties, final String propertyName, final Class<?> type) {
public static <T> T getValue(final Map<String, ?> properties, final String propertyName, final Class<T> type) {
return PropertiesHelper.getValue(properties, propertyName, type, CommonProperties.LEGACY_FALLBACK_MAP);
}

Expand Down
36 changes: 36 additions & 0 deletions docs/src/main/docbook/appendix-properties.xml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,42 @@
@since 2.30
</entry>
</row>
<row>
<entry>&jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES; /
<entry>&jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES_CLIENT; /
<entry>&jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES_SERVER;
</entry>
<entry>
<literal>jersey.config.json.jackson.enabled.modules</literal>
<literal>jersey.config.client.json.jackson.enabled.modules</literal>
<literal>jersey.config.server.json.jackson.enabled.modules</literal>
</entry>
<entry>
Comma separated list of jackson modules which shall be used for json-jackson provider.
If set, only those modules will be used for JSON processing.

Default value is <literal>NULL</literal>
@since 2.36
</entry>
</row>
<row>
<entry>&jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES; /
<entry>&jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES_CLIENT; /
<entry>&jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES_SERVER;
</entry>
<entry>
<literal>jersey.config.json.jackson.disabled.modules</literal>
<literal>jersey.config.client.json.jackson.disabled.modules</literal>
<literal>jersey.config.server.json.jackson.disabled.modules</literal>
</entry>
<entry>
Comma separated list of jackson modules which shall be excluded from json-jackson provider.
If set, those modules will be excluded from JSON processing.

Default value is <literal>NULL</literal>
@since 2.36
</entry>
</row>
<row>
<entry>&jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_NAME;
</entry>
Expand Down
6 changes: 6 additions & 0 deletions docs/src/main/docbook/jersey.ent
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,12 @@
<!ENTITY jersey.common.CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#OUTBOUND_CONTENT_LENGTH_BUFFER_CLIENT'>CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_CLIENT</link>" >
<!ENTITY jersey.common.CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER'>CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER</link>" >
<!ENTITY jersey.common.CommonProperties.PROVIDER_DEFAULT_DISABLE "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#PROVIDER_DEFAULT_DISABLE'>CommonProperties.PROVIDER_DEFAULT_DISABLE</link>" >
<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_ENABLED_MODULES'>CommonProperties.JSON_JACKSON_ENABLED_MODULES</link>" >
<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_ENABLED_MODULES'>CommonProperties.JSON_JACKSON_ENABLED_MODULES_CLIENT</link>" >
<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_ENABLED_MODULES'>CommonProperties.JSON_JACKSON_ENABLED_MODULES_SERVER</link>" >
<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_DISABLED_MODULES'>CommonProperties.JSON_JACKSON_DISABLED_MODULES</link>" >
<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_DISABLED_MODULES'>CommonProperties.JSON_JACKSON_DISABLED_MODULES_CLIENT</link>" >
<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_DISABLED_MODULES'>CommonProperties.JSON_JACKSON_DISABLED_MODULES_SERVER</link>" >
<!ENTITY jersey.common.internal.inject.DisposableSupplier "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/DisposableSupplier.html'>DisposableSupplier</link>">
<!ENTITY jersey.common.internal.inject.InjectionManager "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/InjectionManager.html'>InjectionManager</link>">
<!ENTITY jersey.common.internal.inject.AbstractBinder "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/AbstractBinder.html'>AbstractBinder</link>">
Expand Down
11 changes: 10 additions & 1 deletion docs/src/main/docbook/media.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" standalone="no"?>
<!--
Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2012, 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
Expand Down Expand Up @@ -579,6 +579,15 @@ final Application application = new ResourceConfig()
instance into your Jersey application.
</para>

<para>
Since the 2.36 version of Jersey it is possible to filter (include/exclude) Jackson modules by properties
&jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES; and &jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES;
(with their client/server derivatives). If the &jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES; property is used,
only those named modules will be used for JSON processing. On the other hand if the &jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES;
property is used, those listed modules will be explicitly excluded from processing while other (not listed) will remain. Please note that
the <literal>JaxbAnnotationModule</literal> module is always excluded from processing and this is not configurable.
</para>

<para>
In order to use Jackson as your JSON (JAXB/POJO) provider you need to register &jersey.media.JacksonFeature;
(&jersey.media.Jackson1Feature;) and a &lit.jaxrs.ext.ContextResolver; for &lit.jersey.media.ObjectMapper;,
Expand Down
3 changes: 1 addition & 2 deletions media/json-jackson/pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2012, 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
Expand Down Expand Up @@ -122,7 +122,6 @@
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
Expand All @@ -18,42 +18,72 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.Module;
import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.jackson.internal.jackson.jaxrs.cfg.Annotations;
import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider;

import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Context;

/**
* Entity Data provider based on Jackson JSON provider.
*/
@Singleton
public class DefaultJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider {

@Context
private Configuration commonConfig;

//do not register JaxbAnnotationModule because it brakes default annotations processing
private static final String EXCLUDE_MODULE_NAME = "JaxbAnnotationModule";

public DefaultJacksonJaxbJsonProvider() {
super();
findAndRegisterModules();
}

public DefaultJacksonJaxbJsonProvider(final Annotations... annotationsToUse) {
super(annotationsToUse);
findAndRegisterModules();
}

@PostConstruct
private void findAndRegisterModules() {

final ObjectMapper defaultMapper = _mapperConfig.getDefaultMapper();
final ObjectMapper mapper = _mapperConfig.getConfiguredMapper();

final List<Module> modules = ObjectMapper.findModules();
modules.removeIf(mod -> mod.getModuleName().contains(EXCLUDE_MODULE_NAME));
final List<Module> modules = filterModules();

defaultMapper.registerModules(modules);
if (mapper != null) {
mapper.registerModules(modules);
}
}

private List<Module> filterModules() {
final String disabledModules =
CommonProperties.getValue(commonConfig.getProperties(),
commonConfig.getRuntimeType(),
CommonProperties.JSON_JACKSON_DISABLED_MODULES, String.class);
final String enabledModules =
CommonProperties.getValue(commonConfig.getProperties(),
commonConfig.getRuntimeType(),
CommonProperties.JSON_JACKSON_ENABLED_MODULES, String.class);

final List<Module> modules = ObjectMapper.findModules();
modules.removeIf(mod -> mod.getModuleName().contains(EXCLUDE_MODULE_NAME));

if (enabledModules != null && !enabledModules.isEmpty()) {
final List<String> enabledModulesList = Arrays.asList(enabledModules.split(","));
modules.removeIf(mod -> !enabledModulesList.contains(mod.getModuleName()));
} else if (disabledModules != null && !disabledModules.isEmpty()) {
final List<String> disabledModulesList = Arrays.asList(disabledModules.split(","));
modules.removeIf(mod -> disabledModulesList.contains(mod.getModuleName()));
}

return modules;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.jackson.internal;

import org.glassfish.jersey.jackson.internal.model.ServiceTest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import javax.ws.rs.core.Application;

import static org.junit.Assert.assertEquals;

public class DefaultJsonJacksonProviderForBothModulesTest extends JerseyTest {
@Override
protected final Application configure() {
return new ResourceConfig(ServiceTest.class)
.property("jersey.config.json.jackson.enabled.modules", "Jdk8Module");
}

@Test
public final void testDisabledModule() {
final String response = target("entity/simple")
.request().get(String.class);

assertEquals("{\"name\":\"Hello\",\"value\":\"World\"}", response);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* 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.jackson.internal;

import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import org.glassfish.jersey.jackson.internal.model.JAXBServiceTest;
import org.glassfish.jersey.jackson.internal.model.ServiceTest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Configuration;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

public class DefaultJsonJacksonProviderForDisabledModulesTest extends JerseyTest {
@Override
protected final Application configure() {
return new ResourceConfig(ServiceTest.class, JAXBServiceTest.class)
.property("jersey.config.json.jackson.disabled.modules", "Jdk8Module");
}

@Test
public final void testDisabledModule() {
getClient()
.register(JacksonFeature.class)
.register(TestJacksonJaxbJsonProvider.class)
.property("jersey.config.json.jackson.disabled.modules", "Jdk8Module");
final String response = target("JAXBEntity")
.request().get(String.class);
assertNotEquals("{\"key\":\"key\",\"value\":\"value\"}", response);
}

private static class TestJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider {

@Inject
private Configuration configuration;

@PostConstruct
public void checkModulesCount() {
final String disabledModules =
CommonProperties.getValue(configuration.getProperties(),
configuration.getRuntimeType(),
CommonProperties.JSON_JACKSON_DISABLED_MODULES, String.class);
assertEquals("Jdk8Module", disabledModules);
}

}

}
Loading

0 comments on commit 78ea6dc

Please sign in to comment.