注册MessageBodyReader和MessageBodyWriter实现的适当位置是什么? [英] What is the proper place to register MessageBodyReader and MessageBodyWriter implementations?
问题描述
我已经为 com.ca.tas.crypto.cmp.client.GeneralPKIMessageJaxRsReader
MessageBodyReader >和 MessageBodyWriter
for 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
在文件中的两行上。根据我在互联网上找到的资源,我想添加
@Provider
和@Produces(application / pkixcmp)
注释应该足够了。 -
我注意到FasterXML Jackson有
META-INF / services / javax.ws.rs。 ext.MessageBodyReader
和META-INF / services / javax.ws.rs.ext.MessageBodyWriter
这些文件似乎注册了一个实现界面也是。
所以我的问题是:
-
IntelliJ IDEA是正确还是错误,抱怨我没有实现
javax.ws.rs.ext.Providers
? -
注册
MessageBodyReader
和MessageBodyWriter
implementation? -
哪些权威文档可以让我了解这个?
IntelliJ IDEA是正确还是错误,抱怨我没有实现
javax.ws.rs.ext.Providers
?
META-INF / services
中的文件是我们通过使用 docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.htmlrel =nofollow noreferrer> ServiceLoader
。它的工作原理是文件名应该是合同的名称,文件的内容应该是该合同的实现的列表。然后 ServiceLoader
将查看该文件并收集所有实现。因此,使用 ServiceLoader
,我们可以
ServiceLoader< MessageBodyReader> readersLoader
= ServiceLoader.load(MessageBodyReader.class);
基于传递给加载的类
方法,Java将搜索文件
META-INF / services / javax.ws.rs.ext.MessageBodyReader
并查看该文件的内容以查找它应加载的所有实现。
因此,基于该信息,您可以看到IntelliJ 在抱怨中是正确的,因为您的读者和作者没有正确实现 javax.ws .rs.ext.Providers
。
我应该指出的一点是,我不认为 ServiceLoader
类是直接使用的,因为它要求服务实现具有无参数构造函数。但这是用于META服务的确切模式。
注册<$ c $的正确文件是什么c> MessageBodyReader 和
MessageBodyWriter
实现?
使用 META-INF / services
文件不是JAX-RS规范的一部分。这是一个特定于JAX-RS实现的实现细节,尽管这种模式被大量使用。您将主要看到可重用库中使用的文件,例如您提到的 1 的杰克逊库。
如果提供者将是我们的应用程序的一部分,然后有更常见的方式来注册它。
-
你提到的@Provider
注释是一个标记注释,用于检测应该注册的提供者类。启用扫描后,运行时将扫描使用@Provider
注释的类,然后将其与应用程序一起注册。
<当我们谈论扫描时,有几种不同的方式:类路径扫描和包扫描。通过使用@ApplicationPath
注释的空Application
类,在JAX-RS应用程序中启用类路径扫描。 / p>
@ApplicationPath(/ api / *)
公共类ApplicationConfig扩展Application {}
这足以让JAX-RS应用程序配置为 2 。将启用类路径扫描,它将扫描整个类路径中所有使用
@Path
和@Provider
注释的类并注册那些类。
包扫描是特定于Jersey实现的东西。我们可以这样配置我们的应用程序
@ApplicationPath(api)
公共类ApplicationConfig扩展ResourceConfig {
public ApplicationConfig(){
package(the.package.to.scan);
}
}
在这里,我们告诉泽西岛扫描
the.package.to.scan
包@Path
和@Provider
要在应用程序中注册的类。 -
注册我们的提供者的另一种方法是显式注册它们。在
Application
子类中,您将覆盖getClasses()
或getSingletons()
分别将它们注册为类或对象。@ApplicationPath(/ api / *)
公共类ApplicationConfig扩展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(){
返回this.classes;
}
@Override
public Set< Object> getSingletons(){
返回this.singletons;
}
}
请注意,一旦覆盖其中任何一种方法并返回非空集,类路径扫描会自动禁用,您需要手动注册所有内容。
如果您使用Jersey实现,还有Jersey特定的我们可以明确注册资源和提供者的方式。有关此问题的更多讨论,请参阅 Jersey 2中的ResourceConfig类究竟是什么?。
-
我认为注册提供商的另一种方式是使用功能。我们可以使用香草
功能
或我们可以使用DynamicFeature
。
使用
功能
,我们在整个应用程序中注册提供程序//我们应该在我们的网站上注册该功能application
public class MyFeature实现Feature {
@Override
public boolean configure(FeatureContext context){
context.register(MyMessageBodyReader.class);
}
}
使用
DynamicFeature
我们可以选择性地注册具有特定资源方法或资源类的提供程序。有关详细信息,请参阅 Jersey文档以了解动态绑定。应该注意的是,动态绑定更多地用于过滤器和拦截器(这也是一般意义上的术语,提供者),而不是实体提供者(MessageBodyReader / Writers)。 -
可能还有其他方式来注册您的提供商,但上面提到的是您在应用程序中看到它的主要方式。
哪些权威文档可以让我了解这个?
我不确定在任何文档中有多少关于META-INF /服务文件的信息。但是显式注册和类路径扫描,您可能会在 JAX-RS规范或泽西文件
1 - 应该注意的是,仅仅因为文件存在,并不意味着它将被使用。无论是否使用它,都取决于JAX-RS的实现。例如,Jersey不会在 MessageBodyReader
s和作者上使用它。
2 - 请参阅如何在没有web.xml的情况下将Jersey用作JAX-RS实现?
I have implemented Javax WS RS API MessageBodyReader
for com.ca.tas.crypto.cmp.client.GeneralPKIMessageJaxRsReader
and MessageBodyWriter
for org.bouncycastle.asn1.cmp.PKIMessage
so that I can easily use the types in CMP over HTTP REST API. Now, to register the types I have created META-INF/services/javax.ws.rs.ext.Providers
file and put the class names there. Everything works fine, I can do REST calls using the API, except:
IntelliJ IDEA (or one of the plugins I have installed into it) complains that
Registered extension should implement javax.ws.rs.ext.Providers
on the two lines in the file. Based on the resources I have found somewhere on the Internet I thought adding
@Provider
and@Produces("application/pkixcmp")
annotations should be enough.I have noticed that FasterXML Jackson has
META-INF/services/javax.ws.rs.ext.MessageBodyReader
andMETA-INF/services/javax.ws.rs.ext.MessageBodyWriter
files and those seem to register a class that implements the interfaces as well.
So my questions are:
Is the IntelliJ IDEA correct or wrong to complain about me not implementing
javax.ws.rs.ext.Providers
?What is the correct file to register the
MessageBodyReader
andMessageBodyWriter
implementations?What is the authoritative documentation that would enlighten me about this?
Is the IntelliJ IDEA correct or wrong to complain about me not implementing
javax.ws.rs.ext.Providers
?
The files in the META-INF/services
are part of the way we can create extensible applications by making use of the ServiceLoader
. How it works is that the filename should be the name of the contract and the contents of the file should be a list of implementations of that contract. The ServiceLoader
will then see the file and collect all the implementations. So using the ServiceLoader
, we could do
ServiceLoader<MessageBodyReader> readersLoader
= ServiceLoader.load(MessageBodyReader.class);
Based on the class passed to the load
method, Java will search for the file
META-INF/services/javax.ws.rs.ext.MessageBodyReader
and look at the contents of that file to find all the implementations that it should load.
So based on that information, you can see that IntelliJ is correct in complaining, as your reader and writer do not correctly implement javax.ws.rs.ext.Providers
.
One thing I should point out is that I don't think that the ServiceLoader
class is used directly as it requires that the service implementations have no-arg constructors. But this is the exact pattern that is used in regards to the META services.
What is the correct file to register the
MessageBodyReader
andMessageBodyWriter
implementations?
The use of META-INF/services
files is not something that is a part of the JAX-RS specification. This is an implementation detail that will be specific to the JAX-RS implementation, though this pattern is used a lot. You will mostly see the files being used in reusable libraries, such as the Jackson library you mentioned1.
If the provider is going to be a part of our application, then there are more common ways in which to register it.
The
@Provider
annotation as you mentioned is a marker annotation to detect a provider class that should be registered. When scanning is enabled, the runtime scans for classes annotated with@Provider
and then it will register them with the application.When we talk about scanning, there are a couple different ways: classpath scanning and package scanning. Classpath scanning is enabled in a JAX-RS application by having an empty
Application
class that is annotated with@ApplicationPath
.@ApplicationPath("/api/*") public class ApplicationConfig extends Application {}
This is enough to get a JAX-RS application configured2. Classpath scanning will be enabled, which will scan the entire classpath for all classes annotated with
@Path
and@Provider
and register those classes.Package scanning is something that is specific to the Jersey implementation. We could configure our application as such
@ApplicationPath("api") public class ApplicationConfig extends ResourceConfig { public ApplicationConfig() { package("the.package.to.scan"); } }
Here, we are telling Jersey to scan the
the.package.to.scan
package for@Path
and@Provider
classes to register with the application.Another way to register our providers is to explicitly register them. In
Application
subclass, you would overridegetClasses()
orgetSingletons()
to register them as a class or as an object, respectively.@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; } }
Note that once you override either of these methods and return a non-empty set, the classpath scanning is automatically disabled, and you will need to register everything manually.
If you are using the Jersey implementation, there are also Jersey specific ways that we can explicitly register resources and providers. For more discussion on this, see What exactly is the ResourceConfig class in Jersey 2?.
Another way I can think to register providers is through the use of features. We can use the vanilla
Feature
or we can use aDynamicFeature
.With the
Feature
, we register the provider with the entire application// We should register the feature with our application public class MyFeature implements Feature { @Override public boolean configure(FeatureContext context) { context.register(MyMessageBodyReader.class); } }
With a
DynamicFeature
we can selectively register a provider with specific resource methods or resource classes. See more in the Jersey docs for dynamic binding. It should be noted that dynamic binding is more used with filters and interceptors (which are also in the general sense of the term, providers) and not so much with entity providers (MessageBodyReader/Writers).There may be other ways to register your providers, but the one mentioned above are the main ways that you will see it being done in an application.
What is the authoritative documentation that would enlighten me about this?
I'm not sure how much information about META-INF/service files in any documentation. But explicit registration and classpath scanning, you will probably find in the JAX-RS specification or Jersey documentation
1 - It should be noted that just because the file is there, it does not mean that it will be used. It is up to the JAX-RS implementation whether or not they care to use it. For Example, Jersey will not use it on MessageBodyReader
s and writers.
2 - See How to use Jersey as JAX-RS implementation without web.xml?
这篇关于注册MessageBodyReader和MessageBodyWriter实现的适当位置是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!