我有一个由多个模块组成的库:
core
模块是必需的,而guava
是可选的。还有其他可选模块(此问题代表最小的测试用例)。
每个模块都公开了一组用户可以调用的方法:
class CoreVerifier
{
MapVerifier verify(Map);
}
class GuavaVerifier
{
MultimapVerifier verify(Multimap);
}
为用户提供一个可以在一个地方导出所有方法的类:
class UnifiedVerifier
{
MapVerifier verify(Map);
MultimapVerifier verify(Multimap);
}
我希望用户能够使用此类,即使运行时缺少可选模块(例如guava)。这意味着,UnifiedVerifier
与类路径上的所有库一起编译,但在第二种方法引用的运行时MultimapVerifier
不存在。
如果用户从应用程序代码中调用第一个方法,则javac失败并显示:
Application.java: cannot access MultimapVerifier
class file for MultimapVerifier not found
意思是,即使第一个方法定义良好(核心模块在编译时可用),编译器也拒绝继续,因为第二个方法(它们没有使用)引用了一个缺少的类。类路径。
有没有办法在Java中实现这类功能?
assertj有一个聪明的静态导入机制,它为每个模块(核心,番石榴)声明一个不同的Assertions
类,Java的静态导入根据类型选择正确的方法你传入了。我已经在静态方法中使用了类似的机制,但现在我想要一些类似的东西,我不能使用静态方法。
答案 0 :(得分:0)
是的,你可以这样做:
定义一个接口(可能是提供这些服务的模块的内部);我将其称为ThingyImplementation
。
将使用可选库(Guava等)的代码放在一个您不能在任何其他代码中直接引用的独特类中。该类实现ThingyImplementation
。
在运行时,使用Class.forName
动态尝试使用可选的librayr加载类,并通过Class#newInstance
实例化它,将结果分配给声明为ThingyImplementation
的变量。通过接口使用生成的实例作为提供。
如果类路径上没有可选库,则在步骤3中加载或实例化类将引发异常,您可以在自己的异常中传播或包装。
请注意,外部类(UnifiedVerifier
)不能直接引用可选库定义的类型,因此您不能拥有MultimapVerifier verify(Multimap);
。如果 提供,则必须接受Object
,然后根据需要在可选模块实现中进行转换。
答案 1 :(得分:0)
我想出办法!您可以使用类阴影来实现所需的行为。
CoreVerifiers
GuavaVerifiers
GuavaVerifiers
GuavaVerifiers
接口都应该声明该模块实现的方法。因此,核心模块中的GuavaVerifiers
应为空,而guava模块中的GuavaVerifiers
应包含该模块实现的方法。 (意思是,如果用户只链接核心模块,他们就不应该看到任何与番石榴有关的功能)。CoreVerifiersImpl
应该实现CoreVerifiers
。核心模块中的GuavaVerifiersImpl
应为空,因为核心模块中的GuavaVerifiers
为空。另一方面,guava模块中的GuavaVerifiersImpl
应该实现非空的GuavaVerifiers
接口。对于步骤2中的每个接口,使用委派给现有验证程序的默认方法在核心模块中声明接口。例如:
public interface ForwardingCoreVerifiers
{
CoreVerifiers coreVerifiers();
default CoreVerifiers method1()
{
coreVerifiers().method1();
}
}
最后,在核心库中,声明一个扩展所有转发接口的实现:
public final class Verifiers
implements ForwardingCoreVerifiers, ForwardingGuavaVerifiers
{
public CoreVerifiers coreVerifiers()
{
return new CoreVerifiersImpl(...);
}
public CoreVerifiers guavaVerifiers()
{
return new GuavaVerifiersImpl(...);
}
}
现在这里有魔力:
GuavaVerifier
接口将影响核心模块中的接口)。表现提示:
CoreVerifiers
)并使用默认方法来处理其余模块(GuavaVerifiers
)更新:我为Java 9发布了updated question。