java - 注册MessageBodyReader和MessageBodyWriter实现的适当位置是什么?

标签 java jax-rs

我为MessageBodyReader实现了Javax WS RS API com.ca.tas.crypto.cmp.client.GeneralPKIMessageJaxRsReader,为MessageBodyWriter实现了org.bouncycastle.asn1.cmp.PKIMessage,因此我可以轻松使用CMP over HTTP REST API中的类型。现在,要注册我创建的META-INF/services/javax.ws.rs.ext.Providers文件的类型并将类名放在此处。一切正常,我可以使用API​​进行REST调用,但以下情况除外:


IntelliJ IDEA(或我已安装到其中的插件之一)抱怨


  注册的扩展名应实现javax.ws.rs.ext.Providers


在文件的两行上。根据我在Internet上某处发现的资源,我认为添加@Provider@Produces("application/pkixcmp")批注就足够了。
我注意到FasterXML Jackson具有META-INF/services/javax.ws.rs.ext.MessageBodyReaderMETA-INF/services/javax.ws.rs.ext.MessageBodyWriter文件,这些文件似乎也注册了一个实现接口的类。


所以我的问题是:


抱怨我未实现javax.ws.rs.ext.Providers时,IntelliJ IDEA是正确还是错误?
注册MessageBodyReaderMessageBodyWriter实现的正确文件是什么?
什么能启发我的权威文献?

最佳答案

抱怨我未实现javax.ws.rs.ext.Providers时,IntelliJ IDEA是正确还是错误?


META-INF/services中的文件是我们通过使用create extensible applications进行ServiceLoader方式的一部分。它的工作方式是,文件名应为合同的名称,文件的内容应为该合同的实现列表。 ServiceLoader然后将看到该文件并收集所有实现。因此,使用ServiceLoader,我们可以

ServiceLoader<MessageBodyReader> readersLoader
        = ServiceLoader.load(MessageBodyReader.class);


根据传递给load方法的类,Java将搜索文件

META-INF/services/javax.ws.rs.ext.MessageBodyReader


并查看该文件的内容以查找该文件应加载的所有实现。

因此,根据这些信息,您可以看到IntelliJ在抱怨中是正确的,因为您的阅读器和编写器没有正确实现javax.ws.rs.ext.Providers

我应该指出的一件事是,我不认为直接使用ServiceLoader类是因为它要求服务实现具有无参数构造函数。但这是用于META服务的确切模式。


  注册MessageBodyReaderMessageBodyWriter实现的正确文件是什么?


META-INF/services文件的使用不是JAX-RS规范的一部分。这是一个实现细节,将专用于JAX-RS实现,尽管这种模式使用了很多。您将大体上看到可重用库中使用的文件,例如您提到的Jackson库1。

如果提供者将成为我们应用程序的一部分,那么可以使用更通用的方式进行注册。


您提到的@Provider注释是标记注释,用于检测应注册的提供程序类。启用扫描后,运行时将扫描用@Provider注释的类,然后它将在应用程序中注册它们。

当我们谈论扫描时,有两种不同的方式:类路径扫描和包扫描。通过使用以Application注释的空@ApplicationPath类,可以在JAX-RS应用程序中启用类路径扫描。

@ApplicationPath("/api/*")
public class ApplicationConfig extends Application {}


这足以配置JAX-RS应用程序。将启用类路径扫描,它将扫描整个类路径以查找所有用@Path@Provider注释的类,并注册这些类。

软件包扫描是特定于Jersey实施的内容。我们可以这样配置我们的应用程序

@ApplicationPath("api")
public class ApplicationConfig extends ResourceConfig {
    public ApplicationConfig() {
        package("the.package.to.scan");
    }
}


在这里,我们告诉Jersey扫描the.package.to.scan包中的@Path@Provider类,以向应用程序注册。
注册我们的提供程序的另一种方法是显式注册他们。在Application子类中,您将覆盖getClasses()getSingletons()分别将它们注册为类或对象。

@ApplicationPath("/api/*")
public class ApplicationConfig extends Application {
    private final Set<Class<?>> classes = new HashSet<>();
    private final Set<Object> singletons = new HashSet<>();

    public ApplicationConfig() {
        classes.add(MyMessageBodyReader.class);
        singletons.add(new MyMessageBodyReader());
    }

    @Override
    public Set<Class<?>> getClasses() {
        return this.classes;
    }

    @Override
    public Set<Object> getSingletons() {
        return this.singletons;
    }
}


请注意,一旦您覆盖了这两种方法中的任何一个并返回了一个非空集,则将自动禁用类路径扫描,并且您将需要手动注册所有内容。

如果您使用的是Jersey实施,则还有一些我们可以明确注册资源和提供程序的特定于Jersey的方法。有关此内容的更多讨论,请参见What exactly is the ResourceConfig class in Jersey 2?
我可以考虑注册提供者的另一种方法是使用功能。我们可以使用香草Feature,也可以使用DynamicFeature

使用Feature,我们在整个应用程序中注册提供商

// We should register the feature with our application
public class MyFeature implements Feature {
    @Override
    public boolean configure(FeatureContext context) {
         context.register(MyMessageBodyReader.class);
    }
}


使用DynamicFeature,我们可以选择使用特定的资源方法或资源类注册提供程序。在Jersey docs for dynamic binding中查看更多信息。应该注意的是,动态绑定更多地用于过滤器和拦截器(在通常的意义上,提供者),而不是实体提供者(MessageBodyReader / Writers)。
可能还有其他注册提供商的方法,但是上面提到的是您将看到它在应用程序中完成的主要方法。



  什么能启发我的权威文献?


我不确定任何文档中有多少关于META-INF /服务文件的信息。但是显式注册和类路径扫描,您可能会在JAX-RS specificationJersey documentation中找到



1-应该注意的是,仅仅因为文件存在,并不意味着它将被使用。是否关心是否使用JAX-RS取决于它。例如,Jersey不会在MessageBodyReader和writers上使用它。

2-参见How to use Jersey as JAX-RS implementation without web.xml?

关于java - 注册MessageBodyReader和MessageBodyWriter实现的适当位置是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50345202/

相关文章:

java - 如何在 Java 中将变量发送到 Aspect?

java - 将通用代码应用于 jbutton 组

java - 如何通过分段文件上传接受表单参数

java - 如何在 Jax rs 中运行 localhost url 进行发布

java - 映射、绑定(bind)和解析之间有什么区别?

java - 如何在没有 labelmaps.txt 文件的情况下使用 Tensorflow lite 检测对象地标?

java - 如何从url中过滤txt

java - 我需要一个正则表达式命令来隔离所有不与插入符号 (^) 相邻的数字

json - 为什么Apache CXF将String错误地转换为JSON?

java - 表单数据剩余 Web 服务中的德语/特殊字符支持