使用 Jersey 2.2 和 Jackson 2.1 自定义 ObjectMapper

2023-11-21

我正在与 Grizzly、Jersey 和 Jackson 一起使用 REST 应用程序,因为 Jersey 忽略了我的自定义 ObjectMapper。

POM 依赖项:

<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-grizzly2-servlet</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>2.1.4</version>
    </dependency>
</dependencies>

最终版本为:Grizzly 2.3.3、Jackson 2.1.4 和 Jersey 2.2。

主类(我想要明确注册 Jersey 组件):

public class Main {
    public static void main(String[] args) {
        try {
            ResourceConfig rc = new ResourceConfig();
            rc.register(ExampleResource.class);
            rc.register(ObjectMapperResolver.class);

            HttpHandler handler = ContainerFactory.createContainer(
                    GrizzlyHttpContainer.class, rc);

            URI uri = new URI("http://0.0.0.0:8080/");

            HttpServer server = GrizzlyHttpServerFactory.createHttpServer(uri);

            ServerConfiguration config = server.getServerConfiguration();
            config.addHttpHandler(handler, "/");

            server.start();
            System.in.read();

        } catch (ProcessingException | URISyntaxException | IOException e) {
            throw new Error("Unable to create HTTP server.", e);
        }
    }
}

ObjectMapper 的 ContextResolver:

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class ObjectMapperResolver implements ContextResolver<ObjectMapper> {

    private final ObjectMapper mapper;

    public ObjectMapperResolver() {
        System.out.println("new ObjectMapperResolver()");
        mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        System.out.println("ObjectMapperResolver.getContext(...)");
        return mapper;
    }

}

Neither ObjectMapperResolver构造函数也不getContext接到电话。我缺少什么?我更喜欢使用 Jersey 2.2 和 Jackson 2.1,因为它是另一个库的依赖项。

完整的示例可以在 GitHub 上找到:https://github.com/svenwltr/example-grizzly-jersey-jackson/tree/stackoverflow


以下解决方案适用于以下堆栈(如...这是我用来测试它的设置)

泽西岛 2.12、杰克逊 2.4.x

我正在添加我的消息以及我在这篇文章中提出的解决方案,因为它与我今天进行的许多谷歌搜索非常相关......对于我认为的问题来说,这是一个麻烦的解决方案更麻烦的问题。

1.确保你的maven配置包含jackson-jaxrs-json-provider依赖性:

<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-json-provider</artifactId>
    <version>2.4.1</version>
</dependency>

2. 确保您的 Maven 配置不包含jersey-media-json-jackson依赖性:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
</dependency>

3. 创建一个@Provider组件扩展com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider像这样:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class CustomJsonProvider extends JacksonJaxbJsonProvider {

    private static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
     }

    public CustomJsonProvider() {
        super();
        setMapper(mapper);
    }
}

正如您所观察到的,这也是我们定义自定义实例的地方com.fasterxml.jackson.databind.ObjectMapper

4. 扩展javax.ws.rs.core.Feature via MarshallingFeature像这样:

import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;

public class MarshallingFeature implements Feature {

    @Override
    public boolean configure(FeatureContext context) {
        context.register(CustomJsonProvider.class, MessageBodyReader.class, MessageBodyWriter.class);
        return true;
    }
}

5. 您需要像这样注册这个自定义提供程序,前提是您通过以下方式配置您的应用程序org.glassfish.jersey.server.ResourceConfig像这样:

import org.glassfish.jersey.server.ResourceConfig;
...

public class MyApplication extends ResourceConfig {

    public MyApplication() {

        ...
        register(MarshallingFeature.class);
        ...
     }
 }

其他注释和观察:

  1. 无论您是否使用此解决方案都适用javax.ws.rs.core.Response是否包装控制器的响应。
  2. 请确保您仔细考虑(复制/粘贴)以下代码片段,因为可以说唯一的“非强制性”位是有关自定义配置的位com.fasterxml.jackson.databind.ObjectMapper.

@jcreason

很抱歉在这个问题上犯了错误@jcreason,我希望你仍然感到好奇。 所以我查看了去年的代码,这就是我提供自定义映射器的方法。

问题是,在功能初始化期间,任何自定义对象映射器都会被以下代码禁用:

org.glassfish.jersey.jackson.Jackson特征:77 (泽西媒体-json-jackson-2.12.jar)

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

但此功能只能由该组件注册

org.glassfish.jersey.jackson.internal.JacksonAutoDiscoverable

if (!context.getConfiguration().isRegistered(JacksonFeature.class)) {
    context.register(JacksonFeature.class);
}

所以我所做的就是注册我自己的功能,该功能注册我自己的对象映射器提供程序并放入绊线停止中 org.glassfish.jersey.jackson.JacksonFeature 被注册并覆盖我的对象映射器...

import com.fasterxml.jackson.jaxrs.base.JsonMappingExceptionMapper;
import com.fasterxml.jackson.jaxrs.base.JsonParseExceptionMapper;

import org.glassfish.jersey.internal.InternalProperties;
import org.glassfish.jersey.internal.util.PropertiesHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;

public class MarshallingFeature implements Feature {

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

    @Override
    public boolean configure(FeatureContext context) {

      context.register(JsonParseExceptionMapper.class);
      context.register(JsonMappingExceptionMapper.class);
      context.register(JacksonJsonProviderAtRest.class, MessageBodyReader.class, MessageBodyWriter.class);

      final Configuration config = context.getConfiguration();
      // Disables discoverability of org.glassfish.jersey.jackson.JacksonFeature
      context.property(
          PropertiesHelper.getPropertyNameForRuntime(InternalProperties.JSON_FEATURE,
                                                     config.getRuntimeType()), JSON_FEATURE);

      return true;
    }
}

这是自定义对象映射器提供程序......

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonJsonProviderAtRest extends JacksonJaxbJsonProvider {

    private static ObjectMapper objectMapperAtRest = new ObjectMapper();

    static {
        objectMapperAtRest.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapperAtRest.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapperAtRest.configure(SerializationFeature.INDENT_OUTPUT, true); // Different from default so you can test it :)
        objectMapperAtRest.setSerializationInclusion(JsonInclude.Include.ALWAYS);
    }

    public JacksonJsonProviderAtRest() {
        super();
        setMapper(objectMapperAtRest);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Jersey 2.2 和 Jackson 2.1 自定义 ObjectMapper 的相关文章

随机推荐

  • JS Promise - 立即从返回 Promise 的函数中检索一些数据

    谁能推荐一种从返回 Promise 的函数中立即检索数据的模式 我的 简化的 示例是 AJAX 预加载器 loadPage index html then displayPage 如果这是下载一个大页面 我希望能够检查正在发生的情况 并可能
  • 有没有办法确定理想的线程数? [复制]

    这个问题在这里已经有答案了 我正在做一个网络爬虫并使用线程来下载页面 我的程序性能的第一个限制因素是带宽 我永远无法下载它可以获得的更多页面 第二件事是我感兴趣的 我使用线程同时下载许多页面 但是当我创建更多线程时 会发生更多的处理器共享
  • R Dataframe 中的级别

    我从 csv 文件导入数据 并附加数据集 我的问题 一个变量是整数形式 有 295 个级别 我需要使用这个变量来创建其他变量 但我不知道如何处理这些级别 这些是什么 我该如何处理它们 当您使用 read table 或 read csv 您
  • 是否可以将动态程序集保存到磁盘?

    最近买了阿延德的书在 Boo 中构建 DSL 购买它 阅读它 太棒了 但是我遇到了一个实现问题 我想看看生成的代码是什么样的 我通常会使用反射器来查看代码 但在这种情况下 程序集是动态的并且仅在内存中 有没有办法将动态程序集保存到磁盘以便我
  • 覆盖路由器并向特定路由添加参数(在使用路径/url 之前)

    我会使用一个简单的管理路由系统 例如现在我有这条路线 welcome ANY ANY ANY acmedemo example index ANY ANY ANY acme demos acmedemo example edit ANY A
  • 如何使用证书而不是密码进行身份验证?

    我正在构建一个小型 C MVC5 应用程序 并准备向其中添加用户安全模块 之前我只是创建了一个会话变量来测试角色 但是 我的安全需求不适合我见过的任何预构建的安全模块 即 SimpleMembership 等 总结一下我的情况和需求 没有密
  • Yii2 DetailView:使用函数的属性值[重复]

    这个问题在这里已经有答案了 当我使用函数获取属性值时出现错误 并且使用 Gridview 可以正常工作 我做错了什么
  • 解决部分链接中的相对重定位

    我注意到使用 r看来 进行部分链接实际上并不能解决任何重定位问题 即使它们可以通过相对寻址来解决 例如 考虑f o and g o with f o含有f 哪个调用g within g o 链接之前 拆卸和重定位均符合预期 部分链接到新文件
  • Python 之禅“显式优于隐式”

    我试图理解 隐式 和 显式 在 Python 上下文中的真正含义 a my understanding is that this is implicit if not a print list is empty my understandi
  • 如何让abap程序暂停?

    出于测试目的 我需要我的 ABAP 程序等待几秒钟 如何才能做到这一点 2个解决方案 1 要么使用等待 秒 WAIT UP TO 42 SECONDS WAIT UP TO 0 5 SECONDS decimals are possible
  • C++0x:在 std::map 中存储任何类型的 std::function

    我试图在地图中存储一组 std function 在 GCC 4 5 下 我想要得到两种东西 存储已传递参数的函数 那么你就拥有了 调用 f 存储不带参数的函数 那么你必须打电话 F 我想我通过类 Command 和 Manager 实现了
  • 使用不同版本的引用DLL

    不知何故 我很幸运 从未遇到过这个问题 尽管我认为这是一个常见问题 我有一个网络项目 我们称之为SomeProject SomeProject有对第三方库的引用 我们称之为SomeThirdParty 版本1 0 SomeProject还有
  • PromiseRejectionEvent是如何触发的?

    我对以下问题感到困惑 defined onunhandledrejection window onunhandledrejection event gt event preventDefault console log catch unha
  • 提交表单后按 Enter 键时会触发 Google 地方自动完成 place_changed 事件

    我已将 Google Maps Javascript API V3 中的 google maps places Autocomplete 添加到基本搜索表单中 我试图找到一种可靠的方法来检测用户是否从自动完成列表中选择了某个项目 使用鼠标或
  • zipfile 无法处理某些类型的 zip 数据?

    我在尝试解压缩 zip 文件时遇到了这个问题 zipfile is zipfile my file 总是返回 False 即使 UNIX 命令 unzip 可以很好地处理它 另外 当尝试做zipfile ZipFile path file
  • 检查返回 int 的函数时出错

    如果我有一个返回某种指针的函数 我会通过将错误返回设置为 NULL 来检查错误 char foo void If stuff doesn t go okay return NULL char bar foo if bar return 1
  • Visual Studio 监视窗口中的问号 (???) 表示什么?

    我遇到了异常并查看监视窗口中的变量 我看到一些问号 这是否意味着它指向无效地址 这意味着调试器无法计算出它的值 例如 如果您的代码涉及HWNDs 如果你查看 Windows 头文件 它是通过宏定义的 struct HWND int unus
  • 通过 RESTful CXF 使用多部分/表单数据

    我一直在一个 Web 服务中工作 该服务使用 Apache CXF 与 Jackson 结合使用和生成 JSON 文件 但是 该服务的方法之一应该能够保存从移动应用程序上传的图像 该应用程序向我的网络服务发出多部分 表单数据 POST 请求
  • 不是 GROUP BY 表达式错误[重复]

    这个问题在这里已经有答案了 我对数据库比较陌生 我正在使用 Oracle 我正在尝试实现此查询来查找该会员参加的个人培训课程的数量 这些表格是 MEMBERS MEMBERS ID NUMBER MEMBERSHIP TYPE CODE V
  • 使用 Jersey 2.2 和 Jackson 2.1 自定义 ObjectMapper

    我正在与 Grizzly Jersey 和 Jackson 一起使用 REST 应用程序 因为 Jersey 忽略了我的自定义 ObjectMapper POM 依赖项