带有 Spring 的 Jersey 2 中的自定义 Jackson ObjectMapper

2024-01-14

我在将 Jersey 从 1.x 迁移到 2.x 时遇到一些问题。我的应用程序使用 Jersey 提供 REST Web 服务,并通过 Jackson 和 Spring 4 以 JSON 形式提供数据来处理依赖项注入。

在 Jersey 1.x 中,我曾经将 JsonDeserializer 编写为由 Spring 管理的组件,因此我可以访问我的服务,以便在反序列化期间从持久层加载我的域对象,但在 2.x 中,我在注入服务时遇到问题解串器工作。我遵循的方法受到这篇博文的启发:http://www.runningasroot.com/blog/2012/05/02/autowiring-jackson-deserializers-in-spring/ http://www.runningasroot.com/blog/2012/05/02/autowiring-jackson-deserializers-in-spring/

这是我的依赖部分pom.xml:

<dependencies>
    <!-- Spring -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- Jersey -->
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-spring3</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-multipart</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <!-- Commons Codec -->
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>${commons-codec.version}</version>
    </dependency>

    <!-- cut -->

<dependencies>

Jersey版本是2.7,Spring 4.0.2.RELEASE。

这是我的web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <module-name>myApp/module-name>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>it.mgt.myApp.config.ApplicationConfig</param-value>
    </context-param>

    <servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>it.mgt.myApp.config.JerseyConfig</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>

</web-app>

这是我的弹簧配置 class:

@Configuration
@ComponentScan({"it.mgt.myApp"})
@PropertySource("classpath:myApp.properties")
public class ApplicationConfig {

    // Cut

}

这是我的泽西岛资源配置 class:

public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        packages("it.mgt.myApp");

        register(MultiPartFeature.class);

        register(RequestContextFilter.class);

        register(ObjectMapperContextResolver.class);
        register(JacksonFeature.class);

        register(CorsRequestFilter.class);
        register(SignatureProcessingFilter.class);
        register(AuthorizationFeature.class);
        register(CorsResponseFilter.class);
        register(new UserBinder());
    }
}

这是我的对象映射器上下文解析器 class:

@Component
@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

    @Autowired
    private SpringObjectMapper objectMapper;

    public ObjectMapperContextResolver() {
        super();
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return objectMapper;
    }

}

我认为 @Provider 注释与资源配置类中的注册是多余的。

这是我的Spring对象映射器 class:

@Component
public class SpringObjectMapper extends ObjectMapper {

    private static final long serialVersionUID = 1413033425692174337L;

    @Autowired
    ApplicationContext applicationContext;

    public SpringObjectMapper() {
        this.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
        this.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, true);
    }

    @Override
    @Autowired
    public void setHandlerInstantiator(HandlerInstantiator hi) {
        super.setHandlerInstantiator(hi);
    }

}

这是我的SpringBeanHandler实例化器 class:

@Component
public class SpringBeanHandlerInstantiator extends HandlerInstantiator {

    private ApplicationContext applicationContext;

    @Autowired
    public SpringBeanHandlerInstantiator(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public JsonDeserializer<?> deserializerInstance(DeserializationConfig dc, Annotated antd, Class<? extends JsonDeserializer<?>> type) {
        try {
            return (JsonDeserializer<?>) applicationContext.getBean(type);
        } catch (Exception e) {
        }

        return null;
    }

    @Override
    public KeyDeserializer keyDeserializerInstance(DeserializationConfig dc, Annotated antd, Class<? extends KeyDeserializer> type) {
        try {
            return (KeyDeserializer) applicationContext.getBean(type);
        } catch (Exception e) {
        }

        return null;
    }

    @Override
    public JsonSerializer<?> serializerInstance(SerializationConfig sc, Annotated antd, Class<? extends JsonSerializer<?>> type) {
        try {
            return (JsonSerializer<?>) applicationContext.getBean(type);
        } catch (Exception e) {
        }

        return null;
    }

    @Override
    public TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> mc, Annotated antd, Class<? extends TypeResolverBuilder<?>> type) {
        try {
            return (TypeResolverBuilder<?>) applicationContext.getBean(type);
        } catch (Exception e) {
        }

        return null;
    }

    @Override
    public TypeIdResolver typeIdResolverInstance(MapperConfig<?> mc, Annotated antd, Class<? extends TypeIdResolver> type) {
        try {
            return (TypeIdResolver) applicationContext.getBean(type);
        } catch (Exception e) {
        }

        return null;
    }

}

这是我的领域实体类、序列化器和反序列化器是静态内部类:

@JsonSerialize(using = User.Serializer.class)
@JsonDeserialize(using = User.Deserializer.class)
public class User {

    @Component
    public static class Serializer extends JsonSerializer<User> {

        @Override
        public void serialize(User obj, JsonGenerator jg, SerializerProvider sp) throws IOException, JsonProcessingException {
            // Cut
        }

    }

    @Component
    public static class Deserializer extends JsonDeserializer<User> {

        @Autowired
        SomeService someService;

        @Override
        public User deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
            User user = new User();

            // Cut
            // Use someService here
        }

    }

    // Cut

}

我试图在 ObjectMapperContextResolver.getContext(Class type) 中放置一个刹车点,但它从未被击中,我怀疑这是问题的根源,但经过两天的尝试和研究球衣文档,我已经没有想法了。

任何人都可以指出我如何正确实现这一目标?


经过进一步尝试,结果发现 ObjectMapperContextResolver 上的 @Component 导致 Jersey 2.x 不使用提供程序,即使它已在 Jersey 配置类中显式注册。这与 Jersey 1.x 的行为相反,其中需要 @Component。

删除它就成功了,尽管看起来很奇怪。 ObjectMapperContextResolver中的@Autowired SpringObjectMapper仍然是Jersey注入的。

从球衣文档中我无法判断这是设计使然还是错误。

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

带有 Spring 的 Jersey 2 中的自定义 Jackson ObjectMapper 的相关文章

随机推荐

  • CSS - 100% 宽度的输入与 div 重叠

    我正在尝试修复带有填充 边框的常规输入框 在带有填充的 div 内 但是 我希望输入的宽度为 100 但正如您所看到的 它重叠了 我该如何解决 CSS one background red width 300px padding 5px t
  • 来自数据库的漂亮网址

    我正在尝试在我的网站上获取漂亮的网址 现在它们看起来像这样 www site com tag php id 1 我想把它改成 www site com tag 1 slug 我的数据库表有 ID 标题 信息 Slug 我在网上读到有关 sl
  • 使用 Tortoise SVN 进行恢复

    如果我在 TortoiseSVN 中查看 Subversion 日志 当我选择修订版本并右键单击时 我会看到以下选项 以及其他选项 将项目更新为修订版 恢复到此版本 恢复此版本的更改 有人可以解释一下这3者之间有什么区别吗 我真正想做的是暂
  • 在 sql case 语句中使用比较符号

    我正在寻找一种使用小于和大于符号在 sql select 查询中构建 case 语句的方法 例如 我想根据一个变量选择一个排名 DECLARE a INT SET a 0 SELECT CASE WHEN a lt 3 THEN 0 WHE
  • 检测谁创建了线程(w. Eclipse)

    在 Java 中如何找出谁创建了线程 想象一下 您使用 30第三者复杂插件环境中的 JAR 您启动它 运行大量代码 进行一些计算 最后调用 shutdown 这个生命周期通常工作得很好 除了每次运行时一些 非守护进程 线程保持悬空状态 如果
  • MATLAB 散点图中的线性回归线

    我正在尝试获取两个变量散点图的残差 我可以使用最小二乘线性回归线lslinematlab的函数 但是 我也想得到残差 我怎样才能在matlab中得到这个 为此我需要知道参数a and b线性回归线的 ax b 使用功能polyfit htt
  • 如何在自定义约束验证器中使用注释元素

    我在我的项目中编写了一个名为 CGC 的自定义注释 Target METHOD FIELD ANNOTATION TYPE CONSTRUCTOR PARAMETER Retention RUNTIME Documented Constra
  • Gitlab-Ci:如何在作业之间共享数据

    我想在两个作业之间共享一个文件 并在文件发生更改时对其进行修改 python 脚本比较cache json文件发生更改并有时修改缓存文件 gitlab ci yaml image ubuntu stages test cache key o
  • 如何在包含数据的表上创建序号列索引

    我有下表 其中包含 10 个唯一行 BookingID 是包含随机数的 FK 该数字不需要按顺序排列 BookingID Description 1000 Foo 3000 Bar 1500 Zoo 我需要插入一个名为 ID 的顺序索引 该
  • 咖啡因缓存 - 指定条目的到期时间

    我正在努力进一步加深我对咖啡因缓存 https github com ben manes caffeine 我想知道是否有一种方法可以为缓存中填充的条目指定超时 但其余记录没有基于时间的到期时间 本质上我希望有以下界面 put key va
  • 如何通过部分 ID 值选择 CSS 中的元素?

    我有一些用 PHP 生成的元素 我想知道是否可以选择 id 不完整的元素 例如 div class 1 div div class 2 div div class 1 div div class 2 div 该类已经习惯了它们的共同点 但现
  • Android - 窗口标志

    有没有办法检测窗口标志何时触发 假设我有一个WindowManager LayoutParams FLAG SECURE 当我触发它时如何检测它 我尝试用谷歌搜索问题 但我所得到的只是设置 添加窗口标志 谢谢 在您的活动中只需覆盖onWin
  • 使用元组而不是冻结集作为字典的键是否存在性能差异?

    我有一个脚本 它使用由两个变量组成的键多次调用字典 我知道我的程序将以相反的顺序再次遇到这两个变量 这使得将密钥存储为元组变得可行 创建一个行和列具有相同标签的矩阵 因此 我想知道使用元组而不是冻结集作为字典键是否存在性能差异 在快速测试中
  • SVN:如何在提交时忽略修改的文件? [复制]

    这个问题在这里已经有答案了 我在svn中编辑了一些文件 如下所示 svn st M a M b 现在 我想将我的更改提交到 svn 由于某种原因 我不想提交文件b 有没有快速的方法或命令来忽略修改的文件b 最后 我使用 yzucker解决方
  • C# 任务栏中的 Windows 7 进度条?

    如果您注意到在 Windows 7 Beta 中 如果您复制文件或其他系统操作 任务栏中的 Windows 资源管理器图标将填充一个绿色进度条 相当于表单上的进度条 有没有一种方法可以在我的 C 表单中强制我的任务栏进度条与我正在执行的任何
  • 将数据插入 ms access 表时出现语法错误

    我有以下代码 OleDbConnection aConnection new OleDbConnection Provider Microsoft ACE OLEDB 12 0 Data Source storage db accdb st
  • XPath 表达式对 //element 不返回任何内容,但 //* 返回一个计数

    我将 XOM 与以下示例数据一起使用 Element root cleanDoc getRootElement find all the bold elements as those mark institution and clinic
  • C# 中将父对象转换为子对象

    您好 我想在 C 中将父对象转换为子对象 public class Parent public string FirstName get set public string LastName get set public string Ci
  • 根据计数折叠数据框中所有因子变量的因子级别

    我想根据频率仅保留前 2 个因素级别 并将所有其他因素分组为 其他 我尝试过这个但没有帮助 df data frame a as factor c rep D 3 rep B 5 rep C 2 b as factor c rep A 5
  • 带有 Spring 的 Jersey 2 中的自定义 Jackson ObjectMapper

    我在将 Jersey 从 1 x 迁移到 2 x 时遇到一些问题 我的应用程序使用 Jersey 提供 REST Web 服务 并通过 Jackson 和 Spring 4 以 JSON 形式提供数据来处理依赖项注入 在 Jersey 1